rnumericposixctposixlt

`by()` changed POSIXct to numeric value in R


In R, how to prevent the by() function from changing POSIXct to numeric values automatically?


In the following example, the time object is class "POSIXct" "POSIXt". When using by() function, the output is numeric. But when doing what by() does manually, e.g. min(time[index=='a']), the output is still "POSIXct" "POSIXt", which is desired. Is there a way to prevent the by() function from changing POSIXct to numeric values automatically?

time = c("0001-03-04 05:36:00 UTC", "0001-03-04 05:50:00 UTC", "0001-03-04 06:05:00 UTC")
time = as.POSIXct(time, tz = "UTC")
index = c("a", "a", "b")

by(time, index, min) # results are numeric values.
min(time[index=='a']) # "0001-03-04 05:36:00 UTC"

Solution

  • 1) Return a list and then concatenate the elements of the result.

    do.call("c", by(time, index, function(x) list(min(x))))
    ##                         a                         b 
    ## "0001-03-04 05:36:00 UTC" "0001-03-04 06:05:00 UTC" 
    

    2) split/lapply would also work:

    do.call("c", lapply(split(time, index), min))
    ##                         a                         b 
    ## "0001-03-04 05:36:00 UTC" "0001-03-04 06:05:00 UTC" 
    

    3) as would tapply with simplify = FALSE:

    do.call("c", tapply(time, index, min, simplify = FALSE))
    ##                         a                         b 
    ## "0001-03-04 05:36:00 UTC" "0001-03-04 06:05:00 UTC" 
    

    4) aggregate can be used.

    with(aggregate(time ~., data.frame(time, index), min), setNames(time, index))
    ##                         a                         b 
    ## "0001-03-04 05:36:00 UTC" "0001-03-04 06:05:00 UTC" 
    

    or if names are not needed:

    aggregate(time, list(index), min)$x
    ## [1] "0001-03-04 05:36:00 UTC" "0001-03-04 06:05:00 UTC"
    

    or to get a data frame result:

    aggregate(time ~., data.frame(time, index), min)
    ##   index                time
    ## 1     a 0001-03-04 05:36:00
    ## 2     b 0001-03-04 06:05:00