有条件的累积平均值

  • 本文关键字:平均值 有条件 r
  • 更新时间 :
  • 英文 :


这是 r 中具有分组和滞后的累积平均值和分组移动平均线的后续问题。

我希望创建一个累积均值字段,其滞后为一个,该字段对多个变量进行分组,但仅根据某些标准计算平均值。因此,对于下面的示例,S-AVG 仅给出 S 的累积平均值,反之亦然。我确信使用 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)

任何帮助,不胜感激。

假设DF2是我在回答问题中引用的上一篇文章时计算的数据框,即具有AVG列的数据框。本答复末尾的说明中也转载了这一内容。

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

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

但更普遍的方法如下。 将levs设置为Player因子的水平,或者如果您不需要所有玩家,则应将levs设置为仅包含所需玩家的角色向量。 然后使用 sapply 构建一个逻辑矩阵并将其转换为 1 和 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")

另一种方法是简单地使用索引。首先创建一个函数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)])
}

最新更新