web-dev-qa-db-fra.com

extraire des heures et des secondes de POSIXct à des fins de traçage dans R

Supposons que j'ai les data.framefoo suivants

           start.time duration
1 2012-02-06 15:47:00      1
2 2012-02-06 15:02:00      2
3 2012-02-22 10:08:00      3
4 2012-02-22 09:32:00      4
5 2012-03-21 13:47:00      5

Et class(foo$start.time) renvoie

[1] "POSIXct" "POSIXt" 

Je voudrais créer un tracé de foo$duration V. foo$start.time. Dans mon scénario, je ne m'intéresse qu'à l'heure de la journée plutôt qu'au jour réel de l'année. Comment extraire l'heure de la journée en heures: secondes de la classe de vecteur POSIXct?

56
andrewj

C'est une bonne question, et met en évidence une partie de la difficulté à gérer les dates dans R. Le paquet lubridate est très pratique, donc ci-dessous je présente deux approches, l'une utilisant la base (comme suggéré par @ RJ-) et l'autre utilisant lubridate.

Recréez les (deux premières lignes de) la trame de données dans la publication d'origine:

foo <- data.frame(start.time = c("2012-02-06 15:47:00", 
                                 "2012-02-06 15:02:00",
                                 "2012-02-22 10:08:00"),
                  duration   = c(1,2,3))

Convertir en classe POSIXct et POSIXt (deux façons de procéder)

# using base::strptime
t.str <- strptime(foo$start.time, "%Y-%m-%d %H:%M:%S")

# using lubridate::ymd_hms
library(lubridate)
t.lub <- ymd_hms(foo$start.time)

Maintenant, extrayez le temps en heures décimales

# using base::format
h.str <- as.numeric(format(t.str, "%H")) +
               as.numeric(format(t.str, "%M"))/60

# using lubridate::hour and lubridate::minute
h.lub <- hour(t.lub) + minute(t.lub)/60

Démontrez que ces approches sont égales:

identical(h.str, h.lub)

Choisissez ensuite l'une des approches ci-dessus pour attribuer une heure décimale à foo$hr:

foo$hr <- h.str

# If you prefer, the choice can be made at random:
foo$hr <- if(runif(1) > 0.5){ h.str } else { h.lub }

puis tracez en utilisant le package ggplot2:

library(ggplot2)
qplot(foo$hr, foo$duration) + 
             scale_x_datetime(labels = "%S:00")
50
David LeBauer

Vous pouvez compter sur la base R:

# Using R 2.14.2
# The same toy data
foo <- data.frame(start.time = c("2012-02-06 15:47:00", 
                                 "2012-02-06 15:02:00",
                                 "2012-02-22 10:08:00"),
                  duration   = c(1,2,3))

Étant donné que la classe POSIXct contient des informations date-heure de manière structurée, vous pouvez compter sur substr pour extraire les caractères dans les positions temporelles dans le vecteur POSIXct. Autrement dit, étant donné que vous connaissez le format de votre POSIXct (comment il serait présenté lors de l'impression), vous pouvez extraire des heures et des minutes:

# Extract hour and minute as a character vector, of the form "%H:%M"
substr(foo$start.time, 12, 16)

Ensuite, collez-le à une date arbitraire pour le reconvertir en POSIXct. Dans l'exemple, j'utilise le premier janvier 2012, mais si vous ne spécifiez pas de date et utilisez plutôt format R utilise la date actuelle.

# Store time information as POSIXct, using an arbitrary date
foo$time <- as.POSIXct(paste("2012-01-01", substr(foo$start.time, 12, 16)))

Et à la fois plot et ggplot2 savoir formater les heures dans POSIXct hors de la boîte.

# Plot it using base graphics
plot(duration~time, data=foo)

# Plot it using ggplot2 (0.9.2.1)
library(ggplot2)
qplot(x=time, y=duration, data=foo)
17
chemman

Ce code est beaucoup plus rapide que la conversion en chaîne et retour en numérique

time <- c("1979-11-13T08:37:19-0500", "2014-05-13T08:37:19-0400");
time.posix <- as.POSIXct(time, format = "%Y-%m-%dT%H:%M:%S%z");
time.Epoch <- as.vector(unclass(time.posix));
time.poslt <- as.POSIXlt(time.posix, tz = "America/New_York");
time.hour.new.york <- time.poslt$hour + time.poslt$min/60 + time.poslt$sec/3600;

> time;
[1] "1979-11-13T08:37:19-0500" "2014-05-13T08:37:19-0400"
> time.posix;
[1] "1979-11-13 15:37:19 IST" "2014-05-13 15:37:19 IDT"
> time.poslt;
[1] "1979-11-13 08:37:19 EST" "2014-05-13 08:37:19 EDT"
> time.Epoch;
[1]  311348239 1399984639
> time.hour.new.york;
[1] 8.621944 8.621944
8
user43392

Lubridate ne gère pas les données d'heure, Hadley recommande donc le package hms pour ce type de données. Quelque chose comme ça fonctionnerait:

library(lubridate)
foo <- data.frame(start.time = parse_datetime(c("2012-02-06 15:47:00", 
                                 "2012-02-06 15:02:00",
                                 "2012-02-22 10:08:00")),
                  duration   = c(1,2,3))


foo<-foo %>% mutate(time_of_day=hms::hms(second(start.time),minute(start.time),hour(start.time)))

Méfiez-vous de 2 problèmes potentiels - 1) lubridate a une fonction différente appelée hms et 2) hms :: hms prend les arguments dans l'ordre inverse de celui suggéré par son nom (afin que seules quelques secondes puissent être fournies)

6
andyyy