Aller au contenu

Sources

Tout ce que ce cours affirme vient de l'un des trois blocs ci-dessous : nos rapports internes, nos sources de données, ou la littérature. Le statut de chaque bloc est différent, et le cours le signale à chaque fois.

1 · Sources primaires internes

Ce sont les documents qui portent nos mesures. Ils vivent dans le dépôt du projet, à la racine /workspace/cs2-vrs-major-predictor. Chaque dossier d'approche contient au minimum un report.json (les mesures brutes, lisibles par une machine) et, sauf exception, un README.md (le récit en trois paragraphes).

Le protocole et le classement

Fichier Contenu
scratch/ml/BRIEF.md Le protocole commun du concours : paliers à battre, quatre règles non négociables, données disponibles
scratch/ml/LEADERBOARD.md Le classement final des 11 approches et les repères

Les onze approches classées

Approche Dossier Ce qu'on y trouve de particulier
logreg scratch/ml/logreg/ logistique codée à la main, variante « probabilité de manche » rejetée, poids commentés
bayes scratch/ml/bayes/ grilles de réglage Glicko-2 et TrueSkill, horloges en prédicteurs purs, tables de calibration
stats scratch/ml/stats/ extraction des tables de statistiques joueurs de 9 112 pages, player_stats.pkl
maps scratch/ml/maps/ veto, scores par carte avec mi-temps, head-to-head daté, maps_data.pkl
stack scratch/ml/stack/ quatre configurations d'empilement, diagnostics de calibration forcée
final scratch/ml/final/ fusion des trois familles, comparaison logistique / XGBoost / mélange, features_final.pkl
push scratch/ml/push/ ~60 configurations issues de la littérature, trois passes de validation, mapfeats.py
squeeze scratch/ml/squeeze/ quatre chantiers d'extraction du cache, rang mondial daté, rank_data.pkl
assault scratch/ml/assault/ décomposition du saut, build_dataset.py, assault_features.pkl, run.log
lastmile scratch/ml/lastmile/ quatre chantiers, trois morts chiffrées, premiers segments, model_lastmile.pkl
segmodel scratch/ml/segmodel/ le leader : grille de 40 combinaisons, segments du holdout, model_segmodel.pkl

Les approches hors classement

Approche Dossier Statut
gbdt scratch/ml/gbdt/ report.json complet, pas de README — réglage de trois bibliothèques d'arbres, résultat 0.2331
hardcore scratch/ml/hardcore/ hypothèse « le simple bat le riche sur le segment dur » réfutée, grille de 110 configurations
ultimate scratch/ml/ultimate/ économie rejouée sur les manches unifiées : couverture par jeu, 13 vainqueurs discordants listés, verdict « INFIRMÉ »
lastcard scratch/ml/lastcard/ wtsm, chantier de clôture : construction de l'horloge, corrélation à l'ancienne, seuil de bruit, verdict « la validation mentait » (pas de README, report.json + run.log)
scout scratch/ml/scout/ reconnaissance des sources de données : ce qui est mort, ce qui est viable, avec les preuves
harvest scratch/ml/harvest/ industrialisation des trois gisements externes, volumes, taux d'appariement, caveats temporels

Les six chantiers de confrontation au marché

Menés après la clôture de la campagne, ils portent la partie Contre le marché. Aucun n'ajoute de ligne au classement : ce sont des mesures, pas des modèles. Tous sont hors ligne et reproductibles, et chacun commence par reproduire le leader à 0.2041 / 67,9 % sous assertion.

Chantier Dossier Ce qu'il établit
bookpool scratch/ml/bookpool/ les cinq définitions du pool comparable, figées et horodatées avant la première métrique ; le pool coté est plus dur ; le spécialiste « tier 1 » ne sauve rien
odds scratch/ml/odds/ la découverte des cotes dans le champ bet_updates, le diagnostic de contamination in-play, le vrai palier du marché sur nos matchs (0.2094 / 65,6 %)
vsmarket scratch/ml/vsmarket/ la cote en feature (morte), le mélange à deux régimes (0.2036), la courbe plate de \(w\), le pool de 903 matchs
oddsmax scratch/ml/oddsmax/ l'appariement élargi (+525 matchs cotés), l'inversion du verdict, le diagnostic de collecte — pas de README, tout est dans report.json, measure.json et verify.json
fairfight scratch/ml/fairfight/ la mesure à fenêtre de fit constante, le balayage qui chiffre le biais (0.0104 de Brier), les deux verdicts finaux
maxacc scratch/ml/maxacc/ l'angle mort de l'exactitude : seuil de décision, objectifs orientés exactitude, zone d'indécision, cible des 70 %
Objectif Commande
Rejouer la découverte des cotes et le diagnostic in-play python scratch/ml/odds/code/run.py (~35 s)
Rejouer la cote en feature et le blend python scratch/ml/vsmarket/run.py (~22 s)
Rejouer la mesure à armes égales python scratch/ml/fairfight/run.py (~40 s, reprenable)

