有人可以向我解释为什么以下 POSIXct 时间元素不“匹配”吗?
我最终试图将向量
time
中的日期时间值与向量 datetime
中的日期时间值进行匹配。我已经简化了示例,以便所有内容都是相同的日期,只有小时值不同。在这个例子中,我可以使用 match
来查找 time
中每个 datetime
的索引位置。但是,如果我需要将 time
中的日期时间四舍五入到最接近的小时,此处给出的 roundtime
突然匹配失败?但是time==roundtime
?我在这里缺少什么?
datetime <- as.POSIXct("2020-01-01 15:00:00",tz="UTC") + (0:10) * 3600
time <- as.POSIXct(c("2020-01-01 15:00:00", "2020-01-01 16:00:00", "2020-01-01 21:00:00"),tz='UTC')
roundtime<-round(time,units="hours")
time %in% datetime # gives TRUES
time %in% roundtime # give FALSES?
time == roundtime # gives TRUES
match(time, datetime) # returns matches
match(time, roundtime) # No matches?
match(roundtime, datetime) # no matches?
这个答案扩展了我对OP原始问题的评论。
该问题似乎是由使用
round
: 引起的静默类更改引起的
class(time)
[1] "POSIXct" "POSIXt"
class(datetime)
[1] "POSIXct" "POSIXt"
但是
class(roundtime)
[1] "POSIXlt" "POSIXt"
执行类更改时不会发出警告或注释,并且被默认的 S3
print
方法隐藏:
print(datetime[1])
"2020-01-01 15:00:00 UTC"
print(time[1])
[1] "2020-01-01 15:00:00 UTC"
print(roundtime[1])
[1] "2020-01-01 15:00:00 UTC"
但是,当对象被
unclass
编辑时就很明显了:
print(unclass(datetime[1]))
[1] 1577890800
attr(,"tzone")
[1] "UTC"
print(unclass(time[1]))
[1] 1577890800
attr(,"tzone")
[1] "UTC"
print(unclass(roundtime[1]))
$sec
[1] 0
$min
[1] 0
$hour
[1] 15
$mday
[1] 1
$mon
[1] 0
$year
[1] 120
$wday
[1] 3
$yday
[1] 0
$isdst
[1] 0
attr(,"tzone")
[1] "UTC"
match
失败了,因为正如其在线文档中所明确的那样,“因子、原始向量和列表被转换为字符向量,内部分类对象通过 mtfrm 进行转换,然后 x 和 table 被强制为通用类型( R 排序中两种类型中较晚的一种,逻辑 < integer < numeric < complex < character) before matching. ... Exactly what matches what is to some extent a matter of definition".
这个问题可以通过使用
lubridate
来避免:
library(lubridate)
roundtime1 <- floor_date(datetime, "hour")
class(roundtime1)
[1] "POSIXct" "POSIXt"
match(time, roundtime1)
[1] 1 2 7
match(roundtime1, datetime)
[1] 1 2 3 4 5 6 7 8 9 10 11
>
正如 @r2evans 所写,这是一个无声的、令人讨厌的陷阱,可能会导致难以识别和避免的意外行为。