Glicko et le RD figé¶
Mark Glickman, statisticien à Harvard, formule dans les années 1990 la critique la plus juste qu'on puisse faire à Elo : un rating sans barre d'erreur est un mensonge par omission.
Une équipe qui vient de jouer deux matchs et une équipe qui en a joué quatre-vingts portent toutes les deux « 1620 ». Le premier nombre est une supposition, le second une mesure. Elo les traite identiquement, et met à jour les deux avec le même \(K\).
Glicko corrige cela en donnant à chaque équipe deux nombres au lieu d'un. Ce chapitre explique le mécanisme, puis démontre que le système utilisé par Valve pour le classement VRS, malgré son nom, n'en profite pas du tout : avec son paramètre d'incertitude figé, c'est un Elo de \(K \approx 30{,}2\).
Deux nombres au lieu d'un¶
Glicko remplace le rating scalaire par un couple :
- \(r\) : le rating, même échelle qu'Elo, même 1500 au départ ;
- \(RD\) : le Rating Deviation, l'écart-type de l'incertitude sur \(r\).
L'interprétation est directement statistique : la force vraie de l'équipe se trouve avec 95 % de chances dans l'intervalle \(r \pm 2\,RD\). Une équipe à \(r = 1620\), \(RD = 50\) est « à peu près sûrement entre 1520 et 1720 ». La même à \(RD = 200\) est « entre 1220 et 2020 », c'est-à-dire nulle part.
RD petit (équipe bien connue) RD grand (équipe nouvelle)
▁▂▅█▅▂▁ ▁▁▂▂▃▃▃▃▃▂▂▁▁
1570 1620 1670 1220 1620 2020
Le \(RD\) fait deux choses, et elles sont symétriques :
Il grandit quand le temps passe. Une équipe qui n'a pas joué depuis trois mois est moins bien connue qu'après son dernier match — les rosters bougent, la forme change. Glicko réinjecte de l'incertitude en fonction de l'inactivité.
Il rétrécit quand on observe. Chaque match apporte de l'information, donc réduit \(RD\). Une équipe qui enchaîne les tournois voit son \(RD\) descendre vers un plancher.
Le facteur \(g\) : l'incertitude de l'adversaire atténue le signal¶
C'est l'ingrédient le plus élégant du système, et le seul que Valve conserve réellement.
Intuition d'abord. Vous battez une équipe dont on ne sait rien : son rating affiché dit 1500 mais il pourrait aussi bien valoir 1200 ou 1800. Que devez-vous conclure ? Peu de chose. À l'inverse, battre une équipe dont le rating de 1500 est établi sur soixante matchs, c'est une information nette.
Glicko formalise cela avec un facteur d'atténuation qui ne dépend que de l'incertitude de l'adversaire :
Les symboles :
- \(RD\) : l'incertitude de l'adversaire, en points de rating ;
- \(q\) : la constante de conversion entre l'échelle Elo (base 10, pas de 400) et l'échelle logistique naturelle (base \(e\)). Elle vaut \(\ln(10)/400\) ;
- \(\pi^2/3\) : la variance de la loi logistique standard, qui apparaît parce que Glicko approxime l'intégrale d'une logistique contre une gaussienne ;
- \(g(RD)\) : un nombre entre 0 et 1. Il vaut 1 quand \(RD = 0\) (adversaire parfaitement connu) et tend vers 0 quand \(RD\) explose.
L'espérance de victoire devient alors une logistique rétrécie par ce facteur :
C'est exactement la formule d'Elo, à ceci près que l'écart de rating est multiplié par \(g(RD_B) \le 1\). Un adversaire mal connu, c'est un écart de rating qu'on croit moins : la probabilité est tirée vers 0,5.
Exemple numérique : le \(g\) de Valve¶
Valve fixe \(RD = 75\) pour tout le monde (on y revient tout de suite). Calculons :
Concrètement : un écart réel de 300 points est traité comme un écart de \(0{,}97282 \times 300 = 291{,}8\) points.
| écart réel | \(E\) pur Elo | \(E\) avec \(g(75)\) |
|---|---|---|
| 0 | 0.5000 | 0.5000 |
| 100 | 0.6401 | 0.6365 |
| 300 | 0.8490 | 0.8429 |
L'effet est réel mais modeste : quelques millièmes. Retenez ce chiffre, 0,97282 — il revient dans la démonstration.
La mise à jour de Glicko¶
La règle complète, telle qu'elle est transcrite dans vrs/model.py
(fonction apply_match, port fidèle de glicko.js du dépôt de Valve) :
Les symboles :
- \(d^{-2}\) : l'information apportée par le match, au sens de l'information de Fisher. Elle est maximale quand \(E = 0{,}5\) (le match le plus incertain est le plus informatif) et s'annule aux extrêmes ;
- \(1/RD_A^2\) : la précision courante de \(A\), c'est-à-dire l'inverse de sa variance ;
- la fraction \(1/(1/RD_A^2 + d^{-2})\) : la variance après le match. C'est une mise à jour bayésienne classique : les précisions s'additionnent ;
- \(y - E\) : la surprise, exactement comme dans Elo.
Intuition
Le pas de mise à jour de Glicko est la variance a posteriori multipliée par la surprise. Une équipe très incertaine (\(RD\) grand, donc variance grande) bouge beaucoup ; une équipe bien établie bouge peu. Le \(K\) d'Elo, qui était une constante arbitraire, devient ici une quantité calculée — et différente pour chaque équipe.
Voilà pour Glicko en général. Passons à ce qu'en fait Valve.
Valve fige le RD à 75¶
Dans ranking.js du dépôt public de Valve, une seule ligne suffit à tout changer :
le \(RD\) minimum et le \(RD\) maximum sont réglés à la même valeur, 75. Notre port le
transcrit tel quel :
FIXED_RD = 75 # ranking.js:36 — RD figé : le Glicko se réduit à un Elo
et, dans la mise à jour :
for team, delta in deltas:
team.rank += delta
# RD figé : clamp(sqrt(adjusted)) retombe toujours sur FIXED_RD, donc pas de mise à jour.
La troisième équation de Glicko — celle qui met à jour \(RD\) — est calculée, puis son résultat est écrasé. Toutes les équipes portent 75, pour toujours, quel que soit leur nombre de matchs, quelle que soit leur inactivité.
Limite importante
Figer le \(RD\) ne « dégrade » pas légèrement Glicko : cela supprime la seule chose que Glicko ajoute à Elo. Le \(g\) survit, mais comme il est calculé sur un \(RD\) constant, c'est une constante lui aussi. Il ne reste plus qu'un rétrécissement uniforme de 2,7 % de l'échelle.
La démonstration : c'est un Elo de \(K \approx 30{,}2\)¶
Reprenons la formule de mise à jour et injectons \(RD_A = RD_B = 75\) partout.
Étape 1 — le facteur \(g\) devient une constante.
Étape 2 — la précision courante devient une constante.
Étape 3 — l'information du match, au cas le plus fréquent. Prenons le match équilibré, \(E = 0{,}5\), donc \(E(1-E) = 0{,}25\) :
Étape 4 — la variance a posteriori.
Étape 5 — le pas.
C'est littéralement la formule de mise à jour d'Elo, avec \(K = 30{,}17\).
La mesure : +15,08 points à \(p = 0{,}5\)¶
La vérification la plus parlante ne demande pas d'algèbre : on prend deux équipes à
1500 exactement, on applique un match, on regarde ce qui bouge. La fonction
apply_match de vrs/model.py donne :
Or, à \(E = 0{,}5\), la surprise vaut \(y - E = 0{,}5\). Donc :
Le nombre annoncé dans le journal de la campagne — « \(K\) effectif mesuré : 30,2, mise à jour symétrique » — est cette valeur-là.
Et le \(K\) n'est même pas tout à fait constant¶
Honnêteté oblige : \(d^{-2}\) dépend de \(E(1-E)\), donc \(K_{\text{eff}}\) varie légèrement avec le déséquilibre du match. Voici la mesure, en faisant varier l'écart de rating :
| écart \(r_A - r_B\) | \(E\) | \(\Delta\) si \(A\) gagne | \(K_{\text{eff}}\) |
|---|---|---|---|
| 0 | 0.5000 | +15,08 | 30,170 |
| 100 | 0.6365 | +11,00 | 30,265 |
| 300 | 0.8429 | +4,84 | 30,781 |
| \(\to \infty\) | \(\to 1\) | \(\to 0\) | 31,500 |
\(K_{\text{eff}}\) vit dans l'intervalle \([30{,}17\;;\;31{,}50]\) — une amplitude de 4 %. Autrement dit, le système de Valve est un Elo de \(K \approx 30\) dont le pas grossit imperceptiblement sur les matchs très déséquilibrés. Ce n'est pas rien conceptuellement (l'information de Fisher est plus faible sur un match joué d'avance, donc la variance a posteriori reste plus grande), mais numériquement c'est du bruit.
À retenir
Le Glicko de Valve à \(RD\) figé se réduit exactement à un Elo de \(K \approx 30{,}2\), à 4 % près. Les 15,08 points échangés à ratings égaux le prouvent en une ligne. Toute la machinerie bayésienne de Glickman est présente dans le code et neutralisée par une seule constante.
Une conséquence utile : la pondération par l'âge est un \(K\) variable¶
Le port ajoute un paramètre à apply_match : information_content, qui vaut la
pondération par l'âge du match (rampe linéaire sur la fenêtre de six mois). Dans les
formules, il multiplie \(g\) dans le numérateur et \(g^2\) dans \(d^{-2}\).
Comme \(d^{-2}\) est petit devant \(1/RD^2\), l'effet dominant est le numérateur : la
pondération par l'âge agit essentiellement comme un multiplicateur direct sur
\(K_{\text{eff}}\). Un match qui pèse 0,2 déplace cinq fois moins qu'un match récent.
C'est vérifié comme invariant dans _demo :
apply_match(fresh_w, fresh_l, 1.0)
apply_match(stale_w, stale_l, 0.2)
assert fresh_w.rank > stale_w.rank > 1500
Ce que Valve perd en figeant le RD¶
Quatre choses concrètes, et il vaut la peine de les nommer une par une.
L'équipe nouvelle est traitée comme une vétérane. Une équipe qui débarque avec cinq matchs disputés bouge d'exactement 30 points par match, comme une équipe qui en a joué cent. Elle mettra donc autant de temps que tout le monde à rejoindre son vrai niveau — alors qu'un vrai Glicko lui donnerait un \(RD\) élevé et la laisserait converger vite.
L'inactivité ne coûte rien. Une équipe qui disparaît trois mois garde son rating intact et sa « confiance » intacte. Rien ne signale que ce rating est périmé. Notre Glicko-2 du chapitre 4 gonfle explicitement l'incertitude proportionnellement au temps écoulé.
Le changement de roster est invisible. Trois joueurs sur cinq partent, l'entité garde son nombre. C'est le problème que TrueSkill règle en changeant carrément d'objet suivi.
Les probabilités ne peuvent pas exprimer un doute. Comme \(g\) est constant, l'atténuation est la même pour tout le monde. Le système ne peut jamais dire « je ne sais pas » sur un match particulier ; il ne peut dire que « c'est serré ».
Erreur fréquente
En dire du mal serait manquer le sujet. Le VRS de Valve sert à répartir des invitations au Major : il doit être stable, auditable et peu sensible aux accidents. Un \(RD\) figé garantit qu'aucune équipe ne peut faire un bond de 150 points sur un tournoi, et qu'un observateur extérieur peut recalculer le classement sans connaître l'historique d'incertitude de chacun. Ce sont de très bonnes propriétés — pour un classement. Pas pour un prédicteur.
Le chiffre qui compte¶
Sur notre holdout de 1 146 matchs, le Glicko de Valve utilisé en prédicteur pur donne :
| accuracy | Brier | log-loss | |
|---|---|---|---|
| Glicko de Valve (\(RD = 75\)) | 56,0 % | 0.2422 | 0.6772 |
C'est la baseline de tout le cours : le point de départ contre lequel chaque idée ultérieure est mesurée. Un modèle qui annoncerait 0,5 partout obtiendrait 0.2500 de Brier et 50 % d'accuracy environ ; la baseline fait donc mieux, mais pas énormément mieux.
Deux chapitres plus loin, le même mécanisme avec un \(RD\) vivant — notre Glicko-2 — descend à 0.2365, et TrueSkill à 0.2354. Ces 0,006 à 0,007 de Brier sont le prix, mesuré chez nous, d'avoir tué l'incertitude.
Mais avant l'incertitude, il y a plus simple et plus rentable : l'information que personne n'utilise et qui est déjà dans les données. C'est le chapitre 3.