[{"data":1,"prerenderedAt":237},["ShallowReactive",2],{"note-r2-too-good-zh":3,"titles-zh":233},{"note":4,"project":163},{"id":5,"title":6,"body":7,"date":145,"description":146,"draft":147,"extension":148,"kind":149,"meta":150,"navigation":151,"path":152,"pinned":147,"project":153,"seo":154,"stem":156,"summary":157,"tags":158,"__hash__":162,"translated":151},"notes\u002Fnotes\u002Fr2-too-good.md","当 R² 好得过头",{"type":8,"value":9,"toc":139},"minimark",[10,14,22,76,79,84,87,90,93,96,99,112,127,130],[11,12,13],"p",{},"毕业论文的研究问题：按位置（门将、后卫、中场、前锋）分别训练的随机森林模型，能否比单一的通用模型更准确地预测球员的 Sofascore 评分？",[11,15,16,17,21],{},"第一个版本给每个模型输入的是球员在这场比赛本身的数据：射门、传球、对抗、抢断、触球，一共 63 列。验证过程是干净的：用第 1 到 30 轮训练，用第 31 到 38 轮测试，用按比赛分组的 ",[18,19,20],"code",{},"GroupKFold"," 调超参数，保证同一场比赛的球员不会同时出现在一个折的两边。一个只预测该位置平均评分的基线给出了下限。",[23,24,25,41],"table",{},[26,27,28],"thead",{},[29,30,31,35,38],"tr",{},[32,33,34],"th",{},"模型",[32,36,37],{},"MAE",[32,39,40],{},"R²",[42,43,44,55,66],"tbody",{},[29,45,46,50,53],{},[47,48,49],"td",{},"位置平均",[47,51,52],{},"0.391",[47,54],{},[29,56,57,60,63],{},[47,58,59],{},"通用模型",[47,61,62],{},"0.203",[47,64,65],{},"0.72",[29,67,68,71,74],{},[47,69,70],{},"位置专用模型",[47,72,73],{},"0.207",[47,75,65],{},[11,77,78],{},"前锋的 R² 达到了 0.80。把基线误差砍掉一半，写进论文里很好看。但这说不通：在足球里，单场比赛的数据不应该能解释这么多东西。",[80,81,83],"h2",{"id":82},"不是数据泄漏是循环论证","不是数据泄漏，是循环论证",[11,85,86],{},"第一个怀疑对象是训练集和测试集之间的泄漏。结果并没有。数据划分和交叉验证的折都保持每场比赛完整，没有任何测试数据碰到训练过程。",[11,88,89],{},"问题出在预测目标上。Sofascore 评分来自一个不公开的公式，而这个公式的输入和那 63 个特征非常相似：进球、传球、对抗、抢断。随机森林学到的并不是\"什么是好的表现\"，而是在逼近产生这个数字的公式。高 R² 衡量的只是模型模仿 Sofascore 算法的程度，仅此而已。",[11,91,92],{},"这个实验仍然回答了一个更窄的问题（在已知比赛数据的情况下，位置专用模型只在门将上胜出，而门将恰好是统计特征最独特的位置）。但它回答不了真正重要的问题：能不能在比赛开始前就知道评分？",[80,94,95],{"id":95},"重新设计",[11,97,98],{},"第二个实验禁止使用被预测的那场比赛的任何数据。每个特征都必须在开球前就已经存在：",[100,101,102,106,109],"ul",{},[103,104,105],"li",{},"主场还是客场；",[103,107,108],{},"对手实力：对手在之前比赛中的进球数和失球数；",[103,110,111],{},"球员自己的历史：61 项数据的赛季平均值，以及评分和出场时间的赛季平均值和近 5 场平均值，全部只用严格早于本场的比赛计算。",[11,113,114,115,122,123,126],{},"\"严格早于\"正是 ",[116,117,121],"a",{"className":118,"href":120},[119],"wikilink","\u002Fzh\u002Fnotes\u002Fsofascore-data-traps","一个赛季的 Sofascore 数据，以及它在哪里说谎"," 中的轮次顺序不再是小细节的原因。还没有历史数据的球员（14.9% 的球员整个赛季只踢了 3 场或更少）会得到 ",[18,124,125],{},"NaN","，scikit-learn 的随机森林从 1.4 版本起可以原生处理。同时还会加入一个此前出场次数的特征，让模型学会更相信 20 场的历史，而不是 1 场。",[11,128,129],{},"验证方式改为前向滚动：用一批 10 场比赛之前的全部数据训练，预测这一批，再把它加入训练集，继续下一批，覆盖赛季的最后 80 场比赛。超参数搜索在训练窗口内使用按时间排序的折，始终在晚于训练数据的比赛上验证。",[11,131,132,133,138],{},"R² 降到了 0.10。这是预期中的结果，不是退步。用接近评分公式本身的数据去解释一个已经产生的评分，是一回事；在比赛前预测它，是另一件难得多的事。结果见 ",[116,134,137],{"className":135,"href":136},[119],"\u002Fzh\u002Fnotes\u002Fpre-match-ratings","一场比赛的评分，大部分无法预测","。",{"title":140,"searchDepth":141,"depth":141,"links":142},"",2,[143,144],{"id":82,"depth":141,"text":83},{"id":95,"depth":141,"text":95},"2026-10-22","The thesis question: can Random Forest models specialized by position (goalkeeper, defender, midfielder, forward) predict a player's Sofascore rating better than one generic model?",false,"md","article",{},true,"\u002Fnotes\u002Fr2-too-good","sofascore-rating-prediction",{"title":155,"description":146},"When R² is too good","notes\u002Fr2-too-good","第一个模型解释了前锋评分 80% 的方差。问题恰恰在这里：它是在重建 Sofascore 的评分公式，而不是在预测足球。",[159,160,161],"ml","random-forest","python","CP8qnPZk8uwlUZW8_GuAtolxx3ul1AWgwUEW6IlLme8",{"id":164,"title":165,"body":166,"cover":218,"date":219,"demo":218,"description":220,"draft":147,"extension":148,"featured":151,"meta":221,"navigation":151,"order":222,"path":223,"repo":224,"seo":225,"status":227,"stem":228,"summary":229,"tags":230,"__hash__":232,"translated":151},"projects\u002Fprojects\u002Fsofascore-rating-prediction.md","Sofascore 球员评分预测",{"type":8,"value":167,"toc":213},[168,171,174,177,198,201,204,207,210],[11,169,170],{},"我在 FATEC Sorocaba 的毕业论文，指导老师是 Maria das Graças J. M. Tomazela 教授。研究问题只有一个：按位置（门将、后卫、中场、前锋）分别训练的随机森林模型，能否比单一的通用模型以更小的误差在赛前预测球员的 Sofascore 评分？",[80,172,173],{"id":173},"流程",[11,175,176],{},"分三个阶段，每个阶段只从磁盘读取上一阶段的输出，因此任何一个阶段都可以单独重跑。",[100,178,179,186,192],{},[103,180,181,185],{},[182,183,184],"strong",{},"采集。"," 一个\"有礼貌\"的 Sofascore 内部 API 爬虫：限速、带退避的重试、断点续爬，并对每一行数据做 Pydantic 校验。共采集 11,977 条球员单场记录，覆盖 2025 年巴西甲级联赛全部 380 场比赛。",[103,187,188,191],{},[182,189,190],{},"清洗。"," 每个步骤一个函数。有意思的是，一个空单元格可能代表三种不同的含义，每种都有各自的处理规则。",[103,193,194,197],{},[182,195,196],{},"建模。"," 只使用赛前特征：主客场、对手实力，以及球员截至被预测比赛之前的历史表现。在最后 80 场比赛上做前向滚动验证，以整场比赛为单位做 bootstrap 置信区间，并计算置换重要性。",[80,199,200],{"id":200},"结果",[11,202,203],{},"按位置专门建模并没有降低误差。通用模型比\"按位置取平均\"的基线好 6%（MAE 0.374 对 0.398），而门将的评分在赛前几乎无法预测。一场比赛的评分，大部分是在比赛过程中才决定的。",[80,205,206],{"id":206},"笔记",[11,208,209],{},"按顺序讲完整个过程：数据里的陷阱，第一个好得不真实的模型，以及当模型只能看到过去时得出的结果。",[11,211,212],{},"技术栈：Python、httpx、tenacity、Pydantic v2、pandas、scikit-learn、pytest。",{"title":140,"searchDepth":141,"depth":141,"links":214},[215,216,217],{"id":173,"depth":141,"text":173},{"id":200,"depth":141,"text":200},{"id":206,"depth":141,"text":206},null,"2026-08-27","My undergraduate thesis at FATEC Sorocaba, supervised by Prof. Dr. Maria das Graças J. M. Tomazela. One question: can Random Forest models specialized by position (goalkeeper, defender, midfielder, forward) predict a player's Sofascore rating before the match with lower error than a single generic model?",{},3,"\u002Fprojects\u002Fsofascore-rating-prediction","https:\u002F\u002Fgithub.com\u002Falmeidaota\u002Fsofascore-rating-prediction",{"title":226,"description":220},"Sofascore rating prediction","active","projects\u002Fsofascore-rating-prediction","我的毕业论文。按位置分别训练的随机森林模型，能否比一个通用模型更准确地在赛前预测球员的 Sofascore 评分？答案是否定的。",[161,231,159,160],"scraping","IcTcWXpYn5Kpmy9fqNl7cIFEbUs7Jrm8SMXO46pBHt8",{"\u002Fnotes\u002Fva-longe-mas-va-acompanhado":234,"\u002Fnotes\u002Fpre-match-ratings":137,"\u002Fnotes\u002Fr2-too-good":6,"\u002Fnotes\u002Fsofascore-data-traps":121,"\u002Fprojects\u002Fargus-maximus":235,"\u002Fprojects\u002Frobbie":236,"\u002Fprojects\u002Fsofascore-rating-prediction":165},"走得远，就要结伴同行","Argus Maximus","robbie",1793409193263]