【问题标题】:R extract time components from semi-standard stringsR从半标准字符串中提取时间分量
【发布时间】: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

问题

  1. 处理所有可能的字符串格式的“R 方式”是什么?也许单独测试并提取每个元素,然后重新组合?
  2. 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 也使用它)。

标签: string r time posixct


【解决方案1】:

difftime 对象是持续时间对象,可以添加到POSIXctPOSIXlt 对象。也许你想用这个代替POSIXlt

关于从字符串到时间对象的转换,你可以这样做:

data <- data.frame(time.string = c(
    "1 d 1 h",
    "30 m 10 s",
    "1 d 2 h 3 m 4 s",
    "2 h 3 m 4 s",
    "10 d 20 h 30 m 40 s",
    "--"))

f <- function(x) {
    x <- as.character(x)
    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) {
        if (grepl('%j d', format)) {
            # '%j 1' is day 0. We add a day so that x = '1 d' means 24hrs.
            difftime(as.POSIXct(x, format=format) + as.difftime(1, units='days'), 
                    cut(Sys.Date(), breaks='years'),
                    units='hours')
        } else {
            as.difftime(x, format, units='hours')
        }
    } else { NA }
}

data$time.span <- sapply(data$time.string, FUN=f)

【讨论】:

  • 这是计算上面format的另一种方法:library(gsubfn); format &lt;- paste(strapply(x, "[dhms]", list(d = "%j d", h = "%H h", m = "%M m", s = "%S s"))[[1]], collapse = " ")
  • @mplourde 感谢您的详细回复,我正在努力实施和测试。我仍然对 R 中如何使用 paste()sapply() 有所了解,所以我需要深入了解它是如何工作的。
  • 一个可靠的答案。我测试过,它对我有用。是的,difftime 是处理持续时间的最佳数据类型。
  • 我对这个解决方案进行了一些调整,主要是添加了一个单位参数以保持一致性:as.difftime(x, format=format,units="hours"。奇怪的是它会产生一些 negative difftime 值,这是非法的持续时间。我正在调查哪些情况会导致这种行为。
  • 我已更新解决方案以正确处理您的朱利安日。
【解决方案2】:

我认为lubridate 会更好:

来自Dates and Times Made Easy with lubridate

5.3。持续时间

...

持续时间的长度不受闰年、闰秒和夏令时的影响 因为持续时间以秒为单位。因此,持续时间具有一致的长度和 可以很容易地与其他持续时间进行比较。持续时间是在以下情况下使用的适当对象 比较基于时间的属性,例如速度、速率和寿命。 lubridate 使用来自基础 R 的 difftime 类持续时间。其他 difftime 方法 为了促进这一点而创建的。

lubridate 使用基础 R 中的 difftime 类作为持续时间。其他 difftime 方法 为了促进这一点而创建的。

...

可以使用辅助函数 dyears()、dweeks()、ddays()、dhours()、dminutes() 和 dseconds() 轻松创建 Duration 对象。标题中的 d 代表持续时间,并将这些对象与第 5.4 节中讨论的周期对象区分开来。每个对象使用上面给出的估计关系创建一个以秒为单位的持续时间。

也就是说,我还没有(还)找到一个函数来将字符串解析为持续时间。


您还可以查看Ruby's Chronic,了解时间解析的优雅程度。我还没有为 R 找到这样的库。

【讨论】:

  • 这些链接很有用,谢谢。目前我仅限于使用基础 R 2.11。令人沮丧,但我必须忍受的约束。幸运的是,我目前没有自然语言要求。不过,我有兴趣在未来尝试这样的项目,Chronic 可能是一个有用的方法。 Recorded Future 是该领域的一家公司;有趣的是,看看当它起作用时你可以把它带到哪里。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-21
  • 2016-12-24
  • 1970-01-01
  • 2016-01-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多