具有条件的累积平均值

时间:2016-02-16 21:11:03

标签: r

这是来自Cumulative Mean with Grouping and LagGrouped moving average in r的后续问题。

我希望创建一个滞后为1的累积平均字段,该字段对多个变量进行分组,但仅计算某些条件的平均值。因此,对于下面的示例,S-AVG仅给出S的累积平均值,反之亦然O-AVG和J-AVG。我确信这可以使用ave和cumsum,但我不确定该怎么做。

这是所需的输出:

Player  Goals   **S-AVG**    **O-AVG**    **J-AVG**
S       5                         
S       2       5
S       7       3.5         
O       3                    
O       9                     3
O       6                     6      
O       3                     3 
S       7       4.66         
O       1                     5.25
S       7       5.25         
S       3       5.6         
Q       8                     4.4            
S       3       5.16                  
O       4                     5           
P       1                     4.857
S       9       4.857         
S       4       5.375         
Z       6                     4.375        
S       3       5.22         
O       8                     4.55            
S       3       5                  
O       4                     4.9      
O       1                     4.81      
S       9       4.81                  
S       4       5.16                  
O       6                     4.5       
J       6                     

这是r

的数据输入
Player <- c('S','S','S','O','O','O','O','S','O','S','S','O','S','O','O','S','S','O','S','O','S','O','O','S','S','O','J')
Goals <- c(5,2,7,3,9,6,3,7,1,7,3,8,3,4,1,9,4,6,3,8,3,4,1,9,4,6,6)
data.frame(Player, Goals)

感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

假设DF2是在my answer中计算到问题中引用的prior post的数据帧,即具有AVG列的数据帧。它也在本答案末尾的注释中复制。

如果我们只有一个或一个固定数量的玩家,我们可以通过为每个玩家写一个AVG.*列(为一个玩家显示)来做到这一点:

transform(DF2, AVG.S = ifelse(Player == "S", AVG, NA))

但接下来是一种更通用的方法。将levs设置为Player因素的级别,或者如果您不想要所有玩家,那么levs应该设置为您想要的玩家的角色向量。然后使用sapply构造逻辑矩阵并将其转换为1s和NA的矩阵,然后将其标量乘以AVG

该解决方案具有许多令人满意的功能 - 它不会覆盖其输入(这会容易出错)并且它避免了不必要的重复限定(这要归功于transform),它使用整个对象方法而不是比循环和下标,它利用现有代码避免重复(通过使用先前解决方案的结果,这个问题是后续的)并且简短 - 两行代码。它不使用任何包。

(另请注意,替代sapply(...)可以替换为model.matrix(~ Player + 0),在这种情况下,列名称会略有不同。)

levs <- levels(DF2$Player)
transform(DF2, Avg = ifelse(sapply(levs, `==`, Player), 1, NA) * AVG)

,并提供:

   Player Goals      AVG Avg.J    Avg.O    Avg.S
1       S     5       NA    NA       NA       NA
2       S     2 5.000000    NA       NA 5.000000
3       S     7 3.500000    NA       NA 3.500000
4       O     3       NA    NA       NA       NA
5       O     9 3.000000    NA 3.000000       NA
6       O     6 6.000000    NA 6.000000       NA
7       O     3 6.000000    NA 6.000000       NA
8       S     7 4.666667    NA       NA 4.666667
9       O     1 5.250000    NA 5.250000       NA
10      S     7 5.250000    NA       NA 5.250000
11      S     3 5.600000    NA       NA 5.600000
12      O     8 4.400000    NA 4.400000       NA
13      S     3 5.166667    NA       NA 5.166667
14      O     4 5.000000    NA 5.000000       NA
15      O     1 4.857143    NA 4.857143       NA
16      S     9 4.857143    NA       NA 4.857143
17      S     4 5.375000    NA       NA 5.375000
18      O     6 4.375000    NA 4.375000       NA
19      S     3 5.222222    NA       NA 5.222222
20      O     8 4.555556    NA 4.555556       NA
21      S     3 5.000000    NA       NA 5.000000
22      O     4 4.900000    NA 4.900000       NA
23      O     1 4.818182    NA 4.818182       NA
24      S     9 4.818182    NA       NA 4.818182
25      S     4 5.166667    NA       NA 5.166667
26      O     6 4.500000    NA 4.500000       NA
27      J     6       NA    NA       NA       NA

注意:以上用作输入:

DF2 <- structure(list(Player = structure(c(3L, 3L, 3L, 2L, 2L, 2L, 2L, 
3L, 2L, 3L, 3L, 2L, 3L, 2L, 2L, 3L, 3L, 2L, 3L, 2L, 3L, 2L, 2L, 
3L, 3L, 2L, 1L), .Label = c("J", "O", "S"), class = "factor"), 
    Goals = c(5, 2, 7, 3, 9, 6, 3, 7, 1, 7, 3, 8, 3, 4, 1, 9, 
    4, 6, 3, 8, 3, 4, 1, 9, 4, 6, 6), AVG = c(NA, 5, 3.5, NA, 
    3, 6, 6, 4.66666666666667, 5.25, 5.25, 5.6, 4.4, 5.16666666666667, 
    5, 4.85714285714286, 4.85714285714286, 5.375, 4.375, 5.22222222222222, 
    4.55555555555556, 5, 4.9, 4.81818181818182, 4.81818181818182, 
    5.16666666666667, 4.5, NA)), .Names = c("Player", "Goals", 
"AVG"), row.names = c(NA, -27L), class = "data.frame")

答案 1 :(得分:1)

另一种方法是简单地使用索引。首先创建一个函数cummean(这是微不足道的......):

cummean <- function(x){
  cumsum(x) / seq_along(x)
}

然后计算累积均值并存储在列表中(simplify = FALSE):

avgs <- with(mydf,
             tapply(Goals,Player,cummean,
                    simplify = FALSE))

最后,根据玩家名称创建变量,方便地添加为tapply返回的列表的名称。我特意使用for循环来避免每次都重建完整的数据帧。使用索引,我可以以更有效的方式填充数据框,并且仍然具有您想要的滞后。 :

for(i in names(avgs)){
  theavg <- avgs[[i]]
  mydf[[i]][mydf$Player == i] <- c(NA, theavg[-length(theavg)])
}
相关问题