[{"data":1,"prerenderedAt":217},["ShallowReactive",2],{"note-sofascore-data-traps-pt":3,"titles-pt":212},{"note":4,"project":139},{"id":5,"title":6,"body":7,"date":121,"description":122,"draft":123,"extension":124,"kind":125,"meta":126,"navigation":127,"path":128,"pinned":123,"project":129,"seo":130,"stem":132,"summary":133,"tags":134,"__hash__":138,"translated":127},"notes\u002Fnotes\u002Fsofascore-data-traps.md","Uma temporada de dados do Sofascore, e onde eles mentem",{"type":8,"value":9,"toc":114},"minimark",[10,14,17,22,30,34,37,72,75,85,89,92,103],[11,12,13],"p",{},"Meu TCC precisava de todas as notas de jogadores do Brasileirão Série A 2025. O Sofascore tem, atrás da mesma API interna que o próprio site usa. Como não é uma API pública oficial, o crawler foi feito pra ser entediante: uma requisição a cada 1,2 a 2,4 segundos, novas tentativas com backoff, um checkpoint ao fim de cada rodada pra que uma queda retome em vez de recomeçar, e validação com Pydantic em cada linha antes de ela chegar no CSV.",[11,15,16],{},"Isso rendeu 11.977 registros de jogador por partida, de todos os 380 jogos, disputados entre 29 de março e 7 de dezembro de 2025. Coletar foi a parte fácil. Os dados tinham três armadilhas, e nenhuma delas gerou erro.",[18,19,21],"h2",{"id":20},"datas-no-fuso-errado","Datas no fuso errado",[11,23,24,25,29],{},"O crawler guardava as datas das partidas em UTC. Os jogos noturnos no Brasil começam às 21h ou mais tarde, o que já é o dia seguinte em UTC, então 67 das 380 partidas estavam com a data errada. A correção foi recalcular a data a partir do timestamp do início do jogo em ",[26,27,28],"code",{},"America\u002FSao_Paulo",", tanto na limpeza quanto no próprio crawler.",[18,31,33],{"id":32},"três-tipos-de-ausência","Três tipos de ausência",[11,35,36],{},"Uma célula vazia significava três coisas diferentes, e cada uma ganhou sua própria regra:",[38,39,40,52,58],"ul",{},[41,42,43,47,48,51],"li",{},[44,45,46],"strong",{},"Não se aplica."," Defesas de um centroavante. Essas chaves nunca aparecem pra jogadores de linha, então recebem ",[26,49,50],{},"-1",", um valor que nenhuma contagem real pode ter.",[41,53,54,57],{},[44,55,56],{},"Não medido."," Estatísticas físicas (distância, sprints, velocidade máxima) existem em só 349 das 380 partidas, conduções de bola em só 83. Essas continuam ausentes. Preencher com zero seria afirmar que o jogador não correu.",[41,59,60,63,64,67,68,71],{},[44,61,62],{},"Zero, omitido."," O Sofascore não envia estatísticas que valem 0. Nos dados brutos, ",[26,65,66],{},"goals"," estava vazio em 11.124 linhas e ",[26,69,70],{},"expected_goals"," em 6.314, exatamente as linhas em que o jogador não finalizou. Esses viram 0.",[11,73,74],{},"Dentro dos grupos de físicas e de conduções, a regra é por jogador: se ele tem qualquer métrica do grupo, as que faltam são zeros omitidos. Se não tem nenhuma, o grupo não foi medido pra ele.",[11,76,77,78,81,82,84],{},"Um caso de borda: ",[26,79,80],{},"goals_prevented"," pode ser negativo pra goleiros (de -3,79 a 3,12), então ali o sentinela ",[26,83,50],{}," colide com valores reais. A coluna de posição desfaz o empate.",[18,86,88],{"id":87},"rodadas-fora-de-ordem","Rodadas fora de ordem",[11,90,91],{},"O jeito óbvio de ordenar uma temporada é pelo número da rodada. Está errado. Rodadas são remarcadas por causa das competições continentais, e a maior parte da rodada 34 só foi jogada em novembro, depois de as rodadas 35 a 37 terem sido jogadas em outubro. Ao longo da temporada, 1.795 dos 72.010 pares possíveis de partidas (2,49%) têm números de rodada que contradizem o horário de início.",[11,93,94,95,98,99,102],{},"Isso deixa de ser curiosidade assim que você calcula o histórico de um jogador. Ordenar por rodada em vez de horário muda a ordem das partidas de 335 dos 686 jogadores (48,8%) com dois jogos ou mais. Pra um modelo que só pode olhar partidas passadas, isso é vazamento: um jogo futuro se infiltrando no histórico de um jogo passado. Tudo dali pra frente ordena por ",[26,96,97],{},"kickoff_timestamp",", nunca por ",[26,100,101],{},"round",".",[11,104,105,106,113],{},"Depois da limpeza, 163 atuações sem nota foram descartadas, todas de 7 minutos ou menos. Sobraram 11.814 linhas de 732 jogadores, que foi com o que os modelos de ",[107,108,112],"a",{"className":109,"href":111},[110],"wikilink","\u002Fpt\u002Fnotes\u002Fr2-too-good","Quando o R² é bom demais"," foram treinados.",{"title":115,"searchDepth":116,"depth":116,"links":117},"",2,[118,119,120],{"id":20,"depth":116,"text":21},{"id":32,"depth":116,"text":33},{"id":87,"depth":116,"text":88},"2026-10-22","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.",false,"md","article",{},true,"\u002Fnotes\u002Fsofascore-data-traps","sofascore-rating-prediction",{"title":131,"description":122},"A season of Sofascore data, and where it lies","notes\u002Fsofascore-data-traps","Coletando todas as notas de jogadores do Brasileirão 2025, e as três armadilhas nos dados: datas no fuso errado, zeros que nunca são enviados e rodadas jogadas fora de ordem.",[135,136,137],"python","scraping","data","eXQcuImFjV98ThxZr0pIfb9o9ar0a4y7Y8iJLRS93iQ",{"id":140,"title":141,"body":142,"cover":196,"date":197,"demo":196,"description":198,"draft":123,"extension":124,"featured":127,"meta":199,"navigation":127,"order":200,"path":201,"repo":202,"seo":203,"status":205,"stem":206,"summary":207,"tags":208,"__hash__":211,"translated":127},"projects\u002Fprojects\u002Fsofascore-rating-prediction.md","Previsão de notas do Sofascore",{"type":8,"value":143,"toc":191},[144,147,151,154,174,178,181,185,188],[11,145,146],{},"Meu TCC na FATEC Sorocaba, orientado pela Profa. Dra. Maria das Graças J. M. Tomazela. Uma pergunta: modelos Random Forest especializados por posição (goleiro, defensor, meio-campista, atacante) conseguem prever a nota de um jogador no Sofascore antes da partida com erro menor que um único modelo genérico?",[18,148,150],{"id":149},"pipeline","Pipeline",[11,152,153],{},"Três etapas, cada uma lendo do disco só a saída da etapa anterior, então qualquer uma pode ser rodada de novo sozinha.",[38,155,156,162,168],{},[41,157,158,161],{},[44,159,160],{},"Coleta."," Um crawler educado pra API interna do Sofascore: limite de requisições, novas tentativas com backoff, checkpoint\u002Fretomada e validação com Pydantic em cada linha. 11.977 registros de jogador por partida, de todos os 380 jogos do Brasileirão Série A 2025.",[41,163,164,167],{},[44,165,166],{},"Limpeza."," Uma função por etapa. A parte interessante é que uma célula vazia pode significar três coisas diferentes, cada uma com sua própria regra.",[41,169,170,173],{},[44,171,172],{},"Modelagem."," Só features pré-jogo: mando de campo, força do adversário e o histórico do próprio jogador até a partida sendo prevista. Validação walk-forward nas últimas 80 partidas, intervalos de confiança por bootstrap sobre partidas inteiras, importância por permutação.",[18,175,177],{"id":176},"resultado","Resultado",[11,179,180],{},"A especialização não reduziu o erro. O modelo genérico superou em 6% uma baseline de média por posição (MAE 0,374 contra 0,398), e prever goleiros antes do jogo se mostrou um caso perdido. A maior parte da nota de uma partida se decide durante a partida.",[18,182,184],{"id":183},"notas","Notas",[11,186,187],{},"A história em ordem: as armadilhas dos dados, o primeiro modelo, bom demais pra ser verdade, e o que saiu quando o modelo só podia ver o passado.",[11,189,190],{},"Stack: Python, httpx, tenacity, Pydantic v2, pandas, scikit-learn, pytest.",{"title":115,"searchDepth":116,"depth":116,"links":192},[193,194,195],{"id":149,"depth":116,"text":150},{"id":176,"depth":116,"text":177},{"id":183,"depth":116,"text":184},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":204,"description":198},"Sofascore rating prediction","active","projects\u002Fsofascore-rating-prediction","Meu TCC. Modelos Random Forest especializados por posição preveem a nota de um jogador no Sofascore antes do jogo melhor do que um modelo genérico? A resposta foi não.",[135,136,209,210],"ml","random-forest","IcTcWXpYn5Kpmy9fqNl7cIFEbUs7Jrm8SMXO46pBHt8",{"\u002Fnotes\u002Fva-longe-mas-va-acompanhado":213,"\u002Fnotes\u002Fpre-match-ratings":214,"\u002Fnotes\u002Fr2-too-good":112,"\u002Fnotes\u002Fsofascore-data-traps":6,"\u002Fprojects\u002Fargus-maximus":215,"\u002Fprojects\u002Frobbie":216,"\u002Fprojects\u002Fsofascore-rating-prediction":141},"Vá longe, mas vá acompanhado","A maior parte da nota de uma partida não dá pra prever","Argus Maximus","robbie",1793409192818]