4

I'm trying to set a time value into a data frame:

ps = data.frame(t(rep(NA, 2)))
ps[1,1] = strptime('10:30:00', '%H:%M:%S')

but I get the error:

provided 9 variables to replace 1 variables

since a time value is a list (?) in R it thinks I'm trying to set 9 columns, when I really just want to set the one column to that class.

What can I do to make this set properly?

Gavin Simpson
  • 170,508
  • 25
  • 396
  • 453
Reverend Gonzo
  • 39,701
  • 6
  • 59
  • 77

1 Answers1

9

This is due to the result of strptime() being an object of class "POSIXlt":

> ps = data.frame(t(rep(NA, 2)))
> ps[1,1] = strptime('10:30:00', '%H:%M:%S')
Warning message:
In `[<-.data.frame`(`*tmp*`, 1, 1, value = list(sec = 0, min = 30L,  :
  provided 9 variables to replace 1 variables
> strptime('10:30:00', '%H:%M:%S')
[1] "2012-03-21 10:30:00"
> class(strptime('10:30:00', '%H:%M:%S'))
[1] "POSIXlt" "POSIXt"

A "POSIXlt" object is a list representation (hence the lt rather than the ct in the class name) of the time:

> foo <- strptime('10:30:00', '%H:%M:%S')
> str(foo)
 POSIXlt[1:1], format: "2012-03-21 10:30:00"
> unclass(foo)
$sec
[1] 0

$min
[1] 30

$hour
[1] 10

$mday
[1] 21

$mon
[1] 2

$year
[1] 112

$wday
[1] 3

$yday
[1] 80

$isdst
[1] 0

A "POSIXlt" object is a list of length 9:

> length(unclass(foo))
[1] 9

hence the warning message, as the object is being stripped back to it's constituent parts/representation. You can stick the "POSIXct" representation in instead without generating the warning:

> ps[1,1] = as.POSIXct(strptime('10:30:00', '%H:%M:%S'))
> ps[1,1]
[1] 1332325800

but we are still loosing the class information. Still, you can go back to the "POSIXct" representation later using the as.POSIXct() function but you will need to specify the origin argument. See ?POSIXct for more.

> class(ps[1,1])
[1] "numeric"

A solution is to coerce ps$X1 to be class "POSIXct" before inserting the time:

> ps = data.frame(t(rep(NA, 2)))
> ps <- transform(ps, X1 = as.POSIXct(X1))
> ps[1,1] <- as.POSIXct(strptime('10:30:00', '%H:%M:%S'))
> ps
                   X1 X2
1 2012-03-21 10:30:00 NA
> str(ps)
'data.frame':   1 obs. of  2 variables:
 $ X1: POSIXct, format: "2012-03-21 10:30:00"
 $ X2: logi NA

No warning (as before with as.POSIXct()) but also the class information is retained, where before it was lost. Do read ?`[.data.frame`, especially the Coercion section which has some details; but my take how is that understanding the coercion in replacements like this is tricky.

Gavin Simpson
  • 170,508
  • 25
  • 396
  • 453
  • Awesome, and a follow up question, I initially have the POSIXlt in a data frame that I load with read.table and a custom class/parser. Is the reason that data frame was able to hold the list because it had its class coerced to POSIXlt? – Reverend Gonzo Mar 21 '12 at 14:13
  • If you told `read.table()` the correct classes via the `colClasses` argument then it takes you at your word. The problem you are seing is that you are trying to stick a `"POSIXlt"` object into a vector that is class `"logical"` (that is what you get when you define `ps` in the way you did (check `X2` in the very last code example - note the `logi NA`). There is nothing wrong in holding any sort of object in a data frame (subject to the atomicity of the individual vectors) - the issue here is the coercion rules when the target and origin classes are not the same. – Gavin Simpson Mar 21 '12 at 14:23