Comment lire un report.json

Ces fichiers ont tous la même structure : une section protocol (tailles des jeux, nombre de passes de holdout, leader à battre), une section validation (chaque configuration testée avec son Brier), un holdout_table (les mesures finales), une calibration_final par tranches, et souvent un verdict en clair.

C'est cette structure qui rend les échecs réutilisables : on peut retrouver le chiffre exact d'une idée abandonnée sans relancer quoi que ce soit.

Le code de production

Fichier Rôle
vrs/predict.py Le modèle de probabilité de victoire de départ, le balayage chronologique de référence, la définition du holdout de 42 jours et la fonction de métriques commune
vrs/winprob.py L'industrialisation du leader : le blend segmodel en production dans le simulateur
vrs/model.py Le moteur de classement porté depuis le code officiel

Les documents de campagne

Fichier Contenu
docs/corrections-moteur-2026-08.md Les dix corrections du moteur de classement, chacune avec symptôme, cause, correctif et mesure — et les quatre leçons transverses sur l'anachronisme
scratch/drift/rapport.md L'enquête complète sur le patchwork de pagination : symptôme, cause racine, bisection par la donnée, simulation de contrôle, correctifs, protocole de mesure
docs/superpowers/specs/2026-08-22-vrs-major-predictor-design.md Le design initial du simulateur

L'historique Git

Le dépôt porte la chronologie exacte de la campagne. Les commits qui jalonnent la partie modélisation, dans l'ordre :

Commit Horodatage (UTC) Objet
545e94f 24/08 08:36 Monte Carlo des tournois restants — le besoin de probabilités
5e9425c 24/08 18:40 Premier modèle appris, benchmarké contre Glicko
fbe621d 24/08 18:55 L'Elo à marge
3f5a0ed 24/08 20:05 Concours de modèles : six agents, trois familles
c607a9d 24/08 20:33 Missions scout et push
0a88d0d 25/08 03:57 Assaut final : 0.2054
a69a5a0 25/08 04:07 lastmile : 0.2044 et la carte des poches de prévisibilité
a46bf60 25/08 04:54 segmodel confirmé : 0.2041
3e54eef 25/08 05:35 Industrialisation du leader en production
9ce4864 25/08 06:05 Continuité des pages de résultats
c55bb97 25/08 06:59 Hypothèse « simple sur le segment dur » réfutée
a4f4a68 25/08 07:05 Sentinelle anti-patchwork
4be6253 25/08 07:41 Correctif de la fuite d'arrêt anticipé du modèle de repli
adfd8bc 25/08 08:11 Manches unifiées sur douze mois — et correction à la source du tri de tuples à dictionnaires
38fec04 25/08 08:23 Exclusion des 13 vainqueurs discordants de l'état d'économie
904744c 25/08 09:28 wtsm infirmé — clôture de la campagne

Les messages de ces commits contiennent des décompositions chiffrées qui ne figurent nulle part ailleurs — notamment les gains marginaux d'assault, les deux informations de campagne de lastmile, et le constat de clôture de 904744c : « troisième fois que l'unique passe holdout tranche contre elle en fin de campagne ».

Les chantiers ouverts à la clôture de rédaction

Ces dossiers ne contiennent clos après rédaction : couverture insuffisante (mapstats, 5,9 %) et non-viable (headless, Turnstile managed) — rapports dans scratch/ml/{mapstats,headless}/

Deux chantiers ont été lancés après la clôture de la campagne et n'avaient rien produit au moment où ces pages ont été écrites. Ils sont listés pour que le lecteur puisse aller voir s'ils ont abouti depuis — pas comme sources d'un chiffre de ce cours.

