1
votes

I have imported data with a five minute interval into a zoo object, where the index is a chron with both date and time:

> d
(09/09/09 16:45:10)  13.2  5.8
(09/09/09 16:50:10)   8.3  0.7
(09/09/09 16:55:10)   4.7  0.7
(09/09/09 17:00:10)   6.6  0.7
(09/09/09 17:05:10)   4.6  0.7

I am trying to aggregate by quarter hour intervals.

I found way to do so by converting back to a string, but the output is no longer a zoo.

> r =data.frame(aggregate(d,trunc(chron(times=substr(as.character(index(d)),11,18)),"00:15:00"), mean)
> r
00:00:00   0.5644444
00:15:00   0.5400000
00:30:00   0.5488889
00:45:00   0.6155556
01:00:00   0.3422222

While I can plot this, I was trying to do this natively. I found that aggregate with zoo could do day and hour, but I could not subdivide the hour.

3

3 Answers

4
votes

I don't believe that there's any way to do this built into zoo or chron, but you can create your own function by using a little math. Here you go:

trunc.minutes <- function (x, n.minutes) 
{
    if (!inherits(x, "times")) 
        x <- as.chron(x)
    x <- as.numeric(x)
    sec <- round(24 * 3600 * abs(x - floor(x)))
    h <- (sec%/%(n.minutes*60))/(60/n.minutes)
    hour <- as.integer(h)
    minutes <- (h %% hour) * 60
    chron(dates=chron::dates(x), times=times(paste(hour, minutes, "00", sep=":")))
}

Here's an example of the usage:

dts <- chron::dates(c("02/27/92", "02/27/92", "01/14/92",
                "02/28/92", "02/01/92"))
tms <- times(c("23:03:20", "23:29:56", "01:03:30",
                "18:21:03", "16:56:26"))     
x <- chron(dates = dts, times = tms) # original dates
x
[1] (02/27/92 23:03:20) (02/27/92 22:29:56) (01/14/92 01:03:30)
[4] (02/28/92 18:21:03) (02/01/92 16:56:26)
trunc.minutes(x, 15) # new dates at 15 minute intervals
[1] (02/27/92 23:00:00) (02/27/92 22:15:00) (01/14/92 01:00:00)
[4] (02/28/92 18:15:00) (02/01/92 16:45:00)
trunc.minutes(x, 30) # new dates at 30 minute intervals
[1] (02/27/92 23:00:00) (02/27/92 22:00:00) (01/14/92 01:00:00)
[4] (02/28/92 18:00:00) (02/01/92 16:30:00)

Lastly, you can now use this function to aggregate the data:

ts.zoo <- zoo(rnorm(5), x) # a zoo time series

Or just use these new dates for aggregation (see how it rolls up the second example since there are two values in that window):

> aggregate(ts.zoo, trunc.minutes(x, 15), mean)
(01/14/92 01:00:00) (02/01/92 16:45:00) (02/27/92 23:00:00) (02/27/92 23:15:00) 
         -0.6738659          -0.4844803           0.7968155          -1.3571121 
(02/28/92 18:15:00) 
          0.7625861 
> aggregate(ts.zoo, trunc.minutes(x, 30), mean)
(01/14/92 01:00:00) (02/01/92 16:30:00) (02/27/92 23:00:00) (02/28/92 18:00:00) 
         -0.6738659          -0.4844803          -0.2801483           0.7625861 
2
votes

chron has a trunc.times method so we can do this:

library(zoo)
library(chron)
z <- zoo(1:5, 
   chron(c("02/27/92", "02/27/92", "01/14/92", "02/28/92", "02/01/92"),
   c("23:03:20", "23:29:56", "01:03:30", "18:21:03", "16:56:26")))
aggregate(z, function(x) trunc(x, "00:15:00"), mean)
1
votes

Given Shane's idea, I've change it a bit... The original question was how to aggregate on the minutes in the hours involved and get rid of the date. Also since the math didn't like midnight earlier, I'm using string parsing.

# Where X is a zoo obj with chron timestamps containing both time & date
# and min is like "00:30:00" for half hour intervals
> trunc.chrontime = function (x, min)
  {
    if (!inherits(x, "times")) 
        x = as.chron(x)
    s = substr(as.character(x),11,18)
    c = chron(times=s)
    trunc(c,min)
  }

> s = aggregate(d,trunc.minstr(index(d),"00:30:00"),mean)
s
00:00:00  0.5522222 0.4988889 0.006666667
00:30:00  0.5822222 0.5366667 0.012222222
01:00:00  0.3388889 0.4455556 0.000000000
01:30:00  0.3422222 0.4344444 0.000000000
02:00:00  0.3366667 0.4366667 0.000000000 ...