在R语言中为足球比赛数据框批量生成胜负平泊松概率列
问题描述
我有一个记录足球比赛及对应球队平均进球率的数据框df,前两列为主队、客队,第三、四列分别是主队、客队的平均进球率,示例如下:
Home Away HomeRate AwayRate 1 Arsenal Bristol 1.3 1.3 2 Chelsea Newcastle 2.4 2.3 3 Liverpool Leeds 3.3 1.7 4 Bolton Fulham 2.1 2.5
我希望生成三个新列HomeWin、Draw、AwayWin,分别给出每场比赛主队获胜、平局、客队获胜的泊松概率,并添加到数据框中,假设事件相互独立。
我可以手动逐个处理单场比赛,但不知道如何对整个表格批量处理。以第二行(切尔西vs纽卡斯尔)为例,手动处理代码如下:
# 生成主队进球概率(含20+球的概率) H <- c(dpois(0:20, df[2,3]), ppois(20, df[2,3], lower.tail=FALSE)) # 生成客队进球概率(含20+球的概率) A <- c(dpois(0:20, df[2,4]), ppois(20, df[2,3], lower.tail=FALSE)) # 生成比分概率矩阵 ProbMatrix = outer(H, A) # 计算胜负平概率 Prob_Home_Win = sum(ProbMatrix[lower.tri(ProbMatrix)]) Prob_Away_Win = sum(ProbMatrix[upper.tri(ProbMatrix)]) Prob_Draw = sum(diag(ProbMatrix))
但如何高效地为数据框df中的所有比赛生成完整的HomeWin、AwayWin和Draw列?
解决方案
方法1:基础R apply 批量处理
把单场比赛的计算逻辑封装成函数,通过apply对数据框逐行调用,实现批量计算:
# 定义计算单场胜负平概率的函数 calc_poisson_probs <- function(row) { home_rate <- row["HomeRate"] away_rate <- row["AwayRate"] # 生成主队进球概率向量(0-20球 + 20+球的概率) H <- c(dpois(0:20, home_rate), ppois(20, home_rate, lower.tail = FALSE)) # 生成客队进球概率向量(修正手动代码中的参数错误,用客队进球率) A <- c(dpois(0:20, away_rate), ppois(20, away_rate, lower.tail = FALSE)) # 构建比分概率矩阵 prob_matrix <- outer(H, A) # 计算三种结果的概率 home_win <- sum(prob_matrix[lower.tri(prob_matrix)]) away_win <- sum(prob_matrix[upper.tri(prob_matrix)]) draw <- sum(diag(prob_matrix)) # 返回命名结果向量 return(c(HomeWin = home_win, Draw = draw, AwayWin = away_win)) } # 对数据框的进球率列逐行应用函数,合并结果到原数据框 prob_results <- t(apply(df[, c("HomeRate", "AwayRate")], 1, calc_poisson_probs)) df <- cbind(df, prob_results)
方法2:tidyverse 逐行处理(更易读)
如果使用dplyr,可以通过rowwise()实现逐行计算,逻辑更直观:
library(dplyr) df <- df %>% rowwise() %>% mutate( # 生成主队/客队进球概率列表(保留为向量) H = list(c(dpois(0:20, HomeRate), ppois(20, HomeRate, lower.tail = FALSE))), A = list(c(dpois(0:20, AwayRate), ppois(20, AwayRate, lower.tail = FALSE))), # 计算各结果概率 HomeWin = sum(outer(H, A)[lower.tri(outer(H, A))]), AwayWin = sum(outer(H, A)[upper.tri(outer(H, A))]), Draw = sum(diag(outer(H, A))) ) %>% # 移除中间临时列 select(-H, -A) %>% ungroup()
关键修正与说明
- 修正了手动代码中的错误:计算客队20+球概率时,应使用客队的平均进球率
AwayRate,而非主队的HomeRate,避免概率计算偏差。 - 以20球作为进球上限,既能保证概率总和接近1,又不会因计算量过大影响效率。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