Dossier Objet État à la rédaction
scratch/ml/mapstats/ inventaire de la couverture archivée des pages de statistiques par carte, avant toute collecte massive script d'inventaire écrit, clos après rédaction : couverture insuffisante (mapstats, 5,9 %) et non-viable (headless, Turnstile managed) — rapports dans scratch/ml/{mapstats,headless}/
scratch/ml/headless/ sonde d'un navigateur sans interface contre la protection anti-robot dossier créé, clos après rédaction : couverture insuffisante (mapstats, 5,9 %) et non-viable (headless, Turnstile managed) — rapports dans scratch/ml/{mapstats,headless}/

2 · Sources de données externes

Statut : testées et documentées par la mission scout, avec les preuves dans scratch/ml/scout/report.json.

Sources exploitées

Source Accès Ce qu'elle a apporté
HLTV — https://www.hltv.org cache local de ~16 000 pages, aucune requête pendant la campagne résultats, compositions, statistiques par joueur, veto, scores par carte, historique de classement daté
bo3.gg — API REST publique, https://bo3.gg/api/v1 ouverte, sans clé, ~1 requête/seconde 209 482 manches détaillées (économie, pistolets, premiers kills, échanges, clutchs) et 40 023 matchs d'historique depuis janvier 2024
Wayback Machine — http://web.archive.org/cdx/search/cdx puis https://web.archive.org/web/<timestamp>id_/<url> ouverte, cadence volontairement lente 966 clichés datés de statistiques de carrière, contournant le blocage du sous-domaine de statistiques

Sources testées et écartées

