如何高效计算两队进球的泊松概率并优化Numpy矩阵运算?
问题描述
我想用泊松分布计算两队都进球的概率,但遇到两个问题:
- 只计算0-6进球范围的比分时,概率总和达不到100%;
- 手动累加numpy矩阵元素效率极低。
已知变量m存储了所有可能比分的对应概率,希望找到高效方法覆盖所有有效比分,让含零/不含零比分的概率总和趋近100%。
原代码如下:
from scipy.stats import poisson import numpy as np home_goals_vector = poisson(1.23).pmf(np.arange(0, 6)) away_goals_vector = poisson(2.23).pmf(np.arange(0, 6)) print(home_goals_vector) m = np.outer(home_goals_vector, away_goals_vector) print(m[1, 1] + m[2, 1] + m[3, 1] + m[4, 1] + m[1, 2] + m[2, 2] + m[2, 3] + m[2, 4] + m[3, 2] + m[3, 3] + m[3, 4] + m[4, 1] + m[4, 2] + m[4, 4] + m[1, 3] + m[1, 4]) print(np.sum(m))
解决方案
1. 解决概率总和不足的问题
泊松分布是无限离散分布,只取0-6会丢失大比分的小概率。有两种处理方式:
- 扩大计算范围:找到足够大的进球数上限
n,使得超过n的概率总和小于可忽略阈值(比如1e-6); - 互补概率法:两队都进球的概率 = 1 - 主队没进球概率 - 客队没进球概率 + 两队都没进球概率(避免重复减去重叠部分),这种方法无需枚举所有非零比分,效率更高。
2. 解决手动累加低效的问题
利用numpy的矩阵切片和批量求和替代手动索引:
m[1:, 1:].sum():直接取主队进球≥1且客队进球≥1的所有元素求和,就是两队都进球的概率;- 若要让
np.sum(m)趋近100%,需先扩大进球数计算范围。
优化后代码
方法一:扩大范围+矩阵切片
from scipy.stats import poisson import numpy as np # 设定足够大的上限,取到15时剩余概率可忽略 max_goals = 15 home_pmf = poisson(1.23).pmf(np.arange(0, max_goals+1)) away_pmf = poisson(2.23).pmf(np.arange(0, max_goals+1)) # 生成所有比分概率矩阵 m = np.outer(home_pmf, away_pmf) # 计算两队都进球的概率:主队≥1且客队≥1 both_scored = m[1:, 1:].sum() # 验证总概率 total_prob = np.sum(m) print(f"两队都进球的概率:{both_scored:.6f}") print(f"总概率:{total_prob:.6f}") # 结果接近100%
方法二:互补概率法(更高效)
from scipy.stats import poisson home_lambda = 1.23 away_lambda = 2.23 # 主队没进球的概率 home_no_goal = poisson(home_lambda).pmf(0) # 客队没进球的概率 away_no_goal = poisson(away_lambda).pmf(0) # 两队都没进球的概率 both_no_goal = home_no_goal * away_no_goal # 两队都进球的概率 = 1 - 主队没进球 - 客队没进球 + 两队都没进球 both_scored = 1 - home_no_goal - away_no_goal + both_no_goal print(f"两队都进球的概率:{both_scored:.6f}")
说明
- 方法二无需生成庞大的概率矩阵,计算效率更高,且天然覆盖所有可能比分(泊松分布的互补概率是精确的);
- 方法一适合需要查看具体比分概率分布的场景,只要上限足够大,总概率会无限接近100%。
内容的提问来源于stack exchange,提问作者Chigstardan
相关产品推荐
相关产品推荐

