十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

美赛C题实战:基于负二项回归的奥运会奖牌数预测与建模思路

美赛C题实战:基于负二项回归的奥运会奖牌数预测与建模思路 今年美赛C题一出不少队伍盯着“奥运会奖牌榜”这几个字就开始兴奋觉得这又是一道纯数据挖掘题把历史奖牌数拖下来画个热力图再拿随机森林跑个feature importance就完事。等真正开始做才会发现这里面的数据坑和模型选择比想象中多得多奖牌数是典型的计数型数据、大量国家常年挂零、主办国效应时强时弱、历史数据口径还经常变。这篇文章就把我今年的完整建模思路和代码之外的踩坑经验整理出来从破题、特征工程、模型选型讲到评估和论文写作希望能帮后面参赛的队伍少走点弯路。1. 拿到题目以后我建议你先别碰代码1.1 题目到底想让你解决什么问题今年C题给的大方向是“奥运会奖牌榜”但真把赛题翻完你会发现它不是让你预测某个运动员能不能夺冠而是希望从国家层面建立一个可解释、可推广的模型来解释“为什么有的国家奖牌多、有的国家奖牌少”并且在一定条件下预测未来一届奥运会各国的奖牌数量或者奖牌榜排名。这类问题最迷惑人的地方在于它看起来像“预测”实际上更偏“解释”。美赛的评分往往不在你的RMSE有多低而在于你能否把一个复杂系统的关键驱动因素梳理出来并且用数据验证它。也就是说评委更想看到的是“模型讨论了哪些机制、这些机制是否站得住脚”而不只是一个黑盒预测器。从题目那堆看似杂乱的CSV里能整理出的核心问题其实很朴素用历史可观测的宏观数据解释并预测各个国家在奥运会上拿到的奖牌数量。你最后交出来的东西应该是一个有明确输入、可解释中间过程、能给出置信区间或概率范围的模型体系而不是一个只会输出数字的代码文件。1.2 难点不只在于预测精度我以前第一次做类似题目时也以为最难的是“把准确率提上去”。实际做完发现C题真正的坑有三个第一奖牌数是典型的低计数、高稀疏数据。全球有二百多个奥委会成员但一届奥运会能拿奖牌的国家通常只有六七十个剩下的大部分是0。这让很多常规回归模型直接失效因为你的目标变量不是连续正态分布。第二变量之间的因果关系很复杂。GDP高不是奖牌多的直接原因人口多也不会自动转化成金牌它们通过基础设施建设、训练条件、运动员基数、体育文化等路径间接发生作用。建模时要是不做特征选择和处理很容易出现“相关系数高但解释逻辑站不住”的局面。第三时间维度上的自相关性很强。一个国家这届拿20块奖牌下届很可能还是十几二十块上届只有1块下届也不太可能突然爆发到30块。这种滞后依赖关系既是有用的信息也是交叉验证时最容易出问题的地方处理不好就会导致信息泄露。1.3 工具和准备工作今年我们的主力工具是Python具体包括数据处理pandas、numpy统计建模statsmodels、scipy机器学习scikit-learn、LightGBM可视化matplotlib、seaborn、plotly我们不建议比赛前期就引入太复杂的深度学习框架。这个题目的样本量就是“国家×届数”级别的数据通常只有几千行甚至几百行神经网络很容易过拟合而且评委问一句“你这个特征为什么重要”就很难招架。把statsmodels和scikit-learn吃透已经足够拿M奖了。数据方面除了赛题直接给的奖牌数据我们还需要准备历届夏季奥运会的国家奖牌数、各国GDP、人口等宏观数据。GDP和人口不用自己去翻古老文献直接用世界银行开放数据接口就能拉注意统一口径就好。2. 整体设计先建一个“能解释”的模型再谈优化2.1 从奖牌榜到因果链条哪些变量真的会推高奖牌数在建模之前我习惯先画一张“逻辑链路图”哪些因素会通过什么方式影响奖牌数。这一步不需要写代码但决定了你后面选特征的方向。根据以往经验和文献最稳定的几个宏观驱动因素大概是经济总量GDP高的国家才有能力建设训练基地、聘请教练团队、提供参赛经费。人口规模人口基数大潜在运动天才数量也会多这是简单的统计学底数。主办国优势东道主在家门口比赛省去旅途消耗观众支持项目设置也可能更友好。上届成绩反映一个国家持续的体育投入和竞技水平是很好的稳态指标。参赛规模能参加的单项越多获得奖牌的机会自然越多。这些变量能解释大部分国家之间的差异。比如美国、中国、俄罗斯、英国这些奖牌大户几乎没有一个例外地同时占了“高GDP、大人口或强历史成绩”中的至少两条。值得注意的是现实里还有一个很关键的因素叫“体育体制”比如国家对某些项目集中投入、举国体制培养运动员等但这些很难找到统一的历史量化数据。我的处理方式是用“上届奖牌数”和“国家固定效应”来间接吸收这部分不可观测信息而不是强行找一堆残缺字段填坑。2.2 为什么不用单一机器学习模型开局很多队伍一上来就LightGBM、XGBoost然后跑出一堆feature importance看着很高大上实际上很容易翻车。因为这题的数据量太小特征又相互关联树模型很容易把噪声也学进去尤其当你的目标变量有大量0时输出还会出现“负值奖牌数”这种荒谬结果。我的建议是第一版模型一定要用“能看懂每一个系数”的模型。比如对数线性回归、泊松回归、负二项回归。它们形式简单但能让评委一眼看出“GDP每提高10%、奖牌数预计变化百分之几”这样的信息。这种可解释性是美赛特别看重的。当然不是说机器学习模型不能用。我的定位是把它当“对标模型”和“稳健性检验”。先用经典统计模型搭好框架再用LightGBM去逼近更复杂的非线性关系最后对比两个模型的误差和特征排序看结论是否一致。如果两个口径完全不同的模型都告诉你“主办国效应显著为正”那你这个结论就比较扎实了。2.3 我们采用的模型框架对数线性回归 负二项回归 GBDT对照最终我们采用了三条腿走路的框架对数线性回归作为所有模型的baseline把奖牌数取对数之后做线性回归优点是简单直观容易解释。负二项回归作为主模型。奖牌数是计数数据用泊松分布更合适但实际数据存在“过离散”也就是方差远大于均值所以用负二项分布更稳。梯度提升树GBDT作为复杂模型对照用来捕捉交互效应和非线性暴露出线性模型可能忽略的模式。三个模型用同一套训练集和验证集最后在测试集上做对比。如果负二项回归和GBDT的结果差异不大我倾向于选择负二项回归作为最终交付模型理由很直接可解释性更强灵敏度分析更好写。这里要特别强调负二项回归的对数链接函数会保证预测值永远是正数这正好符合奖牌数的物理约束。“用普通线性回归预测出-3块奖牌”这种尴尬情况在负二项模型里不会出现。2.4 评价指标体系比赛不是只看RMSE今年我们在队内反复强调不要只盯着RMSE或R²。因为奖牌数是一个长尾分布几个大国贡献了绝大部分误差如果只看总RMSE你优化半天可能只是在拟合美国、中国这几个极端值。我们最终用的评价指标包括MAE平均绝对误差直观受极端值影响较小。Spearman相关系数衡量预测排名和真实排名的一致性比直接看数值更贴近“奖牌榜”这个主题。Top 10预测命中率预测出奖牌榜前10的国家里有多少真的进了前10。这个指标很贴合题目本身的场景。区间覆盖率模型给出的置信区间是否能以合理概率覆盖真实值。在比赛中段我们发现A国家实际拿了9块奖牌模型预测了10.2块B国家实际拿了0块模型预测了0.8块。只看RMSEA的误差更大但如果你要预测奖牌榜排名A其实排得挺准B的0.8误差也不小。所以每个指标都在讲不同维度的故事建议赛后一定要做一张指标对比表让评委知道你对自己的模型不是盲目的。3. 建模实操细节决定奖牌榜前十能不能命中3.1 数据清洗把历史奖牌数据整理成“国家-年份”宽表这一步是最枯燥但也是最重要的。赛题给的数据往往是“运动员-项目-奖牌”级别的流水记录而建模要用的单位必须是“国家-年份-奖牌数”所以第一步就是聚合。我们的做法是# 以国家-年份-奖牌类型进行聚合 df_group df_raw.groupby([Year, NOC, Medal]).size().unstack(fill_value0) # 如果某列缺失说明该国家该年份没有该类奖牌 for col in [Gold, Silver, Bronze]: if col not in df_group.columns: df_group[col] 0 df_group[Total] df_group[[Gold, Silver, Bronze]].sum(axis1)但在做这个聚合之前有几个坑必须提前处理团队项目的奖牌统计。有些项目如篮球、足球、接力赛一支队伍可能十几个人但官方奖牌榜只给“1枚金牌”不是按人头算。如果直接从运动员明细聚合就会把一个篮球队当12块金牌这是致命的错误。最好直接使用赛题给的国家奖牌榜汇总表或者聚合时按“Event”去重而不是按“Athlete”计数。国家名称变化。比如前苏联、独联体、俄罗斯在奖牌数据里的代码是不同的德国也经历过东西德合并。我的做法是单独维护一张“历史NOC到现代NOC映射表”把这些有传承关系的国家合并成一条连续序列否则模型会误以为这是个新国家。早年的奖牌数据稀疏。1896年、1900年那几届参赛国家少、项目少直接放进模型会让时间趋势拟合很奇怪。我们最后的处理是选择1948年以后的夏季奥运会作为建模数据因为这段时期的比赛形式和现代奥运更为接近。3.2 特征工程不是只有GDP和人口奖牌数预测常用的特征看起来不多但每构造一个都要问一句“这个特征在预测未来时能取到吗”。我们最终保留了这么几类经济人口特征GDP对数和人口对数。选择对数是因为GDP提升10倍不一定能让奖牌数提升10倍用对数可以把这种边际递减效应压出来。处理历史GDP时要注意部分国家早期数据缺失我们用前后届线性插值补齐并在论文里明确写了插值方法。主办国特征一个二元变量host当年是主办国记为1。更进阶一点的做法是加一个“下届是否主办”的变量因为不少国家在确定申奥成功后会提前一个周期增加投入这种效应在伦敦奥运会前的英国身上表现得非常明显。历史成绩特征上届奖牌数、上上届奖牌数。这两个滞后变量非常强但也非常危险因为它们的缺失值很多——有些国家上一届没参赛滞后奖牌数就是0这会低估它们的真实实力。所以我们额外加了一个“上届是否参赛”的虚拟变量用0/1告诉模型“这个0是参赛但没拿牌还是压根没去”。参赛规模特征参赛运动员人数或参赛项目数。这个特征在数据里往往存在但它和奖牌数存在明显的内生关系运动员多是因为强不是因为有运动员所以强。我们最后是用“上届参赛项目数”作为替代尽量减少内生性。固定效应把大洲或国家代码作为随机截距加入模型用来吸收文化、体制等不可观测因素。这里我推荐用“国家随机效应”而不要用“国家固定效应”因为随机效应可以泛化到样本外的国家。3.3 模型训练与调参滚动交叉验证是关键我们的训练集跨越了很多届奥运会如果直接随机按行切分训练和测试相邻年份的数据不会互相污染吗说实话奥运奖牌这种四年一次的数据时间相关性没有经济数据那么强但依然是存在的。所以我们采用了“滚动预测”的验证方式第一次用截至2012年的数据训练预测2016年第二次用截至2016年的数据训练预测2020年第三次用截至2020年的数据训练预测2024年。然后把三次预测的真实结果拼起来计算整体误差。这个方式很贴近真实场景你要预测2028年时能用的也就只有截至2024年的历史数据。负二项回归在statsmodels里实现非常方便import statsmodels.api as sm import statsmodels.formula.api as smf model smf.glm( formulaTotal ~ log_gdp log_pop host lag_total lag_participated C(Year), datatrain_df, familysm.families.NegativeBinomial(alpha0.5) ).fit() pred model.predict(test_df)这里的alpha是过离散参数可以先设为0.5再通过极大似然估计自动调整。我们在实际用的时候发现alpha估计在1左右说明奖牌数确实存在明显的过离散用普通泊松会低估不确定性。GBDT这里主要由LightGBM来跑但我没有做大规模调参只调了树的棵数和学习率目的是做一个对照不是追求极限精度。最后两个模型的MAE确实很接近但在top10命中率上负二项回归反而更高这也印证了我们“以统计模型为主”的判断。3.4 从期望奖牌数到排名分布只给每个国家一个“期望奖牌数”其实不够因为奖牌榜是一个排名系统你还需要知道这个期望附近的波动有多大。比如A国期望17枚、B国期望16枚看起来A国排名靠前但两者的置信区间可能重叠大半这时候你没法说A国一定排前面。所以我们做了蒙特卡洛模拟利用负二项分布生成每个国家的预测分布然后每次模拟从每个国家抽样一个奖牌数排序形成一个模拟奖牌榜重复比如1000次。最后统计每个国家出现在“奖牌榜前10”“奖牌榜前20”中的概率。这样得到的输出非常优雅你可以画一张横向条形图每根条是“某国进入前10的概率”而不是冷冰冰的预测数字。评委看到这种结果时会很自然地理解你的模型在权衡不确定性这是纯机器学习模型很难直接给出的东西。4. 真实操作中踩过的坑整理成排障手册4.1 奖牌数为0的国家太多线性回归直接崩一开始我们天真地用了“对数线性回归”作为baseline对奖牌总数取log1p之后开始拟合。虽然模型本身没有报错但残差图一出来左下角挤了一大堆真实值为0、预测值在1到3之间的国家。原因很好理解取对数只是把0压到了0但回归假设误差服从正态分布0奖牌的国家和1奖牌的国家在数值上只差1可它们代表的“真实差距”远不止1。后来换成负二项回归后这个问题自然就解决了。负二项分布自带处理整数和0的能力它建模的是“某国家获得k块奖牌的概率”而不是“奖牌数近似等于某个实数”。如果你不想用负二项至少要采用零膨胀泊松ZIP或者Hurdle模型但这就把问题变复杂了反而不如负二项回归清爽。4.2 主办国效应不是加一个虚拟变量那么简单“主办国到底能多拿几块奖牌”这个问题我们翻过不少历史数据平均来看主办国的奖牌数会比正常水平提升30%到50%但这里的“正常水平”很难定义。如果直接用host这个0/1变量它只是给所有主办国加同一个增量。可现实是主办国本身如果体育实力很弱就算有主场优势也拿不了几块奖牌。我们的改进方案是把host和“上届奖牌数是否超过中位数”做一个交互项区分“强队主办”和“弱队主办”。前者有一个肉眼可见的爆发后者提升幅度小甚至不显著。另外英国在伦敦奥运会前一年的奖牌数已经明显上涨这说明“主办红利”可能从前一届就开始了。我们给模型加入了“下一届是否主办”这个变量捕捉申奥成功之后提前投入国家队建设的效应最后显著性和效果都很好。4.3 上届奖牌数看似好用实际上有信息泄漏风险滞后变量是这种题目里最危险的特征。因为你想预测2024年用2020年的真实奖牌数作为特征当然没问题。但如果你在做交叉验证时手滑把2024年目标行也参与了训练模型就相当于“拿着答案考试”。我们刚开始滚动预测的逻辑不够严谨第一折训练到2016年验证2016年但特征里却包含了2016年本身的上届成绩也就是2012年的数据这没问题问题出在第二折我想当然地把2020年数据放进了训练集后来发现这不平等地使用了未来信息。正确的做法是每一次滚动训练只能使用“截至当前预测年份之前的所有历史信息”。预测2020年时训练集最多到2016年而特征中的lag变量只能算到2016年。这段逻辑一定要写成清晰的数据管道最好加断言检查防止在比赛中后期改特征时把泄露带进来。4.4 随机森林在数据量小的时候feature importance不稳定有一次我们跑LightGBM的feature importance发现“GDP”重要性忽高忽低换一个随机种子就完全变了排序。这是小样本下树模型常有的问题因为每一棵树的划分都很容易受个别异常国家影响。后来我们采用了重复排列重要性方法把某个特征随机打乱100次看模型误差平均上升多少重复5组随机种子取中位数。这样得到的排序稳定很多而且比默认的“分裂增益”更能反映真实预测贡献。如果你在论文里要放特征重要性图强烈建议用这个方法不然评委换一次随机种子可能就发现你的排序不靠谱。5. 论文和可视化让评委觉得你的故事是完整闭环5.1 摘要和问题重述的写法美赛论文的摘要极其关键评委可能只花半分钟扫一遍摘要就决定这篇论文的层次。我们的摘要写法遵循“问题是什么、我们用了什么数据、建立了什么模型、得到什么结论、有什么亮点”五段式但每一段都要配上具体结果。比如不能只写“我们使用了负二项回归模型”要写“负二项回归结果显示主办国效应平均带来约40%的奖牌数提升且在强队中更为明显模型在2024年测试集上的Spearman相关系数为0.89前10名命中率达70%。”这样每句话都在告诉评委“我有明确的结论”。问题重述部分千万不要把题目抄一遍。我一般会重新组织语言用自己的理解说清楚“要解决的是一个国家层面的奖牌数估计和排名预测问题”顺便点出其中三个核心难点数据稀疏、计数特征、时间依赖。评委看到你抓的重点和题目设计意图一致印象分会高很多。5.2 四张必须做的图可视化这件事多不代表好关键是每一张图都要服务一个建模结论。我们最后正文里放了四张图每张都能讲出一个故事第一张是“主办国与奖牌数变化”的对比图。横轴是主办年份前后三届纵轴是主办国奖牌总数用多条折线把英国、中国、澳大利亚等近几届主办国连起来直观展示东道主红利。这张图是用来说明特征工程里为什么放host交互项。第二张是“实际奖牌数 vs 预测奖牌数”散点图。每个点是一个国家在某届奥运会上的表现横轴为真实值、纵轴为预测值再用对角线辅助参考。这张图能展示模型整体校准度也能看出哪些国家被高估或低估。第三张是“进入前10概率”条形图。用蒙特卡洛模拟结果展示中国、美国、日本、英国等热门国家进入奖牌榜前10的概率。这张图特别适合放在模型结果部分因为它直接回答了用户最关心的问题。第四张是特征重要性排序图。用重复排列重要性画一个水平条形图让评委一眼看到“哪些因素对奖牌数影响最大”。通常上届奖牌数、GDP、人口、主办国效应会排在前面这与直觉一致会增强模型的可信度。5.3 灵敏度分析和局限性怎么交代灵敏度分析最让我头疼因为做得太浅会被认为没意义做得太重又费时间。我们的做法是选两个关键参数做扰动一是GDP数据如果我们统一上调10%前10名奖牌榜会不会变化二是主办国效应如果从均值估计改为中位数估计排名结果是否稳定。结果显示GDP上调10%后绝大多数国家的排名没有变化只有奖牌数位于临界位置的少数国家可能出现上下一位的浮动。这说明模型整体是稳定的但同时也暴露出排名预测受尾部国家影响较大的问题。局限性部分我建议实话实说但不要写得太“丧”。我们的模型没有考虑运动员伤病、重大赛事爆冷、新增大项带来的项目结构变化这些都是真实存在但宏观数据无法反映的因素。直接在论文里承认并说明这些因素可能是下一步优化方向比藏着掖着更让评委舒服。6. 如果你还有时间可以再往前一步6.1 用分层贝叶斯模型吸收国家异质性如果比赛还剩一天且你已经把主模型写清楚了可以考虑用一个简单版的分层贝叶斯模型做锦上添花。把每个国家的截距看成来自一个共同先验分布的随机变量而不是每个国家单独估计这样既能保留国家特点又能在小样本下借用其他国家的信息。在PyMC或者Stan里写一个负二项分层模型并不复杂但运行时间可能有点长。好处是你能给出更完整的后验分布而不是一个点估计和近似置信区间。评委对这种模型的接受度很高因为它明确展示了你理解了“国家是嵌套在地区或全球体系中的”。6.2 金银铜分开建模 vs 总量建模如果预测“总奖牌数”已经做完了还可以尝试把金、银、铜分开建模。毕竟有些国家的银牌和铜牌可能多但金牌少若按总奖牌数预测会掩盖这种结构性差异。最朴素的做法是分别跑三个负二项回归再加一个“金牌总数”回归用于排序。更进一步可以用多元计数模型或“分层多输出模型”但要小心过度复杂带来的不稳定。在我们自己的实验里分开建模后金牌榜前10的命中率比总量模型高了约5到8个百分点所以这个方向是值得的。6.3 加入新增项目和项目结构变量每届奥运会都会调整小项设置比如新增滑板、冲浪、霹雳舞等。这些新增项目往往对东道主和部分年轻选手比例高的国家有利。如果数据允许可以构造一个“该届新增小项总数”以及“某国在该类项目上的历史优势指数”作为补充特征。我们当时因为时间不够没有做这个但复盘时觉得这个变量很可能解释一部分残差尤其是对日本、澳大利亚这种在某些新增项目上很有优势的国家。下一届如果规则没变这个方向值得仔细研究。最后分享一个我个人很受用的习惯比赛最后半天不要强行加模型把已有代码每个环节跑一遍确保从数据清洗到预测输出的流程可以一键复现然后坐下来花一小时检查摘要里每一个数字看看是不是都能在结果表里找到出处。这套流程看着不起眼却让我们在正式提交前避免了好几次图表和数据对不上的尴尬。建模说到底是一次“说服评委”的过程你能把自己的每一步选择讲清楚比模型多提高0.01的精度重要得多。希望这些思路对准备明年美赛的你有点帮助。
返回列表