ifelse()从时间戳向量中剥离POSIXct属性吗?

时间:2015-06-30 08:35:13

标签: r posixct

这很奇怪: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被替换为...

2 个答案:

答案 0 :(得分:4)

如果你看一下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)))

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

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

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在输出中保留类,并为true和false参数强制使用相同的类。

答案 1 :(得分:1)

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

在没有悲伤的情况下填充NAs的解决方法是更简单,更清晰的功能zoo::na.fill

然后你会这样做:na.fill(timestamp, fixedDate)

另见na.locf, na.approx, na.spline ...,动物园的其他优秀便利功能。