用统计建模预测足球比赛成绩

2020-10-21 00:31:06

结合世界上最受欢迎的运动和每个人最喜欢的离散概率分布,这篇帖子使用泊松分布预测足球比赛。

足球(对我的美国读者来说是足球)充满了陈词滥调:“这是一场两个半场的比赛”、“一场比赛一场比赛”和“利物浦没能赢得英超联赛”。你不太可能听到“将每支球队的进球数量视为独立的泊松过程,统计模型显示主队今天有60%的机会获胜”。但这实际上也有点陈词滥调(这里、这里已经讨论过了,这里讨论得特别好)。我们会发现,简单的泊松模型过于简单化了。但这是一个很好的起点,也是学习统计建模的一种很好的直观方式。所以,如果你来这里是为了赚钱,我听说这家伙不出家门就能每月挣5000 GB。

该模型是建立在每支球队得分/丢球的数量基础上的。过去得分较高的球队未来进球的可能性更大。我们将导入最近结束的英超(2016/17)赛季的所有比赛结果。这些数据的来源多种多样(kaggle、focket-data.co.uk、gihub、api)。我为该API构建了一个R包装器,但这一次我将采用CSV路线。

将熊猫作为PD导入matplotlib.pylot作为PLT导入Numpy作为NP从scipy.stats导入Poisson,skellam EPL_1617=PD。Read_CSV(";http://www.football-data.co.uk/mmz4281/1617/E0.csv";)EPL_1617=EPL_1617[[';HomeTeam&39;,';AwayTeam';,';FTHG&39;,';FTAG';]EPL_1617=EPL_1617。重命名(Columns={';FTHG';:';HomeGoals';,';FTAG';:';AwayGoals';})EPL_1617。头部()。

我们导入了一个CSV作为熊猫数据帧,其中包含2016-17赛季英超赛季380场英超比赛的各种信息。我们将数据帧限制在我们感兴趣的列中(具体地说,就是球队名称和每支球队的进球数量)。我将省略生成本文中图表的大部分代码。但别担心,您可以在我的GitHub页面上找到该代码。我们的任务是模拟本赛季的最后一轮比赛,所以我们必须删除最后10行(每场比赛周包含10场比赛)。

你会注意到,平均来说,主队比客队进了更多的球。这就是所谓的“主场优势”(这里讨论),并不是足球所特有的。现在是介绍泊松分布的方便时间。它是一个离散的概率分布,描述特定时间段(例如,90分钟)内具有已知平均发生速率的事件数量的概率。一个关键的假设是事件的数量与时间无关。在我们的背景下,这意味着进球的可能性不会因为比赛中已经进了多少球而变得更多/更少。取而代之的是,进球数量纯粹表示为平均进球率的函数。如果这一点不清楚,也许这个数学公式会变得更清楚:

表示平均比率(例如,平均目标数、您收到的平均信件数等)。因此,我们可以将主队和客队的进球数视为两个独立的泊松分布。下面的图表显示了进球与相应泊松分布估计的进球数量相比的比例。

平局的概率简单地说就是两支球队进球相等的项目的总和。

请注意,我们将每支球队的进球数量视为独立事件(即P(A N B)=P(A)P(B))。两个泊松分布之差实际上称为Skellam分布。因此,我们可以通过将平均目标值输入到该分布中来计算平局的概率。

因此,希望您能看到我们如何调整这种方法来为特定的比赛建模。我们只需要知道每支球队的平均进球数量,并将这些数据输入泊松模型。让我们来看看切尔西和桑德兰(分别获得第一名和最后一名的球队)的进球分布情况。

现在您应该确信,每支球队的进球数量可以用泊松分布来近似。由于样本量相对较大(每支球队最多打19场主客场比赛),这个近似值的准确性可能会有很大差异(特别是在本赛季早些时候,球队打的比赛较少)。和以前一样,我们现在可以计算出在这场切尔西桑德兰比赛中发生各种事件的可能性。但是,我们将构建一个更通用的泊松回归模型(那是什么?),而不是分别对待每一场比赛。

#导入Poisson回归模型所需的工具将statsmodel s.api作为sm import statsmodel s.mulma.api作为SMF Goal_Model_Data=pd导入。Concat([EPL_1617[[';HomeTeam';,';AwayTeam';,';HomeGoals';]。指定(HOME=1)。重命名(Columns={';HomeTeam';:';Team';,';AwayTeam';:';对手';,';HomeGoals';:';Goals';}),EPL_1617[[';AwayTeam';,';HomeTeam';,';AwayGoals';]]。指定(HOME=0)。重命名(Columns={';AwayTeam';:';Team';,';HomeTeam';:';Andicator';,';AwayGoals';:';Goals';})])POISSON_MODEL=SMF。GLM(FORMULA=";进球~主场+球队+对手";,DATA=GOAL_MODEL_DATA,FAMILY=sm.。家人。泊松(Poisson))。拟合()泊松模型。摘要()。

如果您对smf.glm(...)。这一部分,你可以在这里找到更多信息(编辑:这篇文章的早期版本错误地使用了一个通用的估计公式(GEE)-有什么不同?)。我更感兴趣的是模型汇总表中coef列中显示的值,它们类似于线性回归中的斜率。与Logistic回归类似,我们取参数值的指数。正值表示更多目标(),而更接近零的值表示更中性的效果()。在桌子底部,你可能会注意到HOME的系数是0.2969。这反映了这样一个事实,即主队通常比客队进更多的球(具体地说,==1.35倍的可能性)。但并不是所有的团队都是生而平等的。切尔西的系数是0.0789,而桑德兰的相应系数是-0.9619(差不多是说切尔西(桑德兰)更好(更糟糕!)。得分高于平均水平)。最后,对手会根据对手的实力来惩罚/奖励球队。这反映了每支球队的防守实力(切尔西:-0.3036;桑德兰:0.3707)。换句话说,你在对阵切尔西的比赛中进球的可能性更小。希望这一切在统计上和直觉上都有意义。

让我们开始为即将到来的比赛做一些预测。我们只需将我们的团队传递到POISSON_MODEL中,它将返回该团队的预期平均进球数(我们需要运行两次-我们分别计算每个团队的预期平均进球数)。所以让我们看看我们预计切尔西和桑德兰会进多少球。

和前面一样,我们有两个泊松分布。由此,我们可以计算出各种事件的概率。我将把它包装在一个Simulation_Match函数中。

Def Simulation_Match(FOOT_MODEL,HomeTeam,awayTeam,max_Goals=10):HOME_Goals_avg=FOOT_MODEL。预测(PD)。DataFrame(data={';team';:HomeTeam,';对方';:awayTeam,';home';:1},index=[1]))。VALUES[0]Away_Goals_avg=FOOT_MODEL。预测(PD)。DataFrame(data={';team';:awayTeam,';对方';:HomeTeam,';home';:0},index=[1]))。VALUES[0]TEAM_PRED=[[泊松。[HOME_Goals_Avg,Away_Goals_Avg]中的Team_Avg的范围(0,max_Goals+1)内i的PMF(i,Team_Avg)RETURN(NP.。外部(NP.。数组(Team_pred[0]),np。Array(team_pred[1])Simulate_Match(泊松_model,';切尔西';,';桑德兰';,max_Goals=3)

Array([[0.03108485,0.01272529,0.00260469,0.00035543],[0.0951713,0.03896054,0.00797469,0.00108821],[0.14569118,0.059642,0.01220791,0.00166586],[0.14868571,0.06086788,0.01245883,0.0017001]])。

这个矩阵简单地显示了切尔西(矩阵的行)和桑德兰(矩阵的列)打进特定数量进球的概率。例如,沿对角线,两队进球数相同(例如P(0-0)=0.031)。因此,您可以通过将所有对角线条目相加来计算抽签的赔率。斜线以下的一切都代表着切尔西的胜利(例如P(3-0)=0.149)。如果您更喜欢高于/低于市场,您可以通过对列号和行号之和(均从零开始)小于3(即形成左上角三角形的6个值)的条目求和来估计P(低于2.5个目标)。幸运的是,我们可以使用基本的矩阵操作函数来执行这些计算。

嗯,我们的模型给桑德兰2.7%的获胜机会。但这是对的吗?为了评估预测的准确性,我们将把我们的模型返回的概率与Betfair交易所提供的赔率进行比较。

与传统的博彩公司不同,在博彩交易所(必发不是唯一的博彩交易所--它只是最大的一家),你与其他人打赌(必发从赢家中提取佣金)。它就像是体育赛事的股票市场。而且,就像股票市场一样,由于有效市场假说,Betfair的可用价格反映了这些事件发生的真实价格/几率(至少在理论上)。下面,我发布了5月21日周日Betfair交易所的截图(比赛开始前几个小时)。

盒子里的数字代表了最好的可用价格和按这些价格可供使用的金额。蓝色方框表示反向押注(即押注某一事件将会发生-用股市术语来说是长期的),而粉红色方框表示平局押注(即押注某事不会发生-即做空)。例如,如果我们将100 GB押注于切尔西获胜,如果他们获胜,我们将获得原始金额加100*1.13=GB 13(当然,如果他们没有获胜,我们将失去我们的GB 100)。现在,我们如何将这些价格与我们的模型返回的概率进行比较呢?小数赔率可以很容易地转换成概率:它只是小数赔率的倒数。例如,切尔西获胜的隐含概率是1/1.13%(=0.885-我们的模型将概率设为0.889)。我关注的是小数赔率,但您可能也熟悉Moneyline(美式)赔率(例如+200)和分数赔率(例如2/1)。小数赔率、货币线和概率之间的关系如下表所示。我将坚持使用小数赔率,因为其他选择要么对我来说不熟悉(Moneyline),要么就是愚蠢的(分数赔率)。

因此,我们有自己的模型概率,并且(如果我们信任交易所)我们知道每个事件发生的真实概率。理想情况下,我们的模型将识别市场低估了事件发生的可能性(或在平局押注的情况下不发生)的情况。例如,在一个简单的掷硬币游戏中,想象一下,如果你猜对了,每赌1美元(加上你的赌注),你会得到2美元的奖励。隐含的概率是0.333,但是任何有效的模型都会返回概率0.5%。下表比较了我们的模型和Betfair交易所返回的赔率。

根据我们的模型,绿色单元格表示进行有利可图的押注的机会(单元格的不透明度由隐含的差异决定)。我已经强调了模型和Betfair在绝对值上的差异(相对差异可能与任何交易策略更相关)。透明单元格表示交易所和我们的模型大体一致的情况。强烈的色彩暗示要么是我们的模型错了,要么是交易所错了。考虑到我们模型的简单性,我倾向于后者。

那么我们应该把房子押在曼联身上吗?可能不会(尽管他们确实赢了!)。有一些非统计原因让人抗拒支持他们。狂热的足球迷会注意到,这些比赛代表着本赛季的最后一场比赛周。大多数球队几乎没有什么可争夺的,这意味着比赛的可预测性较差(特别是当它们涉及的是没有动力的“大”球队时)。雪上加霜的是,曼联将在三天后的欧联杯决赛中对阵阿贾克斯。曼联主帅何塞·穆里尼奥甚至确认他将让一线队休息,把他们留到更重要的决赛中去。以类似的方式,关键球员的受伤/停职,管理层的解雇将使我们的模型不准确。永远不要低估领域知识在统计建模/机器学习中的重要性!我们还可以考虑对模型进行改进,在考虑以前的比赛时纳入时间(即最近的比赛应该是

从统计学上讲,泊松分布是否合适呢?我们的模型建立在这样一种信念之上,即目标数量可以准确地表示为泊松分布。如果这一假设是错误的,那么模型输出将是不可靠的。给出带有均值的泊松分布,那么在该时间段的一半内的事件数量遵循带有均值/2的泊松分布。在足球术语中,根据我们的泊松模型,在上半场和下半场应该有相等数量的进球。不幸的是,这似乎并不成立。

EPL_1617_Halves=PD。Read_CSV(";http://www.football-data.co.uk/mmz4281/1617/E0.csv";)EPL_1617_Halves=EPL_1617_Halves[[';FTHG#39;,';FTAG#39;,';HTHG#39;,';HTAG#39;]]EPL_1617_Halves[';FHGoals&39;]=EPL_1617_Halves[';HTHG';]+EPL_1617_Halves[';HTAG';]EPL_1617_Halves[';SHGoals&39;]=EPL_1617_Halves[';FTHG&39;]+EPL_1617_Halves[';FTAG';]-EPL_1617_Halves[';FHGoals&39;]EPL_1617_Halves=EPL_1617_Halves[[';FHGoals';]。,';SHGoals';]]。

我们有无可辩驳的证据,违反了我们模型的一个基本假设,使整个帖子像桑德兰一样毫无意义!或者我们可以在我们粗糙的第一次尝试的基础上再接再厉。与简单的单变量泊松模型相比,使用双变量泊松分布可能会更成功。威布尔分布也被认为是一种可行的选择。这些可能是未来博客文章的主题。

我们建立了一个简单的泊松模型来预测英超比赛的结果。尽管其固有的缺陷,它重新创造了几个特征,这将是任何预测足球模型所必需的(主场优势,不同的进攻实力和对手质量)。总而言之,不要把房租押在钱上,但对于更复杂的现实模型来说,这是一个很好的起点。谢谢你的阅读!