在R中构建分类变量的移动平均数

3
我想构建一个移动平均,同时对两个分类变量的时间序列数据集进行聚合。尽管我看过一些其他教程,但它们似乎都没有涉及到我想要实现的特定任务。
我的原始数据集(df)每行代表一个个体(id),日期范围为0-180天(Days)。个体可以是两个数据子集中的一个成员(Group)。
然后,我将聚合这个数据框以获得两个组的日均值。
library(plyr)
summary <- ddply(df, .(Group,Days), summarise,
                      DV = mean(variable), resp=length(unique(Id)))

下一步是在这两组数据中构建一个移动平均值。在下面的示例数据框中,我只是使用前5天构建了一个5天的平均值。
Group       Days  DV    5DayMA
exceeded    0   2859    
exceeded    1   2948    
exceeded    2   4412    
exceeded    3   5074    
exceeded    4   5098    4078
exceeded    5   5147    4536
exceeded    6   4459    4838
exceeded    7   4730    4902
exceeded    8   4643    4815
exceeded    9   4698    4735
exceeded    10  4818    4670
exceeded    11  4521    4682
othergroup  0   2859    
othergroup  1   2948    
othergroup  2   4412    
othergroup  3   5074    
othergroup  4   5098    4078
othergroup  5   5147    4536
othergroup  6   4459    4838
othergroup  7   4730    4902
othergroup  8   4643    4815
othergroup  9   4698    4735
othergroup  10  4818    4670
othergroup  11  4521    4682

有关如何完成此操作的任何想法?
2个回答

9
您可以尝试使用zoo::rollmean函数。
df <- structure(list(Group = c("exceeded", "exceeded", "exceeded", 
"exceeded", "exceeded", "exceeded", "exceeded", "exceeded", "exceeded", 
"exceeded", "exceeded", "exceeded", "othergroup", "othergroup", 
"othergroup", "othergroup", "othergroup", "othergroup", "othergroup", 
"othergroup", "othergroup", "othergroup", "othergroup", "othergroup"
), Days = c(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 
0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L), DV = c(2859L, 
2948L, 4412L, 5074L, 5098L, 5147L, 4459L, 4730L, 4643L, 4698L, 
4818L, 4521L, 2859L, 2948L, 4412L, 5074L, 5098L, 5147L, 4459L, 
4730L, 4643L, 4698L, 4818L, 4521L), X5DayMA = c(NA, NA, NA, NA, 
4078L, 4536L, 4838L, 4902L, 4815L, 4735L, 4670L, 4682L, NA, NA, 
NA, NA, 4078L, 4536L, 4838L, 4902L, 4815L, 4735L, 4670L, 4682L
)), .Names = c("Group", "Days", "DV", "X5DayMA"), class = "data.frame", row.names = c(NA, 
-24L))

head(df)
     Group Days   DV X5DayMA
1 exceeded    0 2859      NA
2 exceeded    1 2948      NA
3 exceeded    2 4412      NA
4 exceeded    3 5074      NA
5 exceeded    4 5098    4078
6 exceeded    5 5147    4536

library(plyr)
library(zoo)
ddply(
  df, "Group",
  transform,
  5daymean = rollmean(DV, 5, align="right", na.pad=TRUE ))

        Group Days   DV X5DayMA 5daymean
1    exceeded    0 2859      NA       NA
2    exceeded    1 2948      NA       NA
3    exceeded    2 4412      NA       NA
4    exceeded    3 5074      NA       NA
5    exceeded    4 5098    4078   4078.2
6    exceeded    5 5147    4536   4535.8
7    exceeded    6 4459    4838   4838.0
8    exceeded    7 4730    4902   4901.6
9    exceeded    8 4643    4815   4815.4
10   exceeded    9 4698    4735   4735.4
11   exceeded   10 4818    4670   4669.6
12   exceeded   11 4521    4682   4682.0
13 othergroup    0 2859      NA       NA
14 othergroup    1 2948      NA       NA
15 othergroup    2 4412      NA       NA
16 othergroup    3 5074      NA       NA
17 othergroup    4 5098    4078   4078.2
18 othergroup    5 5147    4536   4535.8
19 othergroup    6 4459    4838   4838.0
20 othergroup    7 4730    4902   4901.6
21 othergroup    8 4643    4815   4815.4
22 othergroup    9 4698    4735   4735.4
23 othergroup   10 4818    4670   4669.6
24 othergroup   11 4521    4682   4682.0

使用dplyr可以更快地进行操作。

library(dplyr)
df %.%
  dplyr:::group_by(Group) %.%
  dplyr:::mutate('5daymean' = rollmean(DV, 5, align="right", na.pad=TRUE ))

或者超快的data.table

library(data.table)
dft <- data.table(df)
dft[ , `:=` ('5daymean' = rollmean(DV, 5, align="right", na.pad=TRUE )) , by=Group ]

1
或者使用ave和zoo的rollmeanr的以下变体:transform(DF, MA = ave(DV, Group, FUN = function(x) rollmeanr(x, 5, na.pad = TRUE))) - G. Grothendieck
@G.Grothendieck 这条评论很有价值,对我来说提供了新的信息。您认为这样会更快吗? - Paulo E. Cardoso
1
在讨论速度时,值得注意的是,即使在具有1000个组和1e7行的未经优化的ave解决方案上,也只需要在一台适度的机器上花费约1.4秒。如果只进行一次计算,则使用更快的软件包可能会产生相对巨大的差异,但绝对差异很小。 - thelatemail
不一定。你需要尝试一下。在RcppRoll包中使用的roll_mean替代rolmeanr是用C++编写的,可能具有一些速度优势。 - G. Grothendieck
1
在RcppRoll中,roll_mean()绝对比zoo的rollmean()更快(参见这里),但它似乎缺乏处理缺失值的能力(没有na.pad选项),所以我不知道你如何在dplyr或本答案中的其他方法中使用它... - Andrew
谢谢大家。这很有趣。除了nrows之外,将更多因素纳入分组可能会导致速度差异。我想。但这可能只适用于非常大的数据集。 - Paulo E. Cardoso

3

ave and filter:

with(df, ave(DV, Group, FUN=function(x) filter(x,rep(1/5,5),sides=1)))
# [1]     NA     NA     NA     NA 4078.2 4535.8 4838.0 4901.6 4815.4 4735.4
#[11] 4669.6 4682.0     NA     NA     NA     NA 4078.2 4535.8 4838.0 4901.6
#[21] 4815.4 4735.4 4669.6 4682.0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接