event/game之前的累计积分计算

Calculation of the cumulative points before the event/game

我想把几个足球俱乐部在一个比赛日的积分累加起来。

我创建了一个样本数据集来解释这个问题:

t <- data.frame(Heim = c("A", "B", "B", "D", "C", "A", "C", "D", "A", "B", "B", "D", "C", "A", "C", "D"), 
                Auswärts = c("C", "D", "A", "C", "B", "D", "A", "B", "C", "D", "A", "C", "B", "D", "A", "B"),
                Ergebnis= c("S", "U", "N", "N", "S", "S", "N", "U", "N", "S", "N", "U", "S", "S", "U", "U"),
                Round = c(1,1,2,2,3,3,4,4,1,1,2,2,3,3,4,4),
                Saison = c(1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2))

我的想法是为每个俱乐部(在原始数据集中超过 4 个)一个单独的列,其中包含分数和一个累积的列。

所以像这样:

t$A_Points <- ifelse(t$Heim =="A" & t$Ergebnis =="S", 3, 0)
t$A_Points  <- ifelse(t$Heim =="A" & t$Ergebnis =="U", 1, t$A_Points )
t$A_Points  <- ifelse(t$Auswärts =="A" & t$Ergebnis =="U", 1, t$A_Points )
t$A_Points  <- ifelse(t$Auswärts =="A" & t$Ergebnis =="N", 3, t$A_Points )
t$A_Points  <- ifelse(t$Auswärts !="A" & t$Heim !="A", NA, t$A_Points)
t$A<- ifelse(t$A_Points  == "NA", 0, 1)

t<- t %>% 
  arrange(Saison,Round,A) %>%
  group_by(Saison, A) %>%
  mutate(cumsum = cumsum(A_Points))

不幸的是,这非常耗时 space- 即使是 4 个俱乐部... 另外,我想得到没有当前比赛日结果的比赛总分。

对我来说最佳结果如下:


Heim  Auswärts Ergebnis Round Saison    Points_Heim Points_Auswärts 
   <chr> <chr>    <chr>    <dbl>  <dbl>    <dbl>      <dbl>
 1 A     C        S            1      1        0       0
 2 B     D        U            1      1        0       0
 3 B     A        N            2      1        1       3
 4 D     C        N            2      1        1       0
 5 A     D        S            3      1        6       1          
 6 C     B        S            3      1        3       1
 7 C     A        N            4      1        6       9
 8 D     B        U            4      1        1       1
 9 A     C        N            1      2        0       0
10 B     D        S            1      2        0       0
11 B     A        N            2      2        3       0
12 D     C        U            2      2        0       3
13 A     D        S            3      2        3       1
14 C     B        S            3      2        4       3
15 C     A        U            4      2        7       3    
16 D     B        U            4      2        1       3    

如果有更简单的解决方案,我会非常高兴。

可能不是最短的解决方案。但我愿意

t <- t %>% 
  group_by(Saison) %>%
  mutate(Heim_Points_Veränderung = case_when(Ergebnis == "S" ~ 3,
                                             Ergebnis == "U" ~ 1,
                                             Ergebnis == "N" ~ 0),
         Auswärts_Points_Veränderung = case_when(Ergebnis == "S" ~ 0,
                                                 Ergebnis == "U" ~ 1,
                                                 Ergebnis == "N" ~ 3),
         Points_Heim = 0,
         Points_Auswärts = 0)

for (i in unique(union(t$Heim, t$Auswärts))){
  t <- t %>% 
    mutate(!!sym(paste0(i,"_points")) := if_else(Heim == i, Heim_Points_Veränderung, 0),
           !!sym(paste0(i,"_points")) := if_else(Auswärts == i, Auswärts_Points_Veränderung, !!sym(paste0(i,"_points"))),
           !!sym(paste0(i,"_cumsum")) := cumsum(lag(!!sym(paste0(i,"_points")), default=0)),
           Points_Heim = if_else(Heim == i, !!sym(paste0(i,"_cumsum")), Points_Heim),
           Points_Auswärts = if_else(Auswärts == i, !!sym(paste0(i,"_cumsum")), Points_Auswärts))
}

t <- t %>%
  select(Heim, Auswärts, Ergebnis, Round, Saison, Points_Heim, Points_Auswärts)

输出

> t
# A tibble: 16 x 7
# Groups:   Saison [2]
   Heim  Auswärts Ergebnis Round Saison Points_Heim Points_Auswärts
   <chr> <chr>    <chr>    <dbl>  <dbl>       <dbl>           <dbl>
 1 A     C        S            1      1           0               0
 2 B     D        U            1      1           0               0
 3 B     A        N            2      1           1               3
 4 D     C        N            2      1           1               0
 5 C     B        S            3      1           3               1
 6 A     D        S            3      1           6               1
 7 C     A        N            4      1           6               9
 8 D     B        U            4      1           1               1
 9 A     C        N            1      2           0               0
10 B     D        S            1      2           0               0
11 B     A        N            2      2           3               0
12 D     C        U            2      2           0               3
13 C     B        S            3      2           4               3
14 A     D        S            3      2           3               1
15 C     A        U            4      2           7               6
16 D     B        U            4      2           1               3

此解决方案应适用于任何数量的俱乐部。简而言之,我使用 case_when(比很多 ifelse 更容易)将可能的点变化存储在 Heim/Auswärts_Points_Veränderung 中,因此我可以创建一列点变化每个俱乐部(运行 所有俱乐部的 for 循环)。这允许我像你一样使用 lag 来执行 cumsum 以确保 cumsum 在 1 行之后更新(以显示比赛前而不是比赛后的累积分数),我在 Points_Heim/Auswärts 列仅当俱乐部显示在 Heim/Auswärts 列中时。我的解决方案的关键是在 for 循环中使用 !!sym 将动态变量名称提供给 mutate(注意使用 := 的赋值)。