问题
I'm looking to group dates in R by an arbitrary level of precision.
It's pretty straightforward to do this to the nearest hour or minute, using e.g. lubridate:
library(lubridate)
nearest_hour = floor_date(now(), 'hour')
You can then group a list of such dates with e.g. a simple summarise ddply from plyr.
What I'd like to do is round dates with arbitrary precision, e.g. to the nearest 15 minutes or every 3 hours:
nearest_three_hours = floor_date(now(), '3 hours')
There's a discussion of such things at http://r.789695.n4.nabble.com/Truncating-dates-and-other-date-time-manipulations-td866901.html but outside of cutting dates, there doesn't appear to have been any resolution.
回答1:
lubridate already floors to the nearest atomic unit. To get floor to the nearest 15 minutes, which I think is what you want to do (not round), you just need to map into the correct range via findInterval and a defined set of breakpoints. Try this floor_time, which is functionally equivalent to floor_date, but allows you to specify a variable # of units for seconds, minutes or hours.
floor_time <- function(x, k = 1, unit = c("second", "minute", "hour", "day",
"week", "month", "year")) {
require(lubridate)
nmax <- NULL
switch(unit, second = {nmax <- 60},
minute = {nmax <- 60},
hour = {nmax <- 24})
cuts <- seq(from = 0, to = nmax - 1, by = k)
new <- switch(unit,
second = update(x, seconds = cuts[findInterval(second(x), cuts)]),
minute = update(x, minutes = cuts[findInterval(minute(x), cuts)],
seconds = 0),
hour = update(x, hours = cuts[findInterval(hour(x), cuts)],
minutes = 0, seconds = 0),
day = update(x, hours = 0, minutes = 0, seconds = 0),
week = update(x, wdays = 1, hours = 0, minutes = 0, seconds = 0),
month = update(x, mdays = 1, hours = 0, minutes = 0, seconds = 0),
year = update(x, ydays = 1, hours = 0, minutes = 0, seconds = 0))
new
}
回答2:
A little late, and I don't have rep to comment, but as Selva mentioned, lubridate now has this functionality:
library(lubridate)
round_date(now(), '3 hours')
floor_date(now(), '3 hours')
ceiling_date(now(), '3 hours')
回答3:
You can try this, still based on the lubridate library
library(lubridate)
round_minute<-function(x,precision){
m<-minute(x)+second(x)/60
m.r<- round(m/precision)*precision
minute(x)<-m.r
second(x)<-0
x
}
round_minute(ymd_hms(c("2013-06-03 22:53:00","2013-05-03 12:18:00","2013-05-03 00:10:00")),15)
> "2013-06-03 23:00:00 UTC" "2013-05-03 12:15:00 UTC" "2013-05-03 00:15:00 UTC"
The code handle well all the tricky situations thanks to lubridate. Of course this function works only for precision expressed in minutes but you can easily extend it to other units, and even create a generic function if you really need it.
回答4:
lubridate now has a more generic round_date() function.
lubridate::round_date(date, "5 mins")
lubridate::round_date(date, "2 hours")
来源:https://stackoverflow.com/questions/16803867/round-a-date-in-r-to-an-arbitrary-minute-hour-level-of-precision