R 中 X 小时的循环时间?
Round time by X hours in R?
在对带时间戳的数据进行预测建模时,我想在 R 中编写一个函数(可能使用 data.table),将日期按 X 小时数舍入。例如。按 2 小时四舍五入应该是这样的:
"2014-12-28 22:59:00 EDT" becomes "2014-12-28 22:00:00 EDT"
"2014-12-28 23:01:00 EDT" becomes "2014-12-29 00:00:00 EDT"
按 1 小时四舍五入非常容易 - 使用 round.POSIXt(.date, "hour")
函数。
然而,编写一个通用函数,就像我在下面使用多个 if
语句所做的那样,变得非常难看:
d7.dateRoundByHour <- function (.date, byHours) {
if (byHours == 1)
return (round.POSIXt(.date, "hour"))
hh = hour(.date); dd = mday(.date); mm = month(.date); yy = year(.date)
hh = round(hh/byHours,digits=0) * byHours
if (hh>=24) {
hh=0; dd=dd+1
}
if ((mm==2 & dd==28) |
(mm %in% c(1,3,5,7,8,10,12) & dd==31) |
(mm %in% c(2,4,6,9,11) & dd==30)) { # NB: it won't work on 29 Feb leap year.
dd=1; mm=mm+1
}
if (mm==13) {
mm=1; yy=yy+1
}
str = sprintf("%i-%02.0f-%02.0f %02.0f:%02.0f:%02.0f EDT", yy,mm,dd, hh,0,0)
as.POSIXct(str, format="%Y-%m-%d %H:%M:%S")
}
谁能展示更好的方法?
(也许通过转换为数字并返回到 POSIXt 或其他一些 POSIXt 函数?)
使用 lubridate 包中的 round_date
函数。假设您有一个 data.table 和一个名为 date 的列,您可以执行以下操作:
dt[, date := round_date(date, '2 hours')]
一个简单的示例将为您提供您正在寻找的结果:
x <- as.POSIXct("2014-12-28 22:59:00 EDT")
round_date(x, '2 hours')
实际上,仅使用基础 R 就非常容易。"odd lots" 舍入的基本思想
- 按适当比例因子缩小
- 向下舍入为整数
- 扩大规模并重新转换
或者在两个 R 代码语句中:
R> pt <- as.POSIXct(c("2014-12-28 22:59:00", "2014-12-28 23:01:00 EDT"))
R> pt # just to check
[1] "2014-12-28 22:59:00 CST" "2014-12-28 23:01:00 CST"
R>
R> scalefactor <- 60*60*2 # 2 hours of 60 minutes times 60 seconds
R>
R> as.POSIXct(round(as.numeric(pt)/scalefactor) * scalefactor, origin="1970-01-01")
[1] "2014-12-28 22:00:00 CST" "2014-12-29 00:00:00 CST"
R>
关键的最后一行只是做了我概述的事情:将 POSIXct
转换为数字表示,按比例缩小,然后舍入,然后再按比例放大并再次转换为 POSIXct
。
在对带时间戳的数据进行预测建模时,我想在 R 中编写一个函数(可能使用 data.table),将日期按 X 小时数舍入。例如。按 2 小时四舍五入应该是这样的:
"2014-12-28 22:59:00 EDT" becomes "2014-12-28 22:00:00 EDT"
"2014-12-28 23:01:00 EDT" becomes "2014-12-29 00:00:00 EDT"
按 1 小时四舍五入非常容易 - 使用 round.POSIXt(.date, "hour")
函数。
然而,编写一个通用函数,就像我在下面使用多个 if
语句所做的那样,变得非常难看:
d7.dateRoundByHour <- function (.date, byHours) {
if (byHours == 1)
return (round.POSIXt(.date, "hour"))
hh = hour(.date); dd = mday(.date); mm = month(.date); yy = year(.date)
hh = round(hh/byHours,digits=0) * byHours
if (hh>=24) {
hh=0; dd=dd+1
}
if ((mm==2 & dd==28) |
(mm %in% c(1,3,5,7,8,10,12) & dd==31) |
(mm %in% c(2,4,6,9,11) & dd==30)) { # NB: it won't work on 29 Feb leap year.
dd=1; mm=mm+1
}
if (mm==13) {
mm=1; yy=yy+1
}
str = sprintf("%i-%02.0f-%02.0f %02.0f:%02.0f:%02.0f EDT", yy,mm,dd, hh,0,0)
as.POSIXct(str, format="%Y-%m-%d %H:%M:%S")
}
谁能展示更好的方法?
(也许通过转换为数字并返回到 POSIXt 或其他一些 POSIXt 函数?)
使用 lubridate 包中的 round_date
函数。假设您有一个 data.table 和一个名为 date 的列,您可以执行以下操作:
dt[, date := round_date(date, '2 hours')]
一个简单的示例将为您提供您正在寻找的结果:
x <- as.POSIXct("2014-12-28 22:59:00 EDT")
round_date(x, '2 hours')
实际上,仅使用基础 R 就非常容易。"odd lots" 舍入的基本思想
- 按适当比例因子缩小
- 向下舍入为整数
- 扩大规模并重新转换
或者在两个 R 代码语句中:
R> pt <- as.POSIXct(c("2014-12-28 22:59:00", "2014-12-28 23:01:00 EDT"))
R> pt # just to check
[1] "2014-12-28 22:59:00 CST" "2014-12-28 23:01:00 CST"
R>
R> scalefactor <- 60*60*2 # 2 hours of 60 minutes times 60 seconds
R>
R> as.POSIXct(round(as.numeric(pt)/scalefactor) * scalefactor, origin="1970-01-01")
[1] "2014-12-28 22:00:00 CST" "2014-12-29 00:00:00 CST"
R>
关键的最后一行只是做了我概述的事情:将 POSIXct
转换为数字表示,按比例缩小,然后舍入,然后再按比例放大并再次转换为 POSIXct
。