用POSIXlt对象替换列值

时间:2013-10-04 07:27:50

标签: r dataframe assign posixct

考虑以下R代码,用一组POSIXct值替换数据框的一列中的值:

foo <- as.data.frame(list(bar=rep(5,5)))
bar <- as.POSIXct(rep(5,5), origin="1970-1-1", tz="c")
foo[,1] <- bar

我的问题:当我尝试使用POSIXlt时,为什么同样的操作失败?例如:

foo <- as.data.frame(list(bar=rep(5,5)))
bar <- as.POSIXlt(rep(5,5), origin="1970-1-1", tz="c")
foo[,1] <- bar
Warning message:
   In `[<-.data.frame`(`*tmp*`, , 1, value = list(sec = c(5, 5, 5,  :
   provided 9 variables to replace 1 variables

此外,如果我按名称而不是索引引用列,则相同的赋值可以正常工作:

foo$bar <- bar
foo <- as.data.frame(list(bar=rep(5,5)))
bar <- as.POSIXlt(rep(5,5), origin="1970-1-1", tz="c")
foo$bar <- bar

我错过了什么?

2 个答案:

答案 0 :(得分:5)

来自help("[.data.frame")

  

对于[替换值可以是列表:列表的每个元素都是   用于替换(一部分)一列,根据需要回收列表。

所以你可以这样做:

df <- data.frame(a=1:2)
df[,2:3] <- list(3:4, 5:6)
#  a V2 V3
#1 1  3  5
#2 2  4  6

然而,这会导致警告:

df[,4] <- list(7, 8)
# Warning message:
#   In `[<-.data.frame`(`*tmp*`, , 4, value = list(7, 8)) :
#   provided 2 variables to replace 1 variables
#   a V2 V3 V4
# 1 1  3  5  7
# 2 2  4  6  7

现在POSIXlt对象是一个包含9个元素的列表:

unclass(rep(as.POSIXlt(Sys.time()), 2))
# $sec
# [1] 1.958244 1.958244
# 
# $min
# [1] 54 54
# 
# $hour
# [1] 10 10
# 
# $mday
# [1] 4 4
# 
# $mon
# [1] 9 9
# 
# $year
# [1] 113 113
# 
# $wday
# [1] 5 5
# 
# $yday
# [1] 276 276
# 
# $isdst
# [1] 1 1
# 
# attr(,"tzone")
# [1] ""     "CET"  "CEST"

使用[<-.data.frame将此列表分配给一列会显示您观察到的警告。

解决问题的潜在解决方案很简单:

  • 使用POSIXct并避免POSIXlt。使用后者的唯一原因是需要提取一些列表组件,这通常不是这种情况(并且您可以始终强制转换为POSIXlt,例如,内部函数用于舍入时间值)。
  • 使用$<-.data.frame。在交互式使用之外,这通常很麻烦。
  • POSIXlt对象换入list以进行分配:df[,1] <- list(POSIXlt_object)

答案 1 :(得分:1)

POSIXlt个对象似乎是列表,有9个条目。

unlist(as.POSIXlt(5, origin="1970-1-1"))
sec   min  hour  mday   mon  year  wday  yday isdst 
  5     0     1     1     0    70     4     0     0

unlist(as.POSIXct(5, origin="1970-1-1"))
[1] "1970-01-01 00:00:05 CET"

显然,对data.frame的赋值失败,因为POSIXlt对象未列出。

foo <- as.data.frame(list(bar=rep(5,5)))
bar <- as.POSIXlt(rep(5,5), origin="1970-1-1", tz="")
foo[,1] <- bar   # this fails
foo[,1:9] <- bar # this works

另一方面,对列表的分配起作用。

foo <- as.data.frame(list(bar=rep(5,5)))
bar <- as.POSIXlt(rep(5,5), origin="1970-1-1", tz="")
foo[[1]] <- bar  # or foo$bar <- bar