我有一些数据,其格式如下:
time count
00:00 17
00:01 62
00:02 41
所以我有从 00:00 到 23:59 的时间,每分钟有一个计数器。我想以 15 分钟为间隔对数据进行分组,这样:
time count
00:00-00:15 148
00:16-00:30 284
我尝试过手动执行此操作,但这很累人,所以我确信必须有一个函数或某物可以轻松完成此操作,但我还没有弄清楚如何执行此操作。
我真的很感激一些帮助!
非常感谢!
对于 POSIXct 格式的数据,您可以使用
cut
函数创建 15 分钟分组,然后按这些组进行聚合。下面的代码展示了如何在 base R
中以及使用 dplyr
和 data.table
包执行此操作。
首先,创建一些假数据:
set.seed(4984)
dat = data.frame(time=seq(as.POSIXct("2016-05-01"), as.POSIXct("2016-05-01") + 60*99, by=60),
count=sample(1:50, 100, replace=TRUE))
基础R
cut
将数据分为 15 分钟组:
dat$by15 = cut(dat$time, breaks="15 min")
time count by15 1 2016-05-01 00:00:00 22 2016-05-01 00:00:00 2 2016-05-01 00:01:00 11 2016-05-01 00:00:00 3 2016-05-01 00:02:00 31 2016-05-01 00:00:00 ... 98 2016-05-01 01:37:00 20 2016-05-01 01:30:00 99 2016-05-01 01:38:00 29 2016-05-01 01:30:00 100 2016-05-01 01:39:00 37 2016-05-01 01:30:00
现在
aggregate
通过新的分组列,使用sum
作为聚合函数:
dat.summary = aggregate(count ~ by15, FUN=sum, data=dat)
by15 count 1 2016-05-01 00:00:00 312 2 2016-05-01 00:15:00 395 3 2016-05-01 00:30:00 341 4 2016-05-01 00:45:00 318 5 2016-05-01 01:00:00 349 6 2016-05-01 01:15:00 397 7 2016-05-01 01:30:00 341
dplyr
library(dplyr)
dat.summary = dat %>% group_by(by15=cut(time, "15 min")) %>%
summarise(count=sum(count))
数据表
library(data.table)
dat.summary = setDT(dat)[ , list(count=sum(count)), by=cut(time, "15 min")]
更新:回答评论,对于这种情况,每个分组间隔的终点是
as.POSIXct(as.character(dat$by15)) + 60*15 - 1
。换句话说,分组间隔的终点是从间隔开始算起的 15 分钟减去 1 秒。我们加上 60*15 - 1,因为 POSIXct
以秒为单位。 as.POSIXct(as.character(...))
是因为 cut
返回一个因子,这只是将其转换回日期时间,以便我们可以对其进行数学运算。
如果您希望终点为下一个间隔之前最近的一分钟(而不是最近的秒),您可以
as.POSIXct(as.character(dat$by15)) + 60*14
。
如果您不知道休息间隔,例如,因为您选择了休息次数并让 R 选择间隔,您可以通过执行
max(unique(diff(as.POSIXct(as.character(dat$by15))))) - 1
找到要添加的秒数。
剪切方法很方便,但对于大数据帧来说速度很慢。以下方法比剪切方法快大约 1,000 倍(使用 400k 条记录进行测试。)
# Function: Truncate (floor) POSIXct to time interval (specified in seconds)
# Author: Stephen McDaniel @ PowerTrip Analytics
# Date : 2017MAY
# Copyright: (C) 2017 by Freakalytics, LLC
# License: MIT
floor_datetime <- function(date_var, floor_seconds = 60,
origin = "1970-01-01") { # defaults to minute rounding
if(!is(date_var, "POSIXct")) stop("Please pass in a POSIXct variable")
if(is.na(date_var)) return(as.POSIXct(NA)) else {
return(as.POSIXct(floor(as.numeric(date_var) /
(floor_seconds))*(floor_seconds), origin = origin))
}
}
示例输出:
test <- data.frame(good = as.POSIXct(Sys.time()),
bad1 = as.Date(Sys.time()),
bad2 = as.POSIXct(NA))
test$good_15 <- floor_datetime(test$good, 15 * 60)
test$bad1_15 <- floor_datetime(test$bad1, 15 * 60)
Error in floor_datetime(test$bad, 15 * 60) :
Please pass in a POSIXct variable
test$bad2_15 <- floor_datetime(test$bad2, 15 * 60)
test
good bad1 bad2 good_15 bad2_15
1 2017-05-06 13:55:34.48 2017-05-06 <NA> 2007-05-06 13:45:00 <NA>
您可以使用 FQOAT 中的 trs 函数在一行中完成此操作,就像:
df_15mins=trs(df, "15 mins")
下面是一个可重复的示例:
library(foqat)
head(aqi[,c(1,2)])
# Time NO
#1 2017-05-01 01:00:00 0.0376578
#2 2017-05-01 01:01:00 0.0341483
#3 2017-05-01 01:02:00 0.0310285
#4 2017-05-01 01:03:00 0.0357016
#5 2017-05-01 01:04:00 0.0337507
#6 2017-05-01 01:05:00 0.0238120
#mean
aqi_15mins=trs(aqi[,c(1,2)], "15 mins")
head(aqi_15mins)
# Time NO
#1 2017-05-01 01:00:00 0.02736549
#2 2017-05-01 01:15:00 0.03244958
#3 2017-05-01 01:30:00 0.03743626
#4 2017-05-01 01:45:00 0.02769419
#5 2017-05-01 02:00:00 0.02901817
#6 2017-05-01 02:15:00 0.03439455
我没有足够的代表点来发表评论,但也许这里的版主可以帮助添加上面Stephen McDaniel的答案。 有没有办法扩展这个功能 然后使用新的中断来汇总数据并保持性能?