使用 dplyr 和 apply family 通过多个条件获取多列的滚动平均值
Getting rolling average of multiple column by multiple condition, with dplyr and apply family
我正在对篮球数据进行分析。这是我的数据集的样子(它的一个真正的例子):
df<-data.frame(gmID = 1:20,
H.Team = c("CLE", "MIA", "LAL", "PHI", "CLE", "DET", "CHI", "DAL", "UTA", "PHO", "POR", "WAS", "ORL", "CHA", "BOS", "CHI", "ATL", "DAL", "CLE", "WAS"),
A.Team = c("WAS", "BOS", "DAL", "DEN", "IND", "HOU", "SAC", "WAS", "DAL", "CLE", "LAL", "OKC", "DEN", "IND", "MIL", "CLE", "HOU", "MIA", "UTA", "DEN"),
H.PTS = c(94, 120, 91, 84, 88, 96, 93, 95, 113, 85, 116, 86, 102, 90, 88, 86, 102, 104, 88, 111),
A.PTS = c(84, 107, 99, 75, 90, 105, 87, 99, 94, 87, 106, 84, 89, 89, 99, 115, 109, 84, 86, 88),
H.AST = c(22, 25, 24, 18, 18, 21, 21, 26, 24, 16, 19, 27, 24, 18, 22, 23, 23, 27, 23, 25),
A.AST = c(26, 24, 22, 19, 22, 28, 14, 22, 20, 19, 21, 18, 22, 19, 26, 34, 22, 18, 19, 16))
df
gmID H.Team A.Team H.PTS A.PTS H.AST A.AST
1 1 CLE WAS 94 84 22 26
2 2 MIA BOS 120 107 25 24
3 3 LAL DAL 91 99 24 22
4 4 PHI DEN 84 75 18 19
5 5 CLE IND 88 90 18 22
6 6 DET HOU 96 105 21 28
7 7 CHI SAC 93 87 21 14
8 8 DAL WAS 95 99 26 22
9 9 UTA DAL 113 94 24 20
10 10 PHO CLE 85 87 16 19
11 11 POR LAL 116 106 19 21
12 12 WAS OKC 86 84 27 18
13 13 ORL DEN 102 89 24 22
14 14 CHA IND 90 89 18 19
15 15 BOS MIL 88 99 22 26
16 16 CHI CLE 86 115 23 34
17 17 ATL HOU 102 109 23 22
18 18 DAL MIA 104 84 27 18
19 19 CLE UTA 88 86 23 19
20 20 WAS DEN 111 88 25 16
为了简化问题,我从原始数据集中选择了 20 行和 2 对游戏统计数据,主队 (H.) 和客队 (A.) 的得分 (PTS) 和助攻 (AST) (我的数据中还有 50 对游戏统计数据)。
请注意,行按日期排序,因此不需要进行排列。
目标是对比赛结果进行预测(如果 H.Team 获胜则为 1,如果 A.Team 获胜则为 0),但是现在的数据形式没有用,因为统计信息比赛结束后报告。
因此,想法是用前n个匹配的滚动平均值替换数据框的每个值。我将在我的工作中设置 n=7
或 n=10
,但现在这并不重要,所以为了简化我将设置 n=3
.
输出应如下所示:
gmID H.Team A.Team H.PTSav A.PTSav H.ASTav A.ASTav
1 1 CLE WAS NA NA NA NA
2 2 MIA BOS NA NA NA NA
3 3 LAL DAL NA NA NA NA
4 4 PHI DEN NA NA NA NA
5 5 CLE IND 94.00000 NA 22.00000 NA
6 6 DET HOU NA NA NA NA
7 7 CHI SAC NA NA NA NA
8 8 DAL WAS 99.00000 84.00000 22.00000 26.00000
9 9 UTA DAL NA 97.00000 NA 24.00000
10 10 PHO CLE NA 91.00000 NA 20.00000
11 11 POR LAL NA 91.00000 NA 24.00000
12 12 WAS OKC 91.50000 NA 24.00000 NA
13 13 ORL DEN NA 75.00000 NA 19.00000
14 14 CHA IND NA 90.00000 NA 22.00000
15 15 BOS MIL 107.00000 NA 24.00000 NA
16 16 CHI CLE 93.00000 89.66667 21.00000 19.66667
17 17 ATL HOU NA 105.00000 NA 28.00000
18 18 DAL MIA 96.00000 120.00000 22.66667 25.00000
19 19 CLE UTA 96.66667 113.00000 23.66667 24.00000
20 20 WAS DEN 89.66667 82.00000 25.00000 20.50000
例如,对于打了 5 场比赛的球队 CLE
,平均 PTS
值如下:
gmID avpts
1 1 NA ---> NA
2 5 94.00000 ---> 94/1
3 10 91.00000 ---> (94+88)/2
4 16 89.66667 ---> (94+88+87)/3
5 19 96.66667 ---> (88+87+115)/3
我使用了dplyr
,特别是zoo::rollaply
函数来获取上面显示的值,代码如下:
library(dplyr)
library(zoo)
sub<- df %>%
filter(H.Team == "CLE" | A.Team == "CLE") %>%
mutate(avpts = lag(rollapply(ifelse(H.Team == "CLE", H.PTS,A.PTS), width=3, FUN=mean, align="right", fill=NA, partial=1))) %>%
select(gmID,avpts)
sub
我这样做只是为了一个团队和一个变量,但我可以很容易地为更多在 mutate()
中指定它的变量做这件事,就像这样:
mutate(avpts = lag(rollapply(ifelse(H.Team == "CLE", H.PTS,A.PTS), width=3, FUN=mean, align="right", fill=NA, partial=1)),
avast = lag(rollapply(ifelse(H.Team == "CLE", H.AST,A.AST), width=3, FUN=mean, align="right", fill=NA, partial=1)))
问题是我应该为其他 50 个变量执行此操作,最重要的是我需要计算所有团队的值,而不仅仅是一个团队。
此外,我获得了一个具有正确值的列,但我不知道如何将它们替换到“正确”的位置。
我(部分)解决问题的想法是将上面的代码包装在一个函数中,然后使用 apply
系列中的另一个函数来获取所有团队的值,而不使用 for 循环。
我写了下面的函数:
avstats<- function(team) {
sub <- df %>%
filter(.data$H.Team == !!team | .data$A.Team == !!team) %>%
mutate(avpts = lag(rollapply(ifelse(H.Team == !!team, .data$H.PTS, .data$A.PTS),3,mean,align="right",fill=NA,partial=1))) %>%
select(.data$gmID, .data$avpts)
}
最后,我使用 lapply()
浏览了这个小数据集中的团队列表。
teams <- c("CLE", "MIA", "LAL", "PHI", "DET", "CHI", "DAL", "UTA", "PHO", "POR", "WAS", "ORL", "CHA", "BOS", "ATL", "DEN", "IND", "HOU", "SAC", "OKC","MIL")
lapply(teams,avstats)
这两个函数似乎一切正常。
但是还有两个主要问题我想得到回答:
如何在不为每个统计信息写一行的情况下获取所有其他变量的值? (即如何获得平均助攻、失误、ECC..)
如何将生成的新平均值“组合”并“放在正确的位置”,使得原始数据结构保持不变?
也许我应该修改我的函数 avstats
添加一些参数并因此使用另一个 apply() 函数,例如 mapply()
,但我真的不知道该怎么做。
你要这个吗? (使用了 library(runner)
中的 mean_run
)。
- 您可以为任意数量的变量自动执行此过程。只需在
mutate(across...
的 .cols
参数中使用他们的名字
- 要更改滚动 window 大小,只需根据选择更改
mean_run
中的 k
。
df %>% pivot_longer(!gmID, names_to = c("H_T", ".value"),
names_pattern = "(.+)\.(.+)") %>%
group_by(Team) %>%
mutate(across(.cols = c(PTS, AST),
~ runner::mean_run(x = ., k = 3, lag = 1),
.names = '{.col}_av')) %>%
pivot_wider(id_cols = gmID,
names_from = H_T,
names_glue = "{H_T}_{.value}",
values_from = -c(gmID, H_T))
# A tibble: 20 x 11
gmID H_Team A_Team H_PTS A_PTS H_AST A_AST H_PTS_av A_PTS_av H_AST_av A_AST_av
<int> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 CLE WAS 94 84 22 26 NA NA NA NA
2 2 MIA BOS 120 107 25 24 NA NA NA NA
3 3 LAL DAL 91 99 24 22 NA NA NA NA
4 4 PHI DEN 84 75 18 19 NA NA NA NA
5 5 CLE IND 88 90 18 22 94 NA 22 NA
6 6 DET HOU 96 105 21 28 NA NA NA NA
7 7 CHI SAC 93 87 21 14 NA NA NA NA
8 8 DAL WAS 95 99 26 22 99 84 22 26
9 9 UTA DAL 113 94 24 20 NA 97 NA 24
10 10 PHO CLE 85 87 16 19 NA 91 NA 20
11 11 POR LAL 116 106 19 21 NA 91 NA 24
12 12 WAS OKC 86 84 27 18 91.5 NA 24 NA
13 13 ORL DEN 102 89 24 22 NA 75 NA 19
14 14 CHA IND 90 89 18 19 NA 90 NA 22
15 15 BOS MIL 88 99 22 26 107 NA 24 NA
16 16 CHI CLE 86 115 23 34 93 89.7 21 19.7
17 17 ATL HOU 102 109 23 22 NA 105 NA 28
18 18 DAL MIA 104 84 27 18 96 120 22.7 25
19 19 CLE UTA 88 86 23 19 96.7 113 23.7 24
20 20 WAS DEN 111 88 25 16 89.7 82 25 20.5
我正在对篮球数据进行分析。这是我的数据集的样子(它的一个真正的例子):
df<-data.frame(gmID = 1:20,
H.Team = c("CLE", "MIA", "LAL", "PHI", "CLE", "DET", "CHI", "DAL", "UTA", "PHO", "POR", "WAS", "ORL", "CHA", "BOS", "CHI", "ATL", "DAL", "CLE", "WAS"),
A.Team = c("WAS", "BOS", "DAL", "DEN", "IND", "HOU", "SAC", "WAS", "DAL", "CLE", "LAL", "OKC", "DEN", "IND", "MIL", "CLE", "HOU", "MIA", "UTA", "DEN"),
H.PTS = c(94, 120, 91, 84, 88, 96, 93, 95, 113, 85, 116, 86, 102, 90, 88, 86, 102, 104, 88, 111),
A.PTS = c(84, 107, 99, 75, 90, 105, 87, 99, 94, 87, 106, 84, 89, 89, 99, 115, 109, 84, 86, 88),
H.AST = c(22, 25, 24, 18, 18, 21, 21, 26, 24, 16, 19, 27, 24, 18, 22, 23, 23, 27, 23, 25),
A.AST = c(26, 24, 22, 19, 22, 28, 14, 22, 20, 19, 21, 18, 22, 19, 26, 34, 22, 18, 19, 16))
df
gmID H.Team A.Team H.PTS A.PTS H.AST A.AST
1 1 CLE WAS 94 84 22 26
2 2 MIA BOS 120 107 25 24
3 3 LAL DAL 91 99 24 22
4 4 PHI DEN 84 75 18 19
5 5 CLE IND 88 90 18 22
6 6 DET HOU 96 105 21 28
7 7 CHI SAC 93 87 21 14
8 8 DAL WAS 95 99 26 22
9 9 UTA DAL 113 94 24 20
10 10 PHO CLE 85 87 16 19
11 11 POR LAL 116 106 19 21
12 12 WAS OKC 86 84 27 18
13 13 ORL DEN 102 89 24 22
14 14 CHA IND 90 89 18 19
15 15 BOS MIL 88 99 22 26
16 16 CHI CLE 86 115 23 34
17 17 ATL HOU 102 109 23 22
18 18 DAL MIA 104 84 27 18
19 19 CLE UTA 88 86 23 19
20 20 WAS DEN 111 88 25 16
为了简化问题,我从原始数据集中选择了 20 行和 2 对游戏统计数据,主队 (H.) 和客队 (A.) 的得分 (PTS) 和助攻 (AST) (我的数据中还有 50 对游戏统计数据)。 请注意,行按日期排序,因此不需要进行排列。
目标是对比赛结果进行预测(如果 H.Team 获胜则为 1,如果 A.Team 获胜则为 0),但是现在的数据形式没有用,因为统计信息比赛结束后报告。
因此,想法是用前n个匹配的滚动平均值替换数据框的每个值。我将在我的工作中设置 n=7
或 n=10
,但现在这并不重要,所以为了简化我将设置 n=3
.
输出应如下所示:
gmID H.Team A.Team H.PTSav A.PTSav H.ASTav A.ASTav
1 1 CLE WAS NA NA NA NA
2 2 MIA BOS NA NA NA NA
3 3 LAL DAL NA NA NA NA
4 4 PHI DEN NA NA NA NA
5 5 CLE IND 94.00000 NA 22.00000 NA
6 6 DET HOU NA NA NA NA
7 7 CHI SAC NA NA NA NA
8 8 DAL WAS 99.00000 84.00000 22.00000 26.00000
9 9 UTA DAL NA 97.00000 NA 24.00000
10 10 PHO CLE NA 91.00000 NA 20.00000
11 11 POR LAL NA 91.00000 NA 24.00000
12 12 WAS OKC 91.50000 NA 24.00000 NA
13 13 ORL DEN NA 75.00000 NA 19.00000
14 14 CHA IND NA 90.00000 NA 22.00000
15 15 BOS MIL 107.00000 NA 24.00000 NA
16 16 CHI CLE 93.00000 89.66667 21.00000 19.66667
17 17 ATL HOU NA 105.00000 NA 28.00000
18 18 DAL MIA 96.00000 120.00000 22.66667 25.00000
19 19 CLE UTA 96.66667 113.00000 23.66667 24.00000
20 20 WAS DEN 89.66667 82.00000 25.00000 20.50000
例如,对于打了 5 场比赛的球队 CLE
,平均 PTS
值如下:
gmID avpts
1 1 NA ---> NA
2 5 94.00000 ---> 94/1
3 10 91.00000 ---> (94+88)/2
4 16 89.66667 ---> (94+88+87)/3
5 19 96.66667 ---> (88+87+115)/3
我使用了dplyr
,特别是zoo::rollaply
函数来获取上面显示的值,代码如下:
library(dplyr)
library(zoo)
sub<- df %>%
filter(H.Team == "CLE" | A.Team == "CLE") %>%
mutate(avpts = lag(rollapply(ifelse(H.Team == "CLE", H.PTS,A.PTS), width=3, FUN=mean, align="right", fill=NA, partial=1))) %>%
select(gmID,avpts)
sub
我这样做只是为了一个团队和一个变量,但我可以很容易地为更多在 mutate()
中指定它的变量做这件事,就像这样:
mutate(avpts = lag(rollapply(ifelse(H.Team == "CLE", H.PTS,A.PTS), width=3, FUN=mean, align="right", fill=NA, partial=1)),
avast = lag(rollapply(ifelse(H.Team == "CLE", H.AST,A.AST), width=3, FUN=mean, align="right", fill=NA, partial=1)))
问题是我应该为其他 50 个变量执行此操作,最重要的是我需要计算所有团队的值,而不仅仅是一个团队。 此外,我获得了一个具有正确值的列,但我不知道如何将它们替换到“正确”的位置。
我(部分)解决问题的想法是将上面的代码包装在一个函数中,然后使用 apply
系列中的另一个函数来获取所有团队的值,而不使用 for 循环。
我写了下面的函数:
avstats<- function(team) {
sub <- df %>%
filter(.data$H.Team == !!team | .data$A.Team == !!team) %>%
mutate(avpts = lag(rollapply(ifelse(H.Team == !!team, .data$H.PTS, .data$A.PTS),3,mean,align="right",fill=NA,partial=1))) %>%
select(.data$gmID, .data$avpts)
}
最后,我使用 lapply()
浏览了这个小数据集中的团队列表。
teams <- c("CLE", "MIA", "LAL", "PHI", "DET", "CHI", "DAL", "UTA", "PHO", "POR", "WAS", "ORL", "CHA", "BOS", "ATL", "DEN", "IND", "HOU", "SAC", "OKC","MIL")
lapply(teams,avstats)
这两个函数似乎一切正常。
但是还有两个主要问题我想得到回答:
如何在不为每个统计信息写一行的情况下获取所有其他变量的值? (即如何获得平均助攻、失误、ECC..)
如何将生成的新平均值“组合”并“放在正确的位置”,使得原始数据结构保持不变?
也许我应该修改我的函数 avstats
添加一些参数并因此使用另一个 apply() 函数,例如 mapply()
,但我真的不知道该怎么做。
你要这个吗? (使用了 library(runner)
中的 mean_run
)。
- 您可以为任意数量的变量自动执行此过程。只需在
mutate(across...
的 - 要更改滚动 window 大小,只需根据选择更改
mean_run
中的k
。
.cols
参数中使用他们的名字
df %>% pivot_longer(!gmID, names_to = c("H_T", ".value"),
names_pattern = "(.+)\.(.+)") %>%
group_by(Team) %>%
mutate(across(.cols = c(PTS, AST),
~ runner::mean_run(x = ., k = 3, lag = 1),
.names = '{.col}_av')) %>%
pivot_wider(id_cols = gmID,
names_from = H_T,
names_glue = "{H_T}_{.value}",
values_from = -c(gmID, H_T))
# A tibble: 20 x 11
gmID H_Team A_Team H_PTS A_PTS H_AST A_AST H_PTS_av A_PTS_av H_AST_av A_AST_av
<int> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 CLE WAS 94 84 22 26 NA NA NA NA
2 2 MIA BOS 120 107 25 24 NA NA NA NA
3 3 LAL DAL 91 99 24 22 NA NA NA NA
4 4 PHI DEN 84 75 18 19 NA NA NA NA
5 5 CLE IND 88 90 18 22 94 NA 22 NA
6 6 DET HOU 96 105 21 28 NA NA NA NA
7 7 CHI SAC 93 87 21 14 NA NA NA NA
8 8 DAL WAS 95 99 26 22 99 84 22 26
9 9 UTA DAL 113 94 24 20 NA 97 NA 24
10 10 PHO CLE 85 87 16 19 NA 91 NA 20
11 11 POR LAL 116 106 19 21 NA 91 NA 24
12 12 WAS OKC 86 84 27 18 91.5 NA 24 NA
13 13 ORL DEN 102 89 24 22 NA 75 NA 19
14 14 CHA IND 90 89 18 19 NA 90 NA 22
15 15 BOS MIL 88 99 22 26 107 NA 24 NA
16 16 CHI CLE 86 115 23 34 93 89.7 21 19.7
17 17 ATL HOU 102 109 23 22 NA 105 NA 28
18 18 DAL MIA 104 84 27 18 96 120 22.7 25
19 19 CLE UTA 88 86 23 19 96.7 113 23.7 24
20 20 WAS DEN 111 88 25 16 89.7 82 25 20.5