Python案例:如何应对突发伤病的变数
这是一个很有意思的问题,在体育赛事预测、保险精算、健康管理等领域,"突发伤病"是典型的低概率高影响事件,我用一个可运行的 Python 案例来演示几种应对思路。

场景设定
假设你在做一个体育比赛胜负概率预测系统,需要应对球员突发伤病带来的不确定性。
贝叶斯动态更新(核心思路)
当伤病消息传来时,用贝叶斯定理实时修正概率。
import numpy as np
class BayesianTeamStrength:
"""用贝叶斯更新球队实力评分"""
def __init__(self, prior_mean=1500, prior_std=100):
self.mean = prior_mean
self.std = prior_std # 不确定性
def apply_injury(self, impact=-150, uncertainty=80):
"""
impact: 伤病对实力的影响(负值=削弱)
uncertainty: 突发性带来的额外不确定性
"""
self.mean += impact
# 关键:不确定性叠加(方差相加)
self.std = np.sqrt(self.std**2 + uncertainty**2)
print(f"伤病后:实力 {self.mean:.0f} ± {self.std:.0f}")
def win_probability(self, opponent_mean=1500, opponent_std=100):
"""用正态分布近似的胜率(简化的 Bradley-Terry)"""
diff = self.mean - opponent_mean
combined_std = np.sqrt(self.std**2 + opponent_std**2)
return 1 / (1 + np.exp(-diff / combined_std * 1.7))
# 演示
team = BayesianTeamStrength()
print(f"赛前胜率: {team.win_probability():.1%}")
# 核心球员赛前受伤
team.apply_injury(impact=-180, uncertainty=120)
print(f"伤后胜率: {team.win_probability():.1%}")
要点:伤病不仅改变均值(实力),更关键的是放大方差(不确定性),这比单纯打折更符合现实。
蒙特卡洛模拟(量化极端情景)
伤病有"可能发生也可能不发生"的概率性,用模拟覆盖尾部风险。
import numpy as np
def simulate_season(n_players=11, injury_prob=0.08, n_sims=10000):
"""
模拟一个赛季:每个球员有 injury_prob 概率受伤
受伤后贡献减半
"""
base_contribution = 100 # 每人基础贡献
outcomes = []
for _ in range(n_sims):
injured = np.random.random(n_players) < injury_prob
total = np.sum(np.where(injured, base_contribution * 0.5, base_contribution))
outcomes.append(total)
outcomes = np.array(outcomes)
return {
"均值": outcomes.mean(),
"P5(悲观)": np.percentile(outcomes, 5),
"P50(中位)": np.percentile(outcomes, 50),
"P95(乐观)": np.percentile(outcomes, 95),
"最差情景": outcomes.min(),
}
result = simulate_season()
for k, v in result.items():
print(f"{k}: {v:.0f}")
要点:不要只看期望值,要看 P5 分位数——这才是"伤病变数"的真实杀伤力。
鲁棒性指标(压力测试)
主动评估系统在极端伤病下的表现,而不是被动等待。
def stress_test(roster_contributions, scenarios):
"""
roster_contributions: 各球员的贡献值列表
scenarios: 要模拟的伤病情景
"""
total = sum(roster_contributions)
print(f"全员健康:{total}\n")
for name, lost_indices in scenarios.items():
lost = sum(roster_contributions[i] for i in lost_indices)
remaining = total - lost
drop = lost / total
print(f"{name}: 剩余 {remaining} (下降 {drop:.1%})")
# 关键判断:是否有冗余
if drop > 0.3:
print(f" ⚠️ 风险预警:单一情景损失超过30%,阵容缺乏冗余")
print()
# 演示
roster = [180, 150, 140, 120, 100, 90, 80, 70, 60, 50, 40] # 从核心到替补
scenarios = {
"核心1人伤": [0],
"核心2人伤": [0, 1],
"双核+第三得分手": [0, 1, 2],
"最坏:前4人全伤": [0, 1, 2, 3],
}
stress_test(roster, scenarios)
要点:识别单点故障(concentration risk)——如果一个人受伤就让整体崩盘,说明系统本身脆弱。
决策层——成本-收益权衡
是否要为伤病"买保险"(例如签替补、买保险、调整投注)?
def insurance_decision(loss_if_injured, injury_prob, premium, max_loss):
"""
经典保险决策:期望效用 vs 风险规避
loss_if_injured: 受伤时的损失
injury_prob: 受伤概率
premium: 保费(保险成本)
max_loss: 你能承受的最大损失(风险承受阈值)
"""
expected_loss = loss_if_injured * injury_prob
print(f"期望损失: {expected_loss:.0f}")
print(f"保险成本: {premium}")
print(f"风险承受上限: {max_loss}")
print(f"不保险的最坏损失: {loss_if_injured}")
if loss_if_injured > max_loss:
print("→ 建议保险:最坏情景超出承受能力")
elif expected_loss < premium:
print("→ 不建议保险:期望损失低于保费(精算上不划算)")
else:
print("→ 建议保险:虽然略贵,但能控制尾部风险")
# 演示:核心球员受伤导致赛季失败
insurance_decision(
loss_if_injured=5000, # 赛季失败的直接损失
injury_prob=0.15,
premium=1200, # 签替补的额外成本
max_loss=3000 # 俱乐部能承受的最大损失
)
应对伤病变数的四个层次
| 层次 | 方法 | 解决的问题 |
|---|---|---|
| 预测层 | 贝叶斯更新 | 消息来了如何实时修正判断 |
| 量化层 | 蒙特卡洛 | 伤病概率化后的整体分布与尾部 |
| 诊断层 | 压力测试 | 阵容/系统的冗余度与单点故障 |
| 决策层 | 成本-收益 | 要不要为不确定性付费(保险/替补) |
核心心法:
- 不要只调均值,要放大方差——突发性的本质是不确定性上升;
- 看尾部,别只看期望——伤病是肥尾事件,P5 比均值更重要;
- 冗余 > 预测——你无法预测谁受伤,但可以设计"谁都伤得起"的系统。