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

问题描述 投票:0回答:3

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

r posixct
3个回答
8
投票

如果你看一下

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)))

这利用了替换运算符

[<-
处理右侧列表的方式。

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

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
投票

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

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

zoo::na.fill

然后你会这样做:

na.fill(timestamp, fixedDate)

另请参阅

na.locf, na.approx, na.spline ...
,动物园其他出色的便利功能。


0
投票

threadrezzing 提供更简单的 tidyverse cough 解决方案,因为

dplyr::case_when
保留 POSIXct 数据。

library(dplyr)
library(lubridate)

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

timestamp %>% mutate(a = case_when(
  is.na(a) ~ NA_POSIXct_, 
  TRUE ~ a + 30)) %>% pull
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.