【问题标题】:ifelse() stripping POSIXct attribute from vector of timestamps?ifelse() 从时间戳向量中剥离 POSIXct 属性?
【发布时间】:2015-06-30 08:35:12
【问题描述】:

这很奇怪:R 的 ifelse() 似乎做了一些(不需要的)转换: 假设我有一个时间戳向量(可能是 NA),NA 值的处理方式应与现有日期不同,例如,只是忽略:

formatString = "%Y-%m-%d %H:%M:%OS"
timestamp = c(as.POSIXct(strptime("2000-01-01 12:00:00.000000", formatString)) + (1:3)*30, NA)

现在

timestamp
#[1] "2000-01-01 12:00:30 CET" "2000-01-01 12:01:00 CET" "2000-01-01 12:01:30 CET"
#[6] NA    

根据需要,但翻译 30 秒会导致

ifelse(is.na(timestamp), NA, timestamp+30)
#[1] 946724460 946724490 946724520        NA

请注意,timestamp+30 仍按预期工作,但假设我想用固定日期替换 NA 日期并将所有其他日期翻译 30 秒:

fixedDate = as.POSIXct(strptime("2000-01-01 12:00:00.000000", formatString))
ifelse(is.na(timestamp), fixedDate, timestamp+30)
#[1] 946724460 946724490 946724520 946724400

问题:这个解决方案有什么问题,为什么不能按预期工作?

编辑:所需的输出是一个转换为 30 秒的时间戳(不是整数)向量,并且 NA 被替换为任何内容......

【问题讨论】:

  • 什么不能按预期工作?我将NA 替换为fixedDate。或者我不明白这个问题。
  • 我第二个@Pascal as.numeric(fixedDate) == ifelse(is.na(timestamp), fixedDate, timestamp+30)[4] 返回TRUE 所以不确定真正的问题是什么
  • 我怀疑要问的问题是:您的预期输出是什么?这可能有助于了解您卡在哪里
  • 您应该研究?ifelseValueWarning 部分以及第三组示例(“ifelse()strips attributes”;“这在使用日期时很重要”)。 A relevant post(谷歌搜索“r ifelse as.POSIXct”时第一次点击)。
  • 我编辑了标题以使问题比 “ifelse 坏了吗?” 更清楚。您需要说它正在剥离 POSIXct 属性。

标签: r posixct


【解决方案1】:

如果您查看ifelse 的编写方式,它有一段代码如下所示:

ans <- test
ok <- !(nas <- is.na(test))
if (any(test[ok]))
  ans[test & ok] <- rep(yes, length.out = length(ans))[test & ok]

请注意,答案以逻辑向量开始,与测试相同。然后将具有test == TRUE 的元素分配给yes 的值。

这里的问题是,将逻辑向量的一个或多个元素分配为 POSIX.ct 类的日期会发生什么。如果你这样做,你可以看到会发生什么:

x <- c(TRUE, FALSE)
class(x)
# logical
x[1] <- Sys.time()
class(x)
# numeric

你可以通过写作来解决这个问题:

timestamp <- timestamp + 30
timestamp[is.na(timestamp)] <- fixedDate

你也可以这样做:

fixedDate = as.POSIXct(strptime("2000-01-01 12:00:00.000000", formatString))
unlist(ifelse(is.na(timestamp), as.list(fixedDate), as.list(timestamp+30)))

这利用了替换运算符[&lt;- 处理右侧列表的方式。

你也可以像这样重新添加类属性:

x <- ifelse(is.na(timestamp), fixedDate, timestamp+30)
class(x) <- c("POSIXct", "POSIXt")

或者,如果您不顾一切地想像这样在一行中做到这一点:

`class<-`(ifelse(is.na(timestamp), fixedDate, timestamp+30), c("POSIXct", "POSIXt"))

或者通过复制fixedDate的属性:

x <- ifelse(is.na(timestamp), fixedDate, timestamp+30)
attributes(x) <- attributes(fixedDate)

最后一个版本还具有复制tzone 属性的优点。

从 dplyr 0.5.0 开始,您还可以使用 dplyr::if_else 在输出中保留类,并为真假参数强制使用相同的类。

【讨论】:

  • strptime(ifelse(...),"%s") 将日期重新转换为字符串怎么样?因为它被强制转换为几秒钟。
  • @Tensibai 同意这对于日期来说会更直接。
  • @Tensibai 更直接的方法是添加适当的class
  • @Tensibai 我的意思是这样x &lt;- ifelse(is.na(timestamp), fixedDate, timestamp + 30); class(x) &lt;- c("POSIXct", "POSIXt")
  • 这个问题在这里得到了有效的 dplyr/tidy 解决方案的回答:stackoverflow.com/questions/6668963/…
【解决方案2】:

正如 Henrik 所说,ifelse() 会剥离属性,这与简单的 for 循环不同。

在不悲伤的情况下填充 NA 的解决方法是更简单、更清晰的函数 zoo::na.fill

那么你会这样做:na.fill(timestamp, fixedDate)

另请参阅 na.locf, na.approx, na.spline ...,其他来自 zoo 的出色便利功能。

【讨论】:

  • 如前所述:在向量上的普通 for 循环将返回时间戳序列,而不是整数。
  • 已更新以涵盖该内容
  • 哦,顺便说一句:我不明白为什么 ifelse 会这样做。我不认为它是完美的......它只是一个陷阱。人们还可以对输出进行傅立叶变换,并得到理论上“可以”重新解释为时间戳的东西,但仍然:人们不会这样做。为什么?因为它会是废话:如果我输入时间戳,我希望输出是相同的类型......
  • 我同意这不好,这是一个鲜为人知的陷阱,应该更突出地记录(如果不是也触发 “警告:ifelse 删除的属性 ....”)。我建议你像我说的那样使用zoo::na.fill()。它更快、更简单、更清晰。
猜你喜欢
  • 2011-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-22
相关资源
最近更新 更多