Извлечение часов и секунд с POSIXct для целей построения графика в R
Предположим, что у меня есть data.frame
foo
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
И class(foo$start.time)
возвращает
[1] "POSIXct" "POSIXt"
Я хотел бы создать график foo$duration
v. foo$start.time
. По моему сценарию меня интересует только время дня, а не фактический день года. Как вы делаете извлечение времени дня в виде часов: секунд из POSIXct
класса вектора?
Ответы
Ответ 1
Это хороший вопрос и подчеркивает некоторые трудности в работе с датами в R. Пакет lubridate очень удобен, поэтому ниже я представляю два подхода, один из которых использует базу (как предложено @RJ-), а другой используя lubridate.
Восстановите (первые две строки) блока данных в исходном сообщении:
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))
Преобразовать в класс POSIXct и POSIXt (два способа сделать это)
# 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)
Теперь выберем время в виде десятичных часов
# 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
Продемонстрируйте, что эти подходы равны:
identical(h.str, h.lub)
Затем выберите один из следующих подходов, чтобы назначить десятичный час 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 }
затем построим с использованием пакета ggplot2:
library(ggplot2)
qplot(foo$hr, foo$duration) +
scale_x_datetime(labels = "%S:00")
Ответ 2
Вы можете положиться на базу 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))
Так как класс POSIXct содержит информацию о дате в структурированном виде, вы можете положиться на substr
для извлечения символов во временных позициях в векторе POSIXct. То есть, если вы знаете формат своего POSIXct (как он будет отображаться при печати), вы можете извлечь часы и минуты:
# Extract hour and minute as a character vector, of the form "%H:%M"
substr(foo$start.time, 12, 16)
И затем вставьте его в произвольную дату, чтобы преобразовать его обратно в POSIXct. В примере я использую январь в начале 2012 года, но если вы не укажете дату и вместо этого используете format
, то R использует текущую дату.
# Store time information as POSIXct, using an arbitrary date
foo$time <- as.POSIXct(paste("2012-01-01", substr(foo$start.time, 12, 16)))
И оба plot
и ggplot2
умеют форматировать время в POSIXct из коробки.
# 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)
Ответ 3
Этот код намного быстрее, чем преобразование в строку и обратно в числовое
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
Ответ 4
Lubridate не обрабатывает данные о времени суток, поэтому Хэдли рекомендует пакет hms для этого типа данных. Что-то вроде этого будет работать:
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)))
Следите за двумя потенциальными проблемами - 1) lubridate имеет другую функцию, называемую hms, и 2) hms:: hms принимает аргументы в противоположном порядке к предложению по его имени (так что могут быть предоставлены только секунды)