[{"data":1,"prerenderedAt":627},["ShallowReactive",2],{"home-zh":3},{"projects":4,"notes":187},[5,72,116],{"id":6,"title":7,"body":8,"cover":54,"date":55,"demo":54,"description":47,"draft":56,"extension":57,"featured":56,"meta":58,"navigation":59,"order":60,"path":61,"repo":62,"seo":63,"status":64,"stem":65,"summary":66,"tags":67,"__hash__":71,"translated":59},"projects\u002Fprojects\u002Fargus-maximus.md","Argus Maximus",{"type":9,"value":10,"toc":46},"minimark",[11,18,21,25,28,31,34,37,40,43],[12,13,14],"blockquote",{},[15,16,17],"p",{},"百眼巨人，无所不见。",[15,19,20],{},"为 Cartola FC（巴西最大的足球经理类游戏）自动选阵的工具，分两步完成：预测和优化。",[22,23,24],"h2",{"id":24},"预测",[15,26,27],{},"首先，随机森林模型预测 500 多名可选球员在下一轮各自能拿多少分。输入包括场均得分、近期状态、主客场、对手实力，以及技术统计（抢断、射门、犯规）。",[22,29,30],{"id":30},"优化",[15,32,33],{},"然后，在每名球员都有预测得分之后，用线性规划选出实际阵容：在不超预算、阵型合规（4-3-3、4-4-2 等）的前提下，让预测总分最大。不需要手动调整阵容，求解器会直接找出在这些预测下数学上最优的球队。",[22,35,36],{"id":36},"数据",[15,38,39],{},"前几轮的历史数据来自 Henrique P. Gomide 的 caRtola 数据集，之后的数据都由项目自己的 ETL 脚本抓取。",[22,41,42],{"id":42},"下一步",[15,44,45],{},"项目仍在积极开发中。接下来会用正式的数据库替换 CSV，然后做回测，看看模型在过去几轮里实际表现如何。",{"title":47,"searchDepth":48,"depth":48,"links":49},"",2,[50,51,52,53],{"id":24,"depth":48,"text":24},{"id":30,"depth":48,"text":30},{"id":36,"depth":48,"text":36},{"id":42,"depth":48,"text":42},null,"2025-06-26",false,"md",{},true,1,"\u002Fprojects\u002Fargus-maximus","https:\u002F\u002Fgithub.com\u002Falmeidaota\u002FArgusMaximus",{"title":7,"description":47},"active","projects\u002Fargus-maximus","为 Cartola FC 自动选阵的工具。随机森林预测每名球员的得分，再用线性规划选出最优的合规阵容。",[68,69,70],"python","docker","ml","LTJogzkenoc-e9dFDh3__HsdVWCQSg_wQJO80T_4fgo",{"id":73,"title":74,"body":75,"cover":54,"date":103,"demo":54,"description":104,"draft":56,"extension":57,"featured":56,"meta":105,"navigation":59,"order":48,"path":106,"repo":107,"seo":108,"status":64,"stem":109,"summary":110,"tags":111,"__hash__":115,"translated":59},"projects\u002Fprojects\u002Frobbie.md","robbie",{"type":9,"value":76,"toc":98},[77,80,83,86,89,92,95],[15,78,79],{},"一个住在终端里的英语教练。你可以像和朋友聊天一样和它对话。它会在对话过程中纠正你的语法，长期记录你犯过的每一个错误，并给每次对话打分。",[22,81,82],{"id":82},"分工",[15,84,85],{},"最有意思的是分工。识别交给大语言模型，因为判断一句话\"听起来对不对\"需要灵活的、接近人类水平的判断。之后的一切都是普通的确定性代码：解析、计数、评分。同一次对话，每次算出的数字都一样。以后调整评分权重时，所有历史对话都会按同一标准重新评分，因为分数从不存储，只会重新计算。",[22,87,88],{"id":88},"词汇",[15,90,91],{},"它还会顺便帮你建一套间隔重复的卡片。每个你在句子中途想不起来的词都会变成一张抽认卡，用自己实现的 SM-2 引擎安排复习，也可以直接导出到 Anki。",[22,93,94],{"id":94},"形态",[15,96,97],{},"三种对话模式（日常、正式、面试），用 Postgres 存储；不想跑 Docker 的话，还有一个 SQLite 分支。做这个项目是因为我真的想提高自己的英语，而不是给提示词套个壳。",{"title":47,"searchDepth":48,"depth":48,"links":99},[100,101,102],{"id":82,"depth":48,"text":82},{"id":88,"depth":48,"text":88},{"id":94,"depth":48,"text":94},"2026-08-21","An English coach that lives in your terminal. You talk to it like you'd talk to a friend. It corrects your grammar as you go, tracks every mistake over time, and scores each session.",{},"\u002Fprojects\u002Frobbie","https:\u002F\u002Fgithub.com\u002Falmeidaota\u002Frobbie",{"title":74,"description":104},"projects\u002Frobbie","住在终端里的英语教练。识别交给大语言模型，之后的一切都由确定性代码完成。",[68,112,113,114],"rust","cli","llm","R33A0NwdItt5shI5kf6t1tY5gqRoZBRSAnBQksT4gZM",{"id":117,"title":118,"body":119,"cover":54,"date":173,"demo":54,"description":174,"draft":56,"extension":57,"featured":59,"meta":175,"navigation":59,"order":176,"path":177,"repo":178,"seo":179,"status":64,"stem":181,"summary":182,"tags":183,"__hash__":186,"translated":59},"projects\u002Fprojects\u002Fsofascore-rating-prediction.md","Sofascore 球员评分预测",{"type":9,"value":120,"toc":168},[121,124,127,130,153,156,159,162,165],[15,122,123],{},"我在 FATEC Sorocaba 的毕业论文，指导老师是 Maria das Graças J. M. Tomazela 教授。研究问题只有一个：按位置（门将、后卫、中场、前锋）分别训练的随机森林模型，能否比单一的通用模型以更小的误差在赛前预测球员的 Sofascore 评分？",[22,125,126],{"id":126},"流程",[15,128,129],{},"分三个阶段，每个阶段只从磁盘读取上一阶段的输出，因此任何一个阶段都可以单独重跑。",[131,132,133,141,147],"ul",{},[134,135,136,140],"li",{},[137,138,139],"strong",{},"采集。"," 一个\"有礼貌\"的 Sofascore 内部 API 爬虫：限速、带退避的重试、断点续爬，并对每一行数据做 Pydantic 校验。共采集 11,977 条球员单场记录，覆盖 2025 年巴西甲级联赛全部 380 场比赛。",[134,142,143,146],{},[137,144,145],{},"清洗。"," 每个步骤一个函数。有意思的是，一个空单元格可能代表三种不同的含义，每种都有各自的处理规则。",[134,148,149,152],{},[137,150,151],{},"建模。"," 只使用赛前特征：主客场、对手实力，以及球员截至被预测比赛之前的历史表现。在最后 80 场比赛上做前向滚动验证，以整场比赛为单位做 bootstrap 置信区间，并计算置换重要性。",[22,154,155],{"id":155},"结果",[15,157,158],{},"按位置专门建模并没有降低误差。通用模型比\"按位置取平均\"的基线好 6%（MAE 0.374 对 0.398），而门将的评分在赛前几乎无法预测。一场比赛的评分，大部分是在比赛过程中才决定的。",[22,160,161],{"id":161},"笔记",[15,163,164],{},"按顺序讲完整个过程：数据里的陷阱，第一个好得不真实的模型，以及当模型只能看到过去时得出的结果。",[15,166,167],{},"技术栈：Python、httpx、tenacity、Pydantic v2、pandas、scikit-learn、pytest。",{"title":47,"searchDepth":48,"depth":48,"links":169},[170,171,172],{"id":126,"depth":48,"text":126},{"id":155,"depth":48,"text":155},{"id":161,"depth":48,"text":161},"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":180,"description":174},"Sofascore rating prediction","projects\u002Fsofascore-rating-prediction","我的毕业论文。按位置分别训练的随机森林模型，能否比一个通用模型更准确地在赛前预测球员的 Sofascore 评分？答案是否定的。",[68,184,70,185],"scraping","random-forest","IcTcWXpYn5Kpmy9fqNl7cIFEbUs7Jrm8SMXO46pBHt8",[188,234,393,518],{"id":189,"title":190,"body":191,"date":221,"description":222,"draft":56,"extension":57,"kind":223,"meta":224,"navigation":59,"path":225,"pinned":56,"project":54,"seo":226,"stem":228,"summary":229,"tags":230,"__hash__":233,"translated":59},"notes\u002Fnotes\u002Fva-longe-mas-va-acompanhado.md","走得远，就要结伴同行",{"type":9,"value":192,"toc":219},[193,196,199,210,213,216],[15,194,195],{},"科技是我能想象到的最有意思、也最深奥的领域之一。前几天，我花了将近一个小时去弄懂一个线性代数的概念，而它只是在我为写硕士研究计划而读的一篇论文里被顺带提了一句。",[15,197,198],{},"不过，如果只能挑一样我最喜欢这个领域的东西，我会说是人。",[15,200,201,202,209],{},"读了一些关于外熵主义者（Extropians）的资料后，我很惊叹：寥寥几个投入、有创造力、彼此分享想法的人，就能改变世界。正是他们，在多年的邮件列表讨论中，",[203,204,208],"a",{"href":205,"rel":206},"https:\u002F\u002Fcypherbrush.substack.com\u002Fp\u002Farquivo-cypherpunk-0003-hashcash",[207],"nofollow","提出了后来催生比特币的那些概念","。",[15,211,212],{},"就我个人而言，我有一位在网络安全领域工作的朋友。我们会交流怎么安排学习，也交流各种想法，而在一次随意的闲聊中，冒出了一个想法，如果我被录取，它也许会成为我的硕士课题。",[15,214,215],{},"这个领域里有很多孤僻、不太爱说话的人，他们常常是“不被理解的天才”。但对他们，我想引用一句我外婆常说的老话：",[15,217,218],{},"“独行快，众行远。”",{"title":47,"searchDepth":48,"depth":48,"links":220},[],"2026-10-30","Tech is one of the most interesting and dense fields I can imagine. The other day I spent almost an hour trying to understand a linear algebra concept that was mentioned in passing in a paper I was reading to write my study plan for my master's.","note",{},"\u002Fnotes\u002Fva-longe-mas-va-acompanhado",{"title":227,"description":222},"Go far, but go together","notes\u002Fva-longe-mas-va-acompanhado","我最喜欢科技领域的是人：从催生比特币的邮件列表，到和朋友的一次闲聊，那次闲聊也许会成为我的硕士课题。",[231,232],"community","cypherpunk","6BWabb5zFsUU8mHYtMFIBQQlE8T3i3x5uc64sYAJXZs",{"id":235,"title":236,"body":237,"date":381,"description":382,"draft":56,"extension":57,"kind":383,"meta":384,"navigation":59,"path":385,"pinned":56,"project":373,"seo":386,"stem":388,"summary":389,"tags":390,"__hash__":392,"translated":59},"notes\u002Fnotes\u002Fpre-match-ratings.md","一场比赛的评分，大部分无法预测",{"type":9,"value":238,"toc":374},[239,249,332,335,343,346,349,352,355,358,361,364,367],[15,240,241,242,248],{},"沿用 ",[203,243,247],{"href":244,"className":245},"\u002Fnotes\u002Fr2-too-good",[246],"wikilink","当 R² 好得过头"," 中的设定：在开球前预测每名球员的 Sofascore 评分，只使用主客场、对手实力和球员自己的历史数据。在 2025 年巴西甲级联赛的最后 80 场比赛上做前向滚动验证，共 2,494 人次出场。",[250,251,252,268],"table",{},[253,254,255],"thead",{},[256,257,258,262,265],"tr",{},[259,260,261],"th",{},"模型",[259,263,264],{},"MAE",[259,266,267],{},"R²",[269,270,271,283,294,305,316],"tbody",{},[256,272,273,277,280],{},[274,275,276],"td",{},"球员近 5 场平均",[274,278,279],{},"0.412",[274,281,282],{},"-0.06",[256,284,285,288,291],{},[274,286,287],{},"位置平均",[274,289,290],{},"0.398",[274,292,293],{},"0.01",[256,295,296,299,302],{},[274,297,298],{},"球员赛季平均",[274,300,301],{},"0.389",[274,303,304],{},"0.05",[256,306,307,310,313],{},[274,308,309],{},"位置专用模型",[274,311,312],{},"0.375",[274,314,315],{},"0.10",[256,317,318,323,328],{},[274,319,320],{},[137,321,322],{},"通用随机森林",[274,324,325],{},[137,326,327],{},"0.374",[274,329,330],{},[137,331,315],{},[22,333,334],{"id":334},"位置专用模型没有帮助",[15,336,337,338,342],{},"通用模型的 MAE 减去位置专用模型的 MAE 为 -0.0014，95% 置信区间为 ",[339,340,341],"span",{},"-0.0036, 0.0008","。这个区间来自 2,000 次 bootstrap 重抽样，每次抽取的是整场比赛而不是单行数据，因为同一场比赛中的球员并不相互独立。区间包含零，所以两者打平。决策规则在看到任何结果之前就已确定：如果打平，保留通用模型，因为一个模型比四个更简单。位置专用模型在任何一个位置上都没有胜出。",[22,344,345],{"id":345},"近期状态是噪声",[15,347,348],{},"球员近 5 场的平均评分，表现甚至不如完全不看这名球员、直接猜该位置的平均值。整个赛季的平均值则比两者都好。在五场比赛的尺度上，手感好或差大多只是噪声。置换重要性也印证了这一点：通用模型主要依赖两个特征，主客场和球员本赛季的平均评分。其余 61 项数据的历史几乎没有贡献。",[22,350,351],{"id":351},"门将",[15,353,354],{},"对门将来说，没有任何模型能明显胜过基线（通用模型和位置平均的 MAE 都是 0.559，R² 略低于零）。门将的评分取决于这场比赛中的扑救和失球，而在开球前，根本无法知道他会面对 2 次射门还是 12 次。",[22,356,357],{"id":357},"预测值紧贴平均值",[15,359,360],{},"测试集中真实评分的范围是 3.0 到 9.7，标准差为 0.54。通用模型的预测值范围是 6.63 到 7.41，标准差为 0.16。测试集中有 108 人次的评分在 8.0 或以上，模型的预测从来没有接近过其中任何一个。它会在主场比赛、以及本赛季表现好的球员身上把预测值往上调一点，但无法预见一场格外好或格外差的比赛。",[22,362,363],{"id":363},"答案",[15,365,366],{},"按位置专门建模并没有降低误差。通用模型比位置平均好 6.0%，比球员自己的赛季平均好 3.9%，而第二个差距是真实存在的（它的置信区间不包含零）。数字不大，但这就是信号的真实大小：一场比赛的评分，大部分是在比赛过程中决定的。",[15,368,369,370,209],{},"代码和完整方法：",[203,371,373],{"href":178,"rel":372},[207],"sofascore-rating-prediction",{"title":47,"searchDepth":48,"depth":48,"links":375},[376,377,378,379,380],{"id":334,"depth":48,"text":334},{"id":345,"depth":48,"text":345},{"id":351,"depth":48,"text":351},{"id":357,"depth":48,"text":357},{"id":363,"depth":48,"text":363},"2026-10-22","The setup from When R² is too good: predict each player's Sofascore rating before kickoff, using only home\u002Faway, opponent strength and the player's own history. Walk-forward validation over the last 80 matches of the 2025 Brasileirão, 2,494 appearances.","article",{},"\u002Fnotes\u002Fpre-match-ratings",{"title":387,"description":382},"Most of a match rating can't be predicted","notes\u002Fpre-match-ratings","按位置专门建模没有胜过单一的通用模型，近期状态还不如完全没有信息，而门将的评分谁也预测不了。论文的答案是否定的。",[70,185,391],"football","lRXhmendunPnntPdV0Kyh7MYFU2L_Af49JqWx0-YMFc",{"id":394,"title":247,"body":395,"date":381,"description":510,"draft":56,"extension":57,"kind":383,"meta":511,"navigation":59,"path":244,"pinned":56,"project":373,"seo":512,"stem":514,"summary":515,"tags":516,"__hash__":517,"translated":59},"notes\u002Fnotes\u002Fr2-too-good.md",{"type":9,"value":396,"toc":506},[397,400,408,451,454,458,461,464,467,470,473,484,497,500],[15,398,399],{},"毕业论文的研究问题：按位置（门将、后卫、中场、前锋）分别训练的随机森林模型，能否比单一的通用模型更准确地预测球员的 Sofascore 评分？",[15,401,402,403,407],{},"第一个版本给每个模型输入的是球员在这场比赛本身的数据：射门、传球、对抗、抢断、触球，一共 63 列。验证过程是干净的：用第 1 到 30 轮训练，用第 31 到 38 轮测试，用按比赛分组的 ",[404,405,406],"code",{},"GroupKFold"," 调超参数，保证同一场比赛的球员不会同时出现在一个折的两边。一个只预测该位置平均评分的基线给出了下限。",[250,409,410,420],{},[253,411,412],{},[256,413,414,416,418],{},[259,415,261],{},[259,417,264],{},[259,419,267],{},[269,421,422,431,442],{},[256,423,424,426,429],{},[274,425,287],{},[274,427,428],{},"0.391",[274,430],{},[256,432,433,436,439],{},[274,434,435],{},"通用模型",[274,437,438],{},"0.203",[274,440,441],{},"0.72",[256,443,444,446,449],{},[274,445,309],{},[274,447,448],{},"0.207",[274,450,441],{},[15,452,453],{},"前锋的 R² 达到了 0.80。把基线误差砍掉一半，写进论文里很好看。但这说不通：在足球里，单场比赛的数据不应该能解释这么多东西。",[22,455,457],{"id":456},"不是数据泄漏是循环论证","不是数据泄漏，是循环论证",[15,459,460],{},"第一个怀疑对象是训练集和测试集之间的泄漏。结果并没有。数据划分和交叉验证的折都保持每场比赛完整，没有任何测试数据碰到训练过程。",[15,462,463],{},"问题出在预测目标上。Sofascore 评分来自一个不公开的公式，而这个公式的输入和那 63 个特征非常相似：进球、传球、对抗、抢断。随机森林学到的并不是\"什么是好的表现\"，而是在逼近产生这个数字的公式。高 R² 衡量的只是模型模仿 Sofascore 算法的程度，仅此而已。",[15,465,466],{},"这个实验仍然回答了一个更窄的问题（在已知比赛数据的情况下，位置专用模型只在门将上胜出，而门将恰好是统计特征最独特的位置）。但它回答不了真正重要的问题：能不能在比赛开始前就知道评分？",[22,468,469],{"id":469},"重新设计",[15,471,472],{},"第二个实验禁止使用被预测的那场比赛的任何数据。每个特征都必须在开球前就已经存在：",[131,474,475,478,481],{},[134,476,477],{},"主场还是客场；",[134,479,480],{},"对手实力：对手在之前比赛中的进球数和失球数；",[134,482,483],{},"球员自己的历史：61 项数据的赛季平均值，以及评分和出场时间的赛季平均值和近 5 场平均值，全部只用严格早于本场的比赛计算。",[15,485,486,487,492,493,496],{},"\"严格早于\"正是 ",[203,488,491],{"className":489,"href":490},[246],"\u002Fnotes\u002Fsofascore-data-traps","一个赛季的 Sofascore 数据，以及它在哪里说谎"," 中的轮次顺序不再是小细节的原因。还没有历史数据的球员（14.9% 的球员整个赛季只踢了 3 场或更少）会得到 ",[404,494,495],{},"NaN","，scikit-learn 的随机森林从 1.4 版本起可以原生处理。同时还会加入一个此前出场次数的特征，让模型学会更相信 20 场的历史，而不是 1 场。",[15,498,499],{},"验证方式改为前向滚动：用一批 10 场比赛之前的全部数据训练，预测这一批，再把它加入训练集，继续下一批，覆盖赛季的最后 80 场比赛。超参数搜索在训练窗口内使用按时间排序的折，始终在晚于训练数据的比赛上验证。",[15,501,502,503,209],{},"R² 降到了 0.10。这是预期中的结果，不是退步。用接近评分公式本身的数据去解释一个已经产生的评分，是一回事；在比赛前预测它，是另一件难得多的事。结果见 ",[203,504,236],{"className":505,"href":385},[246],{"title":47,"searchDepth":48,"depth":48,"links":507},[508,509],{"id":456,"depth":48,"text":457},{"id":469,"depth":48,"text":469},"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?",{},{"title":513,"description":510},"When R² is too good","notes\u002Fr2-too-good","第一个模型解释了前锋评分 80% 的方差。问题恰恰在这里：它是在重建 Sofascore 的评分公式，而不是在预测足球。",[70,185,68],"CP8qnPZk8uwlUZW8_GuAtolxx3ul1AWgwUEW6IlLme8",{"id":519,"title":491,"body":520,"date":381,"description":618,"draft":56,"extension":57,"kind":383,"meta":619,"navigation":59,"path":490,"pinned":56,"project":373,"seo":620,"stem":622,"summary":623,"tags":624,"__hash__":626,"translated":59},"notes\u002Fnotes\u002Fsofascore-data-traps.md",{"type":9,"value":521,"toc":613},[522,525,528,531,538,541,544,576,579,589,592,595,606],[15,523,524],{},"我的毕业论文需要 2025 年巴西甲级联赛的全部球员评分。Sofascore 有这些数据，就在它自己网站所用的内部 API 后面。由于这不是官方的公开 API，爬虫被刻意做得很\"无聊\"：每 1.2 到 2.4 秒发一次请求，失败时带退避重试，每一轮结束后保存断点，崩溃后可以接着跑而不必从头开始，并且每一行数据在写入 CSV 之前都要经过 Pydantic 校验。",[15,526,527],{},"最终从全部 380 场比赛中抓取了 11,977 条球员单场记录，比赛时间从 2025 年 3 月 29 日到 12 月 7 日。采集是最简单的部分。数据里有三个陷阱，而且没有一个会报错。",[22,529,530],{"id":530},"时区错误的日期",[15,532,533,534,537],{},"爬虫用 UTC 存储比赛日期。巴西的夜场比赛在 21:00 或更晚开球，按 UTC 已经是第二天了，所以 380 场比赛中有 67 场的日期是错的。修正方法是根据开球时间戳在 ",[404,535,536],{},"America\u002FSao_Paulo"," 时区下重新计算日期，清洗步骤和爬虫本身都做了修改。",[22,539,540],{"id":540},"三种缺失",[15,542,543],{},"一个空单元格可能代表三种不同的含义，每种都有各自的处理规则：",[131,545,546,556,562],{},[134,547,548,551,552,555],{},[137,549,550],{},"不适用。"," 比如中锋的扑救数。这些字段对非门将球员根本不会出现，所以填 ",[404,553,554],{},"-1","，这是任何真实计数都不可能取到的值。",[134,557,558,561],{},[137,559,560],{},"未测量。"," 体能数据（跑动距离、冲刺次数、最高速度）只在 380 场中的 349 场有，带球推进数据只在 83 场有。这些保持缺失。如果填成零，就等于声称球员没有跑动。",[134,563,564,567,568,571,572,575],{},[137,565,566],{},"为零而被省略。"," Sofascore 不会发送值为 0 的数据。在原始数据中，",[404,569,570],{},"goals"," 有 11,124 行为空，",[404,573,574],{},"expected_goals"," 有 6,314 行为空，恰好都是球员没有射门的那些行。这些填为 0。",[15,577,578],{},"在体能和带球推进这两组数据中，规则按球员判断：如果某球员有该组中的任意一项指标，缺失的就是被省略的零值；如果一项都没有，说明这组数据没有为他测量。",[15,580,581,582,585,586,588],{},"一个边界情况：门将的 ",[404,583,584],{},"goals_prevented"," 可能为负（从 -3.79 到 3.12），所以在这里哨兵值 ",[404,587,554],{}," 会和真实值冲突。这时用位置列来区分。",[22,590,591],{"id":591},"打乱顺序的轮次",[15,593,594],{},"给一个赛季排序，最直观的方法是按轮次编号。但这是错的。轮次会因为洲际赛事而改期，第 34 轮的大部分比赛直到 11 月才踢，而第 35 到 37 轮早在 10 月就已经踢完了。整个赛季中，72,010 对可能的比赛组合里，有 1,795 对（2.49%）的轮次编号和实际开球时间相矛盾。",[15,596,597,598,601,602,605],{},"一旦要计算球员的历史数据，这就不再是冷知识了。按轮次而不是开球时间排序，会改变 686 名踢过两场或以上的球员中 335 人（48.8%）的比赛顺序。对于一个只能看到过去比赛的模型来说，这就是数据泄漏：一场未来的比赛混进了过去某场比赛的历史里。之后的所有步骤都按 ",[404,599,600],{},"kickoff_timestamp"," 排序，从不按 ",[404,603,604],{},"round"," 排序。",[15,607,608,609,612],{},"清洗之后，删除了 163 条没有评分的出场记录，它们的出场时间都在 7 分钟或以下。最终剩下 732 名球员的 11,814 行数据，也就是 ",[203,610,247],{"className":611,"href":244},[246]," 中模型所用的训练数据。",{"title":47,"searchDepth":48,"depth":48,"links":614},[615,616,617],{"id":530,"depth":48,"text":530},{"id":540,"depth":48,"text":540},{"id":591,"depth":48,"text":591},"My thesis needed every player rating from the 2025 Brazilian Série A. Sofascore has them, behind the same internal API its website uses. It isn't an official public API, so the crawler was built to be boring: one request every 1.2 to 2.4 seconds, retries with backoff, a checkpoint after every round so a crash resumes instead of starting over, and Pydantic validation on every row before it reaches the CSV.",{},{"title":621,"description":618},"A season of Sofascore data, and where it lies","notes\u002Fsofascore-data-traps","抓取 2025 年巴西甲级联赛的全部球员评分，以及数据里的三个陷阱：时区错误的日期、从不发送的零值，以及打乱顺序的轮次。",[68,184,625],"data","eXQcuImFjV98ThxZr0pIfb9o9ar0a4y7Y8iJLRS93iQ",1793409192383]