Source Test effectué Verdict
HLTV /stats en direct six empreintes de navigateur récentes, plus session réchauffée avec cookies mort — 403 et challenge Cloudflare limité au chemin /stats/* ; il faudrait exécuter le JavaScript du challenge
m.hltv.org résolution DNS mort — même adresse IP que le site principal, pas de variante mobile
Liquipedia (API MediaWiki) requête action=parse avec agent identifiant joignable, mais faible valeur statistique face à bo3.gg ; à garder pour désambiguïser des compositions
PandaScore requête sans jeton clé requise ; les cotes sont réservées aux offres payantes. Le champ ps_id de bo3.gg rendrait l'intégration triviale le jour venu
esports-charts (escharts.com) requête directe mort — 403, et l'audience est de toute façon peu prédictive
Jeu de données ESTA (dépôt pnxenopoulos/esta) interrogation de l'API GitHub mort pour notre usage — données de l'ère CS:GO, aucun recouvrement avec notre fenêtre
Cotes dans le cache HTML recherche des motifs odds, bet, provider sur 30 pages de match mort — le mot n'apparaît que dans les commentaires de forum ; les cotes sont injectées en JavaScript géolocalisé

La source de cotes finalement retenue

Source Accès Ce qu'elle a apporté
bo3.gg, champ bet_updates du listing /api/v1/matches déjà sur disque, zéro requête réseau 1 428 matchs cotés d'avant-match de 2025-10 à 2026-08, cote décimale par équipe, identifiant d'équipe pour l'orientation

Trois précisions qui conditionnent l'usage de cette source. Elle mélange le marché d'avant-match (/en/line/) et le marché en direct (/en/live/), ce dernier étant une fuite du futur à mettre en quarantaine. Elle ne porte aucun horodatage : impossible de savoir s'il s'agit d'une cote d'ouverture ou de clôture. Et elle ne couvre qu'un opérateur, pas un consensus.

Le diagnostic de collecte a par ailleurs établi qu'il n'y a rien de plus à aller chercher chez cette source : aucun point d'accès dédié aux cotes n'existe, le détail d'un match ne porte pas d'autre information que le listing, et réinterroger trente matchs ne change rien.

Limite importante — ce que le verdict sur les cotes ne couvre pas

Le palier bookmaker n'est plus « sans données » : il est mesuré sur nos propres matchs. Mais la mesure porte sur un seul opérateur, des cotes non horodatées, un pool choisi par lui, et onze mois — et elle évalue une qualité probabiliste, jamais un rendement. Aucune stratégie de mise n'a été simulée, et la marge de 6 à 8 % de l'opérateur n'a pas été franchie.

3 · Littérature citée pendant la campagne

Statut : résultats et méthodes d'autres auteurs, cités par nom dans nos rapports et notre code.

Aucune URL n'est donnée ici, et c'est volontaire

Ces références sont citées par leur nom dans nos rapports et nos commentaires de code — vrs/predict.py, scratch/ml/push/mapfeats.py, scratch/ml/push/run.py — sans lien. Aucune URL n'a été inventée pour cette page : une référence bibliographique fabriquée serait pire que l'absence de référence.

Pour retrouver ces travaux, partez des noms et des chiffres ci-dessous.

Repères de performance

Mémoire universitaire de Lund sur CS2. Une régression logistique atteignant une log-loss de 0,62 et 65 % d'exactitude. Cité dans vrs/predict.py et enregistré dans data/winprob_report.json sous la clé lund_cs2_logreg. C'est le repère qui a confirmé deux fois que la frontière était quasi linéaire.

Étude CS:GO sur 11 271 matchs et 142 features. XGBoost identifié comme meilleur modèle, TrueSkill utilisé comme feature. Cité dans l'en-tête de vrs/predict.py. C'est cette référence qui a motivé l'exploration TrueSkill du concours — laquelle a produit la meilleure horloge du projet.

Bookmakers. Environ 68,7 % d'exactitude et 0,198 de Brier. Cité dans vrs/predict.py et dans data/winprob_report.json sous la clé bookmakers. Le même fichier prend soin de préciser que nos chiffres ne sont pas directement comparables : notre pool mêle tier 1 et tier 3.

Ce repère a depuis été remplacé, sur nos matchs, par une mesure directe : 0.2094 de Brier et 65,6 % d'exactitude pour un opérateur réel sur les 160 matchs cotés du holdout (scratch/ml/odds/report.json). Le chiffre de littérature reste cité dans ce cours, mais uniquement comme repère externe — jamais comme la barre de notre échantillon.

Méthodes appliquées

Elo à marge de victoire, façon FiveThirtyEight. Mise à jour modulée par \(\ln(1 + \text{marge})\) avec une correction d'autocorrélation en \(2{,}2 / (0{,}001 \cdot \text{diff} + 2{,}2)\). Recette issue des travaux de FiveThirtyEight sur le hockey (NHL), adaptée ici à la marge en manches par carte. Documentée en tête de scratch/ml/push/mapfeats.py. Adoptée.

pi-ratings, Constantinou & Fenton. Système de rating conçu pour prédire l'écart de score plutôt que la victoire, avec une mise à jour amortie en logarithme de l'erreur. Cité dans scratch/ml/push/mapfeats.py. Adopté — la feature pi_diff_a figure dans tous les leaders à partir de push.

Elo par surface, Tennis Abstract / Kovalchik. L'idée d'un rating par surface mélangé moitié-moitié avec un rating global, transposée ici à un Elo par carte mélangé avec un Elo toutes cartes. Citée dans scratch/ml/push/mapfeats.py. Adoptée sous forme d'horloge, mais la recomposition de série qui devait en découler a échoué.

GBDT→LR, Facebook 2014. Feuilles d'un petit ensemble d'arbres transformées en variables indicatrices, données à une régression logistique. Citée dans scratch/ml/push/run.py. Rejetée — 0.2405 et au-delà contre 0.2263 pour la logistique nue.

Modélisation à la manche. L'idée de modéliser l'issue de chaque manche puis de recomposer la série est une pratique répandue chez les fournisseurs de données esport, dont PandaScore. Elle a été testée sous deux formes ici (logistique de carte gagnée, logistique fractionnaire de manches avec course au premier à 13) et rejetée : 0.2303 à 0.2379 en validation, le veto attendu étant trop bruité. À noter : le projet n'a pas eu accès à une publication détaillant cette approche, seulement à sa description générale — c'est la référence la moins solidement établie de cette liste.

4 · Reproduire les mesures

Les commandes exactes figurent en tête de chaque script et dans les README des approches. Les points d'entrée principaux :

Objectif Commande
Reconstruire les features du leader python scratch/ml/assault/build_dataset.py (~15 min)
Rejouer le leader et ses segments python scratch/ml/segmodel/run_segmodel.py
Rejouer la réfutation de hardcore python scratch/ml/hardcore/run.py
Rejouer la fusion du concours python scratch/ml/final/run.py (~2 min)

Deux garde-fous sont incorporés à ces scripts et méritent d'être connus : le mode hors ligne est forcé à l'import (aucune requête ne peut partir), et chaque chantier commence par reproduire le résultat du leader précédent avec une assertion qui échoue si le chiffre ne retombe pas.


Retour aux annexes · Glossaire · Tableau récapitulatif