最终获胜者是…

图片来自 Shutterstock
许多人(包括我)称足球为“不可预测的比赛”,因为一场足球比赛有不同的因素可以改变最终比分。
这是真的……在某种程度上。
很难预测最终比分或比赛的获胜者,但在预测比赛的获胜者时却并非如此。在过去的5年里,拜仁慕尼黑赢得了所有的德甲冠军,而曼城则赢得了4次英超联赛冠军。
巧合?我不这么认为。
事实上,在 20-21 赛季中期,我创建了一个预测英超、西甲、意甲和德甲联赛冠军的模型,它成功地预测了所有联赛的冠军。
这个预测并不难做出,因为那时已经进行了 19 场比赛。现在我正在运行相同的模型来预测 2022 年世界杯。
以下是我如何使用 Python 预测世界杯
我们将如何预测比赛?
有不同的预测方法。我可以构建一个奇特的机器学习模型并为其提供多个变量,但在阅读了一些论文后,我决定给泊松分布一个机会。
为什么?好吧,让我们看一下泊松分布的定义。
泊松分布是一种离散概率分布,描述了在固定时间间隔或机会区域内发生的事件数量。
如果我们将进球看作是一场足球比赛 90 分钟内可能发生的事件,那么我们可以计算 A 队和 B 队在一场比赛中进球数的概率。
但这还不够。我们仍然需要满足泊松分布的假设。
- 可以计算事件的数量(一场比赛可以有 1、2、3 或更多的目标)
- 事件的发生是独立的(一个进球的发生应该不会影响另一个进球的概率)
- 事件发生的速率是恒定的(在某个时间间隔内进球的概率对于其他相同长度的时间间隔应该完全相同)
- 两个事件不能同时发生(两个目标不能同时发生)
毫无疑问,假设 1 和 4 得到满足,但假设 2 和 3 部分成立。也就是说,让我们假设假设 2 和 3 始终为真。
当我预测欧洲顶级联赛的获胜者时,我绘制了前 4 大联赛过去 5 年每场比赛进球数的直方图。

4个联赛进球数直方图
如果你看一下任何联赛的拟合曲线,它看起来就像泊松分布。
现在我们可以说,可以使用泊松分布来计算一场比赛中进球数的概率。
这是泊松分布的公式。

为了做出我考虑的预测:
lambda : 90 分钟内进球的中位数(A 队和 B 队) x : A 队和 B 队在一场比赛中可以进球的数量
要计算 lambda,我们需要每个国家队的平均进球数/失球数。这将我们带到下一点。
每个国家队的进球数/失球数
在收集了 1930 年到 2018 年所有世界杯比赛的数据后,我可以计算出每个国家队的平均进球数和失球数。

在我对欧洲前 4 联赛的预测中,我考虑了主客场因素,但由于在世界杯上几乎所有球队都在中立场地比赛,因此我在分析时没有考虑这个因素。
一旦我获得了每支国家队的进球数/失球数,我就创建了一个函数来预测每支球队在小组赛阶段将获得的积分数。
预测小组赛阶段
下面是我用来预测每个国家队在小组赛阶段将获得多少分的代码。它看起来很吓人,但它只有我提到的很多东西,直到这一点被翻译成代码。
def predict_points(home, away):
if home in df_team_strength.index and away in df_team_strength.index:
lamb_home = df_team_strength.at[home,'GoalsScored'] * df_team_strength.at[away,'GoalsConceded']
lamb_away = df_team_strength.at[away,'GoalsScored'] * df_team_strength.at[home,'GoalsConceded']
prob_home, prob_away, prob_draw = 0, 0, 0
for x in range(0,11): #number of goals home team
for y in range(0, 11): #number of goals away team
p = poisson.pmf(x, lamb_home) * poisson.pmf(y, lamb_away)
if x == y:
prob_draw += p
elif x > y:
prob_home += p
else:
prob_away += p
points_home = 3 * prob_home + prob_draw
points_away = 3 * prob_away + prob_draw
return (points_home, points_away)
else:
return (0, 0)
用简单的英语, predict_points 计算主队和客队将获得多少分。为此,我使用公式 计算了每个团队的 lambda average_goals_scored * average_goals_conceded 。
然后我模拟了一场比赛的所有可能比分,从 0-0 到 10-10(最后一个比分只是我目标范围的极限)。一旦我有了 lambda 和 x,我就使用泊松分布的公式来计算 p 。
如果比赛分别以 1–0(主场获胜)、1–1(平局)或 0–1(客场获胜)结束,则 prob_home 、 prob_draw 和 prob_away 将累积其值。 p 最后,使用以下公式计算分数。
points_home = 3 * prob_home + prob_draw
points_away = 3 * prob_away + prob_draw
如果我们 predict_points 用来预测英格兰对美国的比赛,我们会得到这个。
>>> predict_points('England', 'United States')
(2.2356147635326007, 0.5922397535606193)
这意味着英格兰将获得 2.23 分,而美国将获得 0.59 分。我得到小数是因为我使用的是概率。
如果我们将此 predict_points 函数应用于小组赛阶段的所有比赛,我们将获得每个小组的第 1 和第 2 名,因此将在淘汰赛中进行以下比赛。

作者使用 Canva 编辑的图像
预测淘汰赛
对于淘汰赛,我不需要预测积分,而是预测每组的胜者。这就是为什么我在 get_winner 以前的功能的基础上创建了一个新 predict_points 功能。
def get_winner(df_fixture_updated):
for index, row in df_fixture_updated.iterrows():
home, away = row['home'], row['away']
points_home, points_away = predict_points(home, away)
if points_home > points_away:
winner = home
else:
winner = away
df_fixture_updated.loc[index, 'winner'] = winner
return df_fixture_updated
简单来说,如果 points_home 大于 points_away 则为主队,否则为客队。
多亏了这个 get_winner 函数,我可以得到前面括号的结果。

作者使用 Canva 编辑的图像
预测四分之一决赛、半决赛和决赛
如果我 get_winner 再次使用我可以预测世界杯的获胜者。这是最终结果!

作者使用 Canva 编辑的图像
通过再次运行该函数,我猜赢家是……
巴西!
这就是我使用 Python 和泊松分布预测 2022 年世界杯的方式。
#2022世界杯#