66

假设我有以下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$durationv.的情节foo$start.time。在我的场景中,我只对一天中的时间感兴趣,而不是一年中的实际一天。如何从POSIXct向量类中提取一天中的时间为小时:秒?

4

5 回答 5

57

这是一个很好的问题,并强调了在 R 中处理日期的一些困难。 lubridate 包非常方便,所以下面我介绍两种方法,一种使用 base(如 @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")
于 2012-05-22T18:42:19.663 回答
18

您可以依赖基础 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 年 1 月第一次,但如果您不指定日期而是使用formatR 使用当前日期。

# 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)
于 2012-10-12T23:18:05.283 回答
10

Lubridate 不处理一天中的时间数据,因此 Hadley 建议将 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)))

注意 2 个潜在问题 - 1) lubridate 有一个不同的函数,称为 hms 和 2) hms::hms 以与其名称所建议的相反的顺序接受参数(因此可以只提供几秒钟)

于 2017-12-06T11:43:08.070 回答
8

此代码比转换为字符串并返回数字要快得多

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
于 2014-07-01T18:32:15.287 回答
2

这是一个古老的话题,但我发现关于这个问题的问题和答案很少。我的解决方案如下

library(hms)
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))

foo$start.time = as.POSIXct( foo$start.time )

g1 = ggplot( ) + xlab("") + 
  geom_line( data = foo, aes(x = as.hms(start.time), y = duration ), color = "steelblue" )
g1

如果您想添加手动时间 (!) 休息时间,那么

time_breaks =    as.POSIXlt(c(
                   "2012-02-06 12:35:00 MSK", 
                   "2012-02-06 13:15:00 MSK",
                   "2012-02-06 14:22:00 MSK",
                   "2012-02-06 15:22:00 MSK"))
 g1 + 
  scale_x_time( breaks = as.hms( time_breaks ) ) +
  theme(  axis.text.x = element_text( angle=45, vjust=0.25) ) 
于 2019-09-11T14:36:58.963 回答