实用脚本如何量化主力缺阵损失值?

wen 实用脚本 3

本文目录导读:

实用脚本如何量化主力缺阵损失值?

  1. 先定义“损失值”的度量口径
  2. 核心量化方法
  3. 脚本化实现(Python 伪代码骨架)
  4. 把损失值转成“可沟通数字”
  5. 常见坑

量化“主力缺阵损失值”本质上是把“某球员不打”这件事,翻译成对球队某项可观测指标的影响,实操中不可能精确到“缺阵=损失X分”这种单一数字,但可以用一套分层、可落地的脚本化方法逼近,下面给出一套完整框架和可直接改用的脚本思路。


先定义“损失值”的度量口径

主力缺阵的损失可以从四个层面量化,脚本应分别输出,不要混成一个数:

口径 含义 数据需求
净胜分影响 该球员在场/不在场时球队每百回合净胜分差 阵容/换人数据(on-off)
胜率影响 缺阵场次 vs 出战场次的胜率差,控制对手强度 赛程+伤病名单
替代者落差 替补顶替后该位置产出下降幅度 球员逐场数据
市场/赔率隐含值 博彩盘口在缺阵消息前后的移动 盘口历史

最常用、最可复现的是前两个,下面以篮球为例(足球同理,把回合换成每90分钟)。


核心量化方法

方法1:On/Off 净效率差(最直接)

对每个球员计算:

OnOff = 球队百回合净胜分(球员在场) − 球队百回合净胜分(球员不在场)

脚本要点:

  • 用阵容组合数据(lineup data)而非简单加减,避免同时在场球员混淆。
  • 加正则化/收缩:样本小的组合向球队均值收缩(贝叶斯收缩),否则替补打垃圾时间会虚高。
  • 输出置信区间,样本<200回合的标记为“不可靠”。

方法2:RAPM 类回归(控制队友和对手)

On/Off 会被“和谁一起打”污染,用岭回归:

净胜分 ~ Σ(球员i是否在场) + 对手强度 + 主客场 + 垃圾时间标记

得到每个球员的“调整后在场贡献值”,缺阵损失 ≈ 该球员RAPM × 预计缺阵回合数,这是业界(NBA、足球的+/-模型)标准做法,脚本可用 sklearn.Ridge 实现。

方法3:缺阵场次的匹配/双重差分(DID)

把“该球员缺阵的比赛”与“同赛季他出战的比赛”做对比,控制对手强度、主客场、背靠背:

损失 = E[净胜分 | 缺阵, 控制变量] − E[净胜分 | 出战, 控制变量]

脚本用固定效应回归:净胜分 ~ 缺阵虚拟变量 + 对手强度 + 主客场 + 背靠背 + 球队固定效应,这是因果味最浓、最容易向教练/管理层解释的口径。

方法4:替补替代落差(位置级)

损失 = 主力该位置场均产出 − 替补顶替期间该位置场均产出

产出用统一单位(如篮球用PER/每36分钟得分+助攻-失误;足球用xA+xG/90),适合快速估算、数据不全时兜底。


脚本化实现(Python 伪代码骨架)

import pandas as pd, numpy as np
from sklearn.linear_model import Ridge
# ---------- 输入 ----------
# games: 每场 球队、对手、主客、日期、净胜分、pace
# stints: 每个换人区间 球队、在场5人、回合数、净胜分
# injuries: 球员、缺阵场次列表
def on_off(stints, player, team_mean):
    on  = stints[stints.players.str.contains(player)]
    off = stints[~stints.players.str.contains(player)]
    def rate(df):  # 百回合净胜分
        return df.net_points.sum() / df.poss.sum() * 100
    raw = rate(on) - rate(off)
    # 贝叶斯收缩:样本越小越靠近0
    w = on.poss.sum() / (on.poss.sum() + 300)
    return raw * w, on.poss.sum()
def rapm(stints):
    # 构造 球员-区间 的0/1矩阵
    X = pd.get_dummies(stints.players.explode()).groupby(level=0).sum()
    y = stints.net_points / stints.poss * 100
    model = Ridge(alpha=1.0).fit(X, y, sample_weight=stints.poss)
    return pd.Series(model.coef_, index=X.columns)
def did_loss(games, injuries, player, team):
    g = games[games.team == team].copy()
    g["absent"] = g.game_id.isin(injuries[player])
    # 固定效应回归
    import statsmodels.formula.api as smf
    m = smf.ols("net_rating ~ absent + opp_strength + home + b2b + C(season)",
                data=g).fit(cov_type="HC1")
    return m.params["absent"], m.conf_int().loc["absent"]
# ---------- 汇总 ----------
def loss_report(player, team, stints, games, injuries, expected_games_out):
    oo, poss = on_off(stints, player, None)
    coef, ci = did_loss(games, injuries, player, team)
    rapm_val = rapm(stints).get(player, np.nan)
    return {
        "on_off_per100": round(oo, 2),
        "on_off_sample_poss": int(poss),
        "did_net_rating_loss": round(coef, 2),
        "did_ci": [round(ci[0],2), round(ci[1],2)],
        "rapm_per100": round(rapm_val, 2),
        "expected_loss_points": round(rapm_val/100 * poss_per_game * expected_games_out, 1),
    }

关键工程细节:

  • 垃圾时间剔除:分差>20且剩余<5分钟的比赛区间剔除,否则替补On/Off严重失真。
  • 收缩估计:样本不足时向0收缩,脚本里用权重实现。
  • 置信区间必输出:缺阵损失是估计值,给区间比给单点更负责。
  • 位置对齐:替代者落差要按位置/角色匹配,不能拿中锋替后卫。

把损失值转成“可沟通数字”

管理层要的是一个能进决策的數,建议输出三档:

  1. 每百回合净胜分损失(战术口径)
  2. 折合赛季胜场损失 = 每百回合损失 × 预计缺阵回合 / 每胜所需净胜分
  3. 盘口隐含损失 = 缺阵消息前后让分盘移动(市场口径,交叉验证)

三档互相印证:若On/Off说损失4分/百回合,但盘口只动1.5分,说明市场认为替补深度好或样本有偏,需要复核。


常见坑

  • 共线性:主力常和另一主力同场,On/Off会互相“抢贡献”,必须用RAPM或阵容组合。
  • 对手强度未控制:缺阵恰好赶上强队赛程,会高估损失。
  • 小样本:缺阵3场就下结论不可靠,务必给区间并标注样本量。
  • 角色变化:主力缺阵后战术体系改变,替补不是简单“顶替”,DID比替代落差更稳。
  • 足球特殊点:用每90分钟xG/xA差、对手ELO控制;门将缺阵损失要用扑救超出预期(PSxG)单独建模。

一句话总结:用“阵容区间On/Off + RAPM回归 + 缺阵DID”三件套交叉估计,输出带置信区间的每百回合净胜分损失,再折成胜场和盘口移动做校验——这就是可脚本化、可复现、能进决策的主力缺阵损失量化流程,需要的话我可以把上面骨架补成可直接跑的完整脚本(含数据清洗和垃圾时间过滤)。

抱歉,评论功能暂时关闭!

友情链接攻略窝 · 礼包窝 · 配置窝 · 换算窝 · 算法窝 · 查文窝 · 手册窝 · 问答窝 · 全文搜 · 手册库
相关站点礼包窝 · 查文窝