Reputation: 24765
Consider the following R code which replaces the values in one column of a data frame with a set of POSIXct values:
foo <- as.data.frame(list(bar=rep(5,5)))
bar <- as.POSIXct(rep(5,5), origin="1970-1-1", tz="c")
foo[,1] <- bar
My question: why does the same operation fail when I try to use POSIXlt instead? For example:
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
Moreover, if I refer to the column by name, instead of by index, the same assignment works just fine:
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
What am I missing?
Upvotes: 1
Views: 4460
Reputation: 132706
From help("[.data.frame")
:
For [ the replacement value can be a list: each element of the list is used to replace (part of) one column, recycling the list as necessary.
So you can do things like this:
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
However, this results in a warning:
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
Now a POSIXlt
object is a list with 9 elements:
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"
Assigning this list to one column using [<-.data.frame
gives the warning you observed.
Potential solutions to the problem are simple:
POSIXct
and avoid POSIXlt
. The only reason for using the latter is a need for extracting some of the list components, which is not often the case (and you can always coerce to POSIXlt
, e.g., inside functions for rounding of time values).$<-.data.frame
. This is often cumbersome outside of interactive use.POSIXlt
object in a list
for assignment: df[,1] <- list(POSIXlt_object)
.Upvotes: 5
Reputation: 22293
It appears that POSIXlt
objects are lists, with 9 entries.
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"
Apparently the assignment to a data.frame fails because the POSIXlt
object is unlisted.
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
On the other hand, the assignment to a list 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
Upvotes: 1