【发布时间】:2012-06-24 04:22:42
【问题描述】:
设置
我有一列持续时间作为字符串存储在数据框中。我想将它们转换为适当的时间对象,可能是POSIXlt。使用this method 可以轻松解析大部分字符串:
> data <- data.frame(time.string = c(
+ "1 d 2 h 3 m 4 s",
+ "10 d 20 h 30 m 40 s",
+ "--"))
> data$time.span <- strptime(data$time.string, "%j d %H h %M m %S s")
> data$time.span
[1] "2012-01-01 02:03:04" "2012-01-10 20:30:40" NA
缺少的持续时间编码为"--",需要转换为NA - 这已经发生但应该保留。
挑战在于字符串会丢弃零值元素。因此所需的值2012-01-01 02:00:14 将是字符串"1 d 2 h 14 s"。然而,这个字符串使用简单的解析器解析为NA:
> data2 <- data.frame(time.string = c(
+ "1 d 2 h 14 s",
+ "10 d 20 h 30 m 40 s",
+ "--"))
> data2$time.span <- strptime(data2$time.string, "%j d %H h %M m %S s")
> data2$time.span
[1] NA "2012-01-10 20:30:40" NA
问题
- 处理所有可能的字符串格式的“R 方式”是什么?也许单独测试并提取每个元素,然后重新组合?
- POSIXlt 是正确的目标类吗?我需要不受任何特定开始时间的持续时间,因此添加错误的年月数据 (
2012-01-) 很麻烦。
解决方案
@mplourde 绝对有正确的想法,即基于测试日期格式中的各种条件来动态创建格式化字符串。添加cut(Sys.Date(), breaks='years') 作为datediff 的基线也很好,但未能解决as.POSIXct() 中的一个关键怪癖注意:我使用的是R2.11 基础,这可能已在更高版本。
as.POSIXct() 的输出会根据是否包含日期组件而发生巨大变化:
> x <- "1 d 1 h 14 m 1 s"
> y <- "1 h 14 m 1 s" # Same string, no date component
> format (x) # as specified below
[1] "%j d %H h %M m %S s"
> format (y)
[1] "% H h % M %S s"
> as.POSIXct(x,format=format) # Including the date baselines at year start
[1] "2012-01-01 01:14:01 EST"
> as.POSIXct(y,format=format) # Excluding the date baselines at today start
[1] "2012-06-26 01:14:01 EDT"
因此difftime 函数的第二个参数应该是:
- 如果输入字符串有天组件,则为当年第一天的开始
- 当前天的开始,如果输入字符串没有有天组件
这可以通过更改cut 函数上的单位参数来实现:
parse.time <- function (x) {
x <- as.character (x)
break.unit <- ifelse(grepl("d",x),"years","days") # chooses cut() unit
format <- paste(c(if (grepl("d", x)) "%j d",
if (grepl("h", x)) "%H h",
if (grepl("m", x)) "%M m",
if (grepl("s", x)) "%S s"), collapse=" ")
if (nchar(format) > 0) {
difftime(as.POSIXct(x, format=format),
cut(Sys.Date(), breaks=break.unit),
units="hours")
} else {NA}
}
【问题讨论】:
-
这可能会给一些方向:stackoverflow.com/questions/1828206/…
-
这并不能解决您的问题,但是您遇到了strptime 的问题,因为它不是为解析持续时间而设计的;它旨在解析时间戳。 (有些持续时间看起来像时间戳,有些则不是。)
-
@DavidJames 好的,这是有道理的。您是否同意@mplourde 的观点,即最好先格式化,然后使用
as.difftime()进行投射? -
如果你从一个字符串开始,你必须先解析它,根据定义。 :) 那么只有选择将其转换为的类型才有意义——
difftime才有意义(lubridate 也使用它)。