我的问题是将每1分钟收集的数据汇总到5分钟的平均值。
DeviceTime Concentration
6/20/2013 11:13
6/20/2013 11:14
6/20/2013 11:15
6/20/2013 11:16
6/20/2013 11:17
6/20/2013 11:18
6/20/2013 11:19
6/20/2013 11:20
6/20/2013 11:21
6/20/2013 11:22
6/20/2013 11:23
6/20/2013 11:24
6/20/2013 11:25
6/20/2013 11:26
6/20/2013 11:27
6/20/2013 11:28
...
我想要的结果是:
DeviceTime Concentration
6/20/2013 11:15
6/20/2013 11:20
6/20/2013 11:25
6/20/2013 11:30
6/20/2013 11:35
...
5分钟的平均值只是过去五分钟内浓度的简单平均值。
答案 0 :(得分:19)
如果你的数据没有在一个漂亮的5分钟挂钟边界上开始(如示例数据中所示--11:13),请注意cut()
将根据第一个时间戳创建断点认定。这可能不是我们通常想要的。实际上,您的示例输出表明这不是您想要的。
这是cut()
的作用:
df <- read.table(header=TRUE, sep=",", stringsAsFactors=FALSE, text="
DeviceTime,Concentration
6/20/2013 11:13,1
6/20/2013 11:14,1
6/20/2013 11:15,2
6/20/2013 11:16,2
6/20/2013 11:17,2
6/20/2013 11:18,2
6/20/2013 11:19,2
6/20/2013 11:20,3
6/20/2013 11:21,3
6/20/2013 11:22,3
6/20/2013 11:23,3
6/20/2013 11:24,3
6/20/2013 11:25,4")
df$DeviceTime <- as.POSIXct(df$DeviceTime, format="%m/%d/%Y %H:%M")
cut(df$DeviceTime, breaks="5 min")
[1] 2013-06-20 11:13:00 2013-06-20 11:13:00 2013-06-20 11:13:00
[4] 2013-06-20 11:13:00 2013-06-20 11:13:00 2013-06-20 11:18:00
[7] 2013-06-20 11:18:00 2013-06-20 11:18:00 2013-06-20 11:18:00
[10] 2013-06-20 11:18:00 2013-06-20 11:23:00 2013-06-20 11:23:00
[13] 2013-06-20 11:23:00
means <- aggregate(df["Concentration"],
list(fiveMin=cut(df$DeviceTime, "5 mins")),
mean)
means
fiveMin Concentration
1 2013-06-20 11:13:00 1.600000
2 2013-06-20 11:18:00 2.600000
3 2013-06-20 11:23:00 3.333333
请注意,means
的第一行(11:13:00条目)是df
的前5行的平均值,其时间为11:13至11:17 - - 即直到11:18的下一个切入/断点之前。
如果您使用cut()
,您将获得与dplyr相同的结果(即@ lukeA&#39;答案):
df %>%
group_by(DeviceTime = cut(DeviceTime, breaks="5 min")) %>%
summarize(Concentration = mean(Concentration))
Source: local data frame [3 x 2]
DeviceTime Concentration
1 2013-06-20 11:13:00 1.600000
2 2013-06-20 11:18:00 2.600000
3 2013-06-20 11:23:00 3.333333
xts包似乎打破了挂钟时间:
require(xts)
df.xts <- xts(df$Concentration, df$DeviceTime)
means.xts <- period.apply(df.xts, endpoints(df.xts, "mins", k=5), mean)
means.xts
[,1]
2013-06-20 11:14:00 1
2013-06-20 11:19:00 2
2013-06-20 11:24:00 3
2013-06-20 11:25:00 4
时间值始终是在5分钟窗口中找到的最后一次输入。如果要报告期末结束的时间,可以使用align.time()
将时间索引列向上舍入下一个5分钟的边界:
means.rounded <- align.time(means.xts, 5*60)
means.rounded
[,1]
2013-06-20 11:15:00 1
2013-06-20 11:20:00 2
2013-06-20 11:25:00 3
2013-06-20 11:30:00 4
如果要报告期间开始的时间,也可以向下舍入。但是你需要先定义自己的函数(我在Cross Validated找到):
align.time.down = function(x,n) {
index(x) = index(x) - n
align.time(x,n)
}
means.rounded.down <- align.time.down(means.xts, 5*60)
means.rounded.down
[,1]
2013-06-20 11:10:00 1
2013-06-20 11:15:00 2
2013-06-20 11:20:00 3
2013-06-20 11:25:00 4
另一个不使用xts包的解决方案,而不是floor()
,如下所示:
df$DeviceTimeFloor <- as.POSIXct(floor(as.numeric(df$DeviceTime) / (5 * 60)) * (5 * 60), origin='1970-01-01')
meansFloor <- aggregate(Concentration ~ DeviceTimeFloor, df, mean)
meansFloor
DeviceTimeFloor Concentration
1 2013-06-20 11:10:00 1
2 2013-06-20 11:15:00 2
3 2013-06-20 11:20:00 3
4 2013-06-20 11:25:00 4
我更愿意报告5分钟间隔的开始时间 - floor()
对此有好处。因为,如果我按小时报告聚合,我希望2013-06-20 11:00:00的时间戳包含11:00:00 - 11:59:59而不是10:00:00的数据 - 10:59:59。
如果您希望报告时间间隔的结束时间,则可以使用ceiling()
代替floor()
。但请注意,时间戳11:01 - 11:05将由ceiling()
转换为(并因此分组)在11:05。相反,floor()
将11:00 - 11:04转换为11:00。
所以他们每组都有一组不同的观察结果。 xts包会将同一组观察结果分组为floor()
,但它会报告最后一次观察的最后一个时间戳。周期。
答案 1 :(得分:12)
使用dplyr
包并假设您的数据存储在名为df
的数据框中:
require(dplyr)
df %>%
group_by(DeviceTime = cut(DeviceTime, breaks="5 min")) %>%
summarize(Concentration = mean(Concentration))
答案 2 :(得分:1)
我想说的是,最简单,最干净的方法是使用CustomType
和lubridate
软件包。
dplyr
这里唯一的问题是,它仅适用于适合一个小时的值,即:1、2、3、4、5、6、10、12、15、20、30、60分钟。但是对于这些来说,它是完美的:-)