L'économie par round¶
C'est la famille la plus exotique du catalogue, la plus coûteuse à collecter, et celle qui a rapporté le moins. Elle mérite pourtant un chapitre entier — parce qu'elle est la seule à descendre sous le niveau du match, et parce que le raisonnement qui l'a motivée reste juste même si le résultat a déçu.
209 482 rounds téléchargés en 209 minutes. Trois colonnes retenues. Environ un à deux millièmes de Brier.
Ce qu'un round de CS2 contient¶
Avant de parler de features, il faut comprendre ce qu'on regarde.
Le round comme unité économique¶
Un match de Counter-Strike n'est pas une suite de rounds indépendants. C'est une chaîne économique. Chaque équipe démarre la manche avec un budget fixe, achète son équipement, joue le round, gagne ou perd de l'argent selon le résultat, et recommence. La manche se joue jusqu'à ce qu'une équipe atteigne 13 rounds gagnés — le code du projet borne d'ailleurs les écarts de score à \(\pm 13\) dans le calcul des pi-ratings.
Trois mécaniques structurent cette chaîne.
Le round pistolet. Le premier round de chaque mi-temps se joue avec un budget de départ identique pour tout le monde : personne n'a d'arme lourde, personne n'a de gilet complet. C'est le round le plus égalitaire de la manche — et le plus déterminant, parce que le vainqueur enchaîne avec un avantage économique qui dure plusieurs rounds.
Le bonus de défaite. Une équipe qui perd reçoit de l'argent, et ce montant augmente à
chaque défaite consécutive, puis se réinitialise à la première victoire. bo3.gg expose
directement ce compteur sous le nom loss_bonus_streak. C'est ce mécanisme qui empêche une
équipe menée de rester ruinée indéfiniment, et qui crée les situations décrites ci-dessous.
Les trois régimes d'achat. À chaque round, une équipe décide combien dépenser, et sa décision produit l'un de trois régimes :
- l'éco — on n'achète presque rien pour épargner et acheter complet au round suivant ;
- le full-buy — armes, utilitaires, gilets, l'équipement complet ;
- l'anti-éco — on est en full-buy face à une équipe en éco, et on doit convertir cet avantage matériel en round gagné.
Ces termes, ainsi que « clutch » et « trade », sont repris dans le glossaire.
Ces régimes ne sont pas annoncés dans les données. On les déduit de la valeur d'équipement, comme on va le voir.
Les champs que bo3.gg fournit¶
L'endpoint /games/<id> renvoie, pour chaque round et pour chaque équipe, un objet dont
voici les champs utiles :
| champ | signification |
|---|---|
equipment_value |
valeur totale de l'équipement de l'équipe au début du round |
enemy_equipment_value |
la même chose pour l'adversaire |
economy_level |
niveau économique catégorisé, avec son écart |
money_spent |
argent dépensé ce round |
money_save |
argent conservé |
loss_bonus_streak |
nombre de défaites consécutives en cours |
pistol_round |
booléen : est-ce un round pistolet |
first_kills, first_death |
l'équipe a-t-elle fait le premier kill, subi la première mort |
trade_kills |
kills de représailles immédiats |
clutch_attempts, clutches |
situations de un contre plusieurs tentées et réussies |
utility_value |
valeur des grenades achetées |
flash_assists |
assistances par aveuglement |
| poses / désamorçages | actions d'objectif |
end_reason |
comment le round s'est terminé |
win |
l'équipe a-t-elle gagné le round |
C'est une granularité qu'aucune page HLTV du cache ne fournit. Le rapport d'exploration résume : « exactement l'économie par round absente de notre cache ».
Intuition
Le score final d'un match dit qui a gagné. Le score par manche dit à quel point. Les rounds disent comment : cette équipe gagne-t-elle parce qu'elle a plus d'aim, ou parce qu'elle gère mieux son argent, ou parce qu'elle sauve les rounds désespérés en clutch ? Trois profils qui aboutissent au même 13-9 et qui ne se comportent pas de la même façon face au même adversaire.
Comment on en fait des features d'équipe¶
Le problème est le suivant : un round est un événement, une feature est un état. Il faut transformer une suite de 209 482 événements en un petit nombre de nombres par équipe, mis à jour dans le temps, sans jamais utiliser les rounds du match qu'on prédit.
Un état glissant par équipe¶
La solution est un objet EcoState par équipe, contenant huit files de longueur bornée. Une
file bornée est une fenêtre glissante gratuite : on pousse à la fin, la structure jette
automatiquement l'élément le plus ancien quand elle déborde.
| file | contenu | longueur | seuil minimum |
|---|---|---|---|
pistol |
victoire 0/1 des rounds pistolets | 30 | 6 |
dis |
victoire quand on est en désavantage d'équipement | 120 | 15 |
adv |
victoire quand on est en avantage d'équipement | 120 | 15 |
even |
victoire à équipement comparable | 120 | — |
fk |
l'équipe a fait le premier kill du round | 200 | 30 |
fkconv |
victoire sachant qu'on a fait le premier kill | 100 | 15 |
clutch |
réussite des tentatives de clutch | 60 | 8 |
won_money |
couples (victoire, argent dépensé) | 200 | — |
La colonne « seuil minimum » est essentielle. Un taux calculé sur trois observations est du
bruit ; le code refuse de produire une valeur tant que la file n'a pas assez d'éléments, et
renvoie NaN à la place :
def _wr(dq, min_n):
return sum(dq) / len(dq) if len(dq) >= min_n else NAN
S'y ajoute un verrou global : aucune feature économique n'est produite tant que les deux équipes n'ont pas au moins 50 rounds observés.
La classification des régimes¶
C'est le seul endroit du dispositif où l'on interprète les données plutôt que de les compter. Pour un round non-pistolet, on calcule la part d'équipement de l'équipe :
puis on classe :
Les rounds pistolets sont exclus de cette classification et comptés à part : leur équipement est identique par construction, ils pollueraient la file « équilibré » sans rien apprendre.
Exemple numérique. Une équipe entre dans un round avec 21 500 $ d'équipement contre
9 800 $ pour l'adversaire. \(\rho = 21500 / 31300 = 0{,}687\), donc au-dessus de 0,58 : c'est
un round d'anti-éco, il part dans la file adv. L'adversaire, lui, a
\(\rho = 9800/31300 = 0{,}313\), sous 0,42, et son round part dans sa propre file dis. Un
même round alimente donc deux files différentes, une par équipe.
Le choix de 0,42 et 0,58 mérite un commentaire : c'est une bande symétrique de 16 points autour de 0,5. Elle est assez large pour que les écarts d'achat mineurs — un AWP de plus, un gilet de moins — restent classés « équilibré », et assez étroite pour capter les vraies situations d'éco. Ce n'est pas un seuil optimisé ; c'est un seuil raisonnable choisi a priori, dans la même logique que la fenêtre \(W = 10\) des statistiques joueurs.
L'efficacité au dollar¶
La feature la plus originale de la famille, et l'une des trois retenues :
Le numérateur est le nombre de rounds gagnés sur les 200 derniers ; le dénominateur est l'argent total dépensé sur ces mêmes rounds, exprimé en tranches de 10 000 dollars. La feature répond donc à la question : combien de rounds cette équipe gagne-t-elle par tranche de 10 000 $ investis ?
Exemple numérique. Une équipe a gagné 104 de ses 200 derniers rounds en dépensant \(3\,600\,000\,\$\). Son efficacité vaut \(104 / 360 = 0{,}289\) round par tranche de 10 000 $. Une autre a gagné 96 rounds en dépensant \(2\,900\,000\,\$\) : \(96 / 290 = 0{,}331\). La seconde gagne moins de rounds mais les gagne moins cher — elle convertit mieux ses situations économiquement défavorables. La feature est la différence des deux : \(0{,}289 - 0{,}331 = -0{,}042\).
C'est exactement le genre de signal qu'aucune statistique de match ne contient. Deux équipes au même winrate de rounds peuvent avoir des efficacités très différentes.
Les huit features candidates¶
pour X parmi : pistol, dis, adv, fk, fkconv, clutch, eff. Plus une huitième,
eco_n_min \(= \log(1 + \min(n_a, n_b))\), qui est encore une fois une feature de fiabilité
— elle dit au modèle sur combien de rounds les sept autres reposent.
L'intégrité temporelle, encore¶
Les rounds d'un match sont appliqués à l'état après la featurisation de ce match. La docstring de la classe l'écrit en majuscules : « Rolling par équipe, mis à jour APRÈS featurisation du match (pas de fuite) ».
Et deux matchs sont exclus en dur du traitement, par leurs clés : ce sont les deux rencontres, sur 4 304, où le vainqueur selon bo3.gg diffère du vainqueur selon HLTV. On ne sait pas laquelle des deux sources a tort, donc on jette les deux lignes.
Ce que ça a rapporté¶
Voici les chiffres, sans arrangement.
Sur le jeu de validation¶
| configuration | Brier |
|---|---|
| base (horloges chaudes, 12 mois) | 0,2219 |
| + économie | 0,2215 |
| + warm-up bo3 | 0,2184 |
| + économie + warm-up bo3 | 0,2178 |
L'économie seule apporte 0,0004. Ajoutée par-dessus le warm-up, elle apporte 0,0006.
Sur le holdout de 1 146 matchs¶
| configuration | Brier | exactitude |
|---|---|---|
| reproduction du leader précédent (états froids) | 0,2153 | 64,6 % |
| horloges réchauffées | 0,2081 | 66,2 % |
| + fenêtre d'entraînement de 12 mois | 0,2078 | 66,3 % |
| + économie seule | 0,2064 | 66,7 % |
| + warm-up bo3 seul | 0,2063 | 66,4 % |
assault retenu en validation |
0,2054 | 66,8 % |
L'économie seule apporte 0,0014 de Brier et 0,4 point d'exactitude sur le holdout.
La sélection gloutonne¶
Sur les huit features candidates, une recherche gloutonne sur le jeu de validation en a
retenu trois : eco_clutch_diff, eco_adv_diff, eco_eff_diff. Elles sont accompagnées
de wmelo_diff dans la sélection finale à 46 features.
Cinq features ont été écartées : les rounds pistolets, les situations de désavantage, les premiers kills, leur conversion, et le compteur de fiabilité.
Le module de production a suivi : sa version de EcoState ne conserve que trois files sur
huit, avec le commentaire « sous-ensemble d'assault : seules les 3 features retenues ».
On ne calcule pas ce qu'on n'utilise pas.
À retenir
Un à deux millièmes de Brier pour cinq heures de collecte, un appariement à construire et valider, et une famille de huit features dont cinq sont mortes. C'est un rendement faible — mais il est positif et mesuré, ce qui le place au-dessus de trois autres chantiers de la campagne qui n'ont rien rapporté du tout.
Pourquoi si peu ?¶
Quatre explications, de la plus mécanique à la plus profonde.
La couverture¶
Sur 6 056 matchs, seuls 4 304 ont des rounds — 71 %. Sur les 29 % restants, les trois
colonnes valent NaN, ramenées à la moyenne du jeu de données après standardisation. Une
feature définie sur sept lignes sur dix ne peut pas déplacer une métrique globale autant
qu'une feature définie partout.
À cela s'ajoute le verrou des 50 rounds minimum par équipe, qui retire encore les débuts de fenêtre et les équipes rares. La couverture effective est donc inférieure à 71 %.
La redondance avec round_share_diff¶
C'est probablement l'explication principale. L'économie décrit comment une équipe gagne
ses rounds. Mais la feature round_share_diff, qui appartient à la famille maps, décrit déjà
combien de rounds elle gagne — et elle est la feature n°1 en importance dans le modèle
maps, devant l'Elo à marge.
Une équipe qui convertit bien ses anti-écos et qui gagne ses clutchs gagne, mécaniquement,
plus de rounds. Une part importante du signal économique est donc déjà comptabilisée, une
fois, sous une forme agrégée. Ce qui reste à eco_adv_diff est le résidu : la partie de la
compétence économique qui n'est pas déjà visible dans la part de rounds.
C'est exactement le même diagnostic que pour le H2H pondéré roster ou les boîtes « Past matches » : la nouvelle famille ne se bat pas contre le hasard, elle se bat contre les features déjà en place.
La stabilité du roster¶
Les fenêtres glissantes vont jusqu'à 200 rounds — soit environ quatre manches, donc deux à
trois matchs. Sur cette profondeur, le roster est généralement stable. Mais les files adv et
clutch remontent respectivement à 120 et 60 observations filtrées, ce qui, dans le temps
réel, peut couvrir plusieurs semaines et donc un ou deux changements de joueurs.
L'économie d'équipe est une compétence collective — elle dépend du in-game leader, des appels, de la discipline d'achat. C'est précisément la compétence qui change le plus quand un joueur change. Les features économiques mesurent donc parfois la gestion économique d'une équipe qui n'existe plus.
Le niveau d'agrégation¶
Le point le plus profond. On a pris 209 482 événements riches et on les a compressés en trois scalaires par équipe. Un taux de victoire en anti-éco est une moyenne : elle perd la séquence, la corrélation avec le score en cours, le fait qu'un anti-éco à 12-11 ne se joue pas comme un anti-éco à 3-1.
Autrement dit : on a utilisé des données de round pour fabriquer des features de match. Le niveau round n'a jamais été le niveau du modèle.
Pourquoi le niveau round reste prometteur¶
C'est la piste que la campagne n'a pas explorée, et l'argument est arithmétique.
Le volume disponible¶
| niveau | observations | par match |
|---|---|---|
| match | 4 304 | 1 |
| manche | 10 180 | 2,4 |
| round | 209 482 | 48,7 |
Modéliser au niveau de la manche multiplierait le nombre d'exemples d'entraînement par 2,4. Modéliser au niveau du round le multiplierait par près de 49.
Or le facteur limitant de toute la campagne a été la taille du jeu de données. Le plus gros gain enregistré — les horloges réchauffées, −0,0072 — est venu de plus d'historique. Le deuxième — la fenêtre d'entraînement portée de 6 à 12 mois, qui fait passer l'entraînement de 4 916 à 10 287 matchs — vient aussi de plus de données. Un modèle qui apprendrait sur 209 482 rounds au lieu de 10 287 matchs disposerait d'un budget d'exemples sans commune mesure.
La cible plus fine¶
Prédire un match, c'est prédire un bit. Prédire un round, c'est prédire un bit contextualisé par un état : score en cours, économie des deux camps, côté joué, numéro du round. L'information par observation est plus faible, mais la structure est beaucoup plus riche — et un modèle de round se recompose en probabilité de manche, puis de match, par simulation.
Le leader actuel fait exactement l'inverse : il prédit directement la série et le simulateur ne recompose rien par-dessus. C'est un choix, pas une fatalité.
Limite importante
Le facteur 49 est trompeur, et il faut le dire nettement. Les rounds d'une même manche ne sont pas indépendants : la chaîne économique lie chaque round au précédent, et le score en cours modifie la façon de jouer. La taille d'échantillon effective est donc très inférieure à 209 482 — probablement plus proche du nombre de manches que du nombre de rounds. Un modèle de round entraîné sans tenir compte de cette dépendance produirait des intervalles de confiance faussement étroits et une validation croisée mensongère si les découpes ne respectent pas les frontières de match.
Ce qui reste à faire, honnêtement¶
La campagne n'a jamais construit de modèle au niveau round. Ce qui précède est donc une hypothèse argumentée, pas un résultat. Ce qu'on sait avec certitude :
- la donnée existe, elle est collectée, validée, et stockée dans
rounds.pkl; - l'appariement avec nos matchs est vérifié sur trois contrôles indépendants ;
- le taux de parsing est mesuré par tier, de 94 % à 100 % ;
- agrégée en features de match, cette donnée rapporte un à deux millièmes de Brier.
Ce qu'on ne sait pas : ce qu'un modèle de round donnerait. Le chiffre n'existe pas, et il ne faut pas faire comme s'il existait.
Récapitulatif¶
209 482 rounds ──────────────────────────────────────────────┐
(bo3.gg, 10 180 manches, 4 304 matchs, 209 min de collecte) │
│
par round et par équipe : │
equipment_value / enemy_equipment_value ──┐ │
money_spent, loss_bonus_streak │ │
pistol_round │ classification │
first_kills, trade_kills │ ρ = eq/(eq+en) │
clutch_attempts / clutches │ <0,42 : dis │
utility_value, end_reason, win │ >0,58 : adv │
▼ │
8 files glissantes par équipe (30 à 200 obs., seuils 6 à 30) │
pistol · dis · adv · even · fk · fkconv · clutch · money │
│ │
▼ │
8 features différenciées ──► sélection gloutonne ──► 3 gardées│
eco_clutch_diff · eco_adv_diff · eco_eff_diff │
│ │
▼ │
holdout : 0,2078 ──► 0,2064 (−0,0014 de Brier) │
validation : 0,2219 ──► 0,2215 (−0,0004) │
│
piste non explorée : modéliser AU niveau round ───────────────┘
2,4× plus d'observations au niveau manche, 48,7× au round
⚠ mais rounds non indépendants dans une manche
Pour aller plus loin¶
Pourquoi ne pas avoir gardé eco_pistol_diff ? Les rounds pistolets sont réputés décisifs.
Ils le sont, mais la file pistol est la plus courte du dispositif : 30 observations, et
un seuil minimum de 6. Il y a deux rounds pistolets par manche, donc 30 observations
représentent une quinzaine de manches — assez pour un taux, pas assez pour un taux
stable. Un taux de victoire en pistolet calculé sur 30 rounds a un écart-type
d'environ 9 points de pourcentage sous l'hypothèse d'indépendance ; l'écart réel entre
deux équipes de niveaux voisins est plus petit que ce bruit. La sélection gloutonne l'a
donc écartée, et c'est cohérent.
La question suivante va dans l'autre sens : si le round est trop grossier, pourquoi ne pas descendre encore d'un cran ?
Les démos GOTV n'auraient-elles pas donné encore plus ?
bo3.gg fournit une demo_url pour de nombreux matchs, et il existe des parseurs de
démos matures. On y trouverait les positions, les trajectoires d'utilitaires, les temps de
rotation — infiniment plus riche que les agrégats par round. Mais le raisonnement de ce
chapitre s'appliquerait avec encore plus de force : plus la donnée est fine, plus il faut
d'ingéniosité pour la ramener à une feature de match qui ne soit pas déjà couverte par
round_share_diff. Une piste, à ouvrir seulement avec un modèle qui travaille au niveau
où la donnée vit.
Retour à l'introduction de cette partie, ou au catalogue complet des features.