Part Zero · Where the model started · 2021 NCAA TournamentPartie zéro · Là où tout a commencé · Tournoi NCAA 2021
Four days, seventeen spreadsheets, and a principal component analysis I had just learned how to run. I was in my first year of a statistics degree and brand new to R. Five years later I finally wrote the rule down as code, scored it against every game, and found out what those two axes were really made of.Quatre jours, dix-sept fichiers de stats et une analyse en composantes principales que je venais tout juste d’apprendre. J’étais en première année de statistiques et je débutais en R. Cinq ans plus tard, j’ai enfin écrit la règle sous forme de code, je l’ai confrontée à chaque match, et j’ai découvert de quoi ces deux axes étaient vraiment faits.
Part OnePartie un
March 2021, and I had four days. I was in my first year of a bachelor’s in statistics, I had just started programming in R, and PCA was brand new to me and felt like a superpower. So I went looking for data and spent most of that week just finding it: seventeen stat tables, one for every category I could track down, covering shooting, rebounds, assists, turnovers, fouls, what opponents did against you, and win-loss records. Thirty-three numbers per team, 68 teams. Then I threw the whole pile into a principal component analysis and plotted everybody on the first two components.
Mars 2021, et j’avais quatre jours. J’étais en première année de baccalauréat en statistiques, je commençais à peine à programmer en R, et l’ACP était toute nouvelle pour moi et me semblait être un superpouvoir. Je suis donc parti à la chasse aux données et j’ai passé presque toute la semaine à les trouver : dix-sept tableaux de statistiques, un pour chaque catégorie que je pouvais dénicher, couvrant les tirs, les rebonds, les passes, les revirements, les fautes, ce que les adversaires réussissaient contre toi et les fiches victoires-défaites. Trente-trois chiffres par équipe, 68 équipes. J’ai ensuite tout passé dans une analyse en composantes principales et placé chaque équipe sur les deux premières composantes.
Then came the part nobody teaches you: figuring out what the axes mean. PCA hands you two numbers per team and no labels. So I looked for teams I already understood. Gonzaga was way out on one end of the first axis, and Gonzaga was the most offense-oriented team in the country that year. Houston sat at one end of the second, and Houston was a Kelvin Sampson team, which meant defense first, defense second, defense always. That was my read: axis one is offense, axis two is defense.
Puis vient la partie que personne ne t’enseigne : comprendre ce que les axes veulent dire. L’ACP te donne deux nombres par équipe et aucune étiquette. J’ai donc cherché des équipes que je connaissais déjà. Gonzaga se trouvait tout au bout du premier axe, et Gonzaga était l’équipe la plus tournée vers l’attaque au pays cette année-là. Houston était à une extrémité du deuxième, et Houston, c’était une équipe de Kelvin Sampson : la défense d’abord, la défense ensuite, la défense toujours. Ma lecture était faite : axe un, l’attaque; axe deux, la défense.
Rebuilding it, that read holds up better than I had any right to expect. Gonzaga finished first of 68 in both points per game and effective field goal percentage. Houston finished first of 68 in opponent field goal percentage, which is the cleanest measure of a defense there is. Out of everybody in that field, I happened to anchor on the actual best offense and the actual best defense. Hold that thought, because it comes back to bite me later.
En reconstruisant le tout, cette lecture tient mieux que je n’aurais pu l’espérer. Gonzaga terminait premier sur 68 pour les points par match et pour la réussite effective. Houston terminait premier sur 68 pour le pourcentage de tir adverse, la mesure la plus propre d’une défense. De toutes les équipes du tournoi, j’étais tombé sur la meilleure attaque et la meilleure défense. Retiens ça, parce que ça va me revenir en pleine face plus loin.
Written down at last, the rule is one line. Flip both axes so bigger means better, then add them together.
Enfin couchée sur papier, la règle tient sur une ligne. On oriente les deux axes pour que « plus grand » veuille dire « meilleur », puis on additionne.
Both axes count the same, because that’s what your eye does when it looks at a chart. Nothing is tuned or weighted.
Les deux axes comptent également, parce que c’est ce que fait l’œil devant un graphique. Rien n’est ajusté ni pondéré.
One thing to be straight about before any of the numbers below: this rule is a reconstruction, and every score on this page belongs to the reconstruction, not to the bracket I actually submitted. The real one went up on CBS and it was a blend. I had the chart, and I also had a week of reading about these teams: who was hot coming in, who was banged up, which recent matchups meant something. The analytics were the new part I wanted to test, not the whole method.
Une précision avant les chiffres qui suivent : cette règle est une reconstruction, et tous les résultats de cette page appartiennent à la reconstruction, pas au pool que j’ai réellement soumis. Le vrai a été rempli sur CBS et c’était un mélange. J’avais le graphique, mais j’avais aussi une semaine de lectures sur ces équipes : qui était en feu à l’approche du tournoi, qui était blessé, quels duels récents voulaient dire quelque chose. Les statistiques étaient la nouveauté que je voulais tester, pas la méthode au complet.
Worth knowing before we go further: those two axes cover 20.9% and 19.3% of what actually separates these teams. Add the third and you’re at 54.7%. So I was making decisions off about 40% of the picture and cheerfully ignoring the rest.
À savoir avant d’aller plus loin : ces deux axes couvrent 20,9 % et 19,3 % de ce qui distingue vraiment ces équipes. Ajoute la troisième et tu montes à 54,7 %. Je prenais donc mes décisions avec environ 40 % du portrait, en ignorant joyeusement le reste.
Here it is. Teams are dots. The arrows are the stats, pointing toward the teams that pile them up. Gonzaga is the dot way out on the right with nobody near it, dragged there by every scoring arrow at once.
Le voici. Les équipes sont des points. Les flèches sont les statistiques, pointant vers les équipes qui les accumulent. Gonzaga, c’est le point tout à droite avec personne autour, tiré là par toutes les flèches offensives en même temps.
This one I made almost by accident, and it ended up mattering more than anything else in the project. Every stat is a row. The first three columns are wins, losses, and winning percentage. Blue means the stat goes up when that column goes up, red means it goes down, and bigger circles mean a stronger relationship. Stars mean don’t trust it.
Celui-là, je l’ai fait presque par accident, et il a fini par compter plus que tout le reste du projet. Chaque statistique est une rangée. Les trois premières colonnes sont les victoires, les défaites et le pourcentage de victoires. Le bleu veut dire que la stat monte quand la colonne monte, le rouge qu’elle descend, et les gros cercles indiquent un lien plus fort. Les étoiles veulent dire « ne t’y fie pas ».
Field goals made per game correlates with wins at +0.47 and with losses at −0.56. Shooting percentage: +0.43 and −0.58. Effective field goal percentage: +0.41 and −0.58. Points, assists, rebound margin, all the same shape. Make shots, win games. Not exactly a revelation, but nobody told the computer that. It sorted thirty-three columns into things that help and things that hurt on its own, and got it right.
Les paniers réussis par match sont corrélés aux victoires à +0,47 et aux défaites à −0,56. Le pourcentage de tir : +0,43 et −0,58. La réussite effective : +0,41 et −0,58. Les points, les passes, le différentiel de rebonds, même patron. Tu rentres tes tirs, tu gagnes. Pas une révélation, mais personne ne l’avait dit à l’ordinateur. Il a trié trente-trois colonnes entre ce qui aide et ce qui nuit tout seul, et il avait raison.
Now look at the defensive rows near the bottom. Opponent rebounds per game manages −0.34 against winning percentage. Opponent points, −0.30. Opponent shooting percentage, −0.26. Every defensive stat in the table is roughly half as connected to winning as basic shooting is.
Maintenant regarde les rangées défensives, vers le bas. Les rebonds adverses par match atteignent −0,34 contre le pourcentage de victoires. Les points adverses, −0,30. Le pourcentage de tir adverse, −0,26. Chaque statistique défensive du tableau est environ deux fois moins liée à la victoire que le simple fait de bien tirer.
That should have been a warning. My rule was giving offense and defense equal billing while the data sat there in two columns telling me it had a much firmer grip on one than the other. I did not pick up on it. I was four days into a project, a few months into R, and the chart looked great.
Ça aurait dû sonner l’alarme. Ma règle accordait le même poids à l’attaque et à la défense alors que les données me disaient, là, en deux colonnes, qu’elle maîtrisait bien mieux l’une que l’autre. Je n’ai rien vu. J’étais à quatre jours du début du projet, à quelques mois de mes débuts en R, et le graphique était beau.
The analysis produced a third component in 2021. I never plotted it. Here it is now. Drag it around.
L’analyse produisait une troisième composante en 2021. Je ne l’ai jamais tracée. La voici. Fais-la tourner.
Rotate it and Virginia and Loyola Chicago pull away from the pack on the vertical axis, even though they look completely ordinary on the flat version. That axis turned out to be the one measuring defense. In 2021 I was reading a flat photograph of a three-dimensional object and calling it analysis.
Fais-la pivoter et Virginia et Loyola Chicago se détachent du peloton sur l’axe vertical, alors qu’elles ont l’air parfaitement ordinaires sur la version plate. Cet axe-là, c’était celui qui mesurait la défense. En 2021, je lisais la photo plate d’un objet en trois dimensions et j’appelais ça de l’analyse.
Part TwoPartie deux
Rank all 68 teams by that one-line rule and you get a board. The top of it is legitimately impressive: Gonzaga first, Baylor third. Those two would play each other for the national championship three weeks later.
Classe les 68 équipes selon cette règle et tu obtiens un palmarès. Le sommet est franchement impressionnant : Gonzaga premier, Baylor troisième. Ces deux-là allaient s’affronter en finale nationale trois semaines plus tard.
Second place went to Liberty. A 13-seed. Ahead of the team that won the whole thing.
La deuxième place est allée à Liberty. Un 13e tête de série. Devant l’équipe qui a tout gagné.
In my defense, Liberty did score a lot of points. In the ASUN. Against ASUN teams. Colgate put up gaudy numbers in the Patriot League, UC Santa Barbara in the Big West, and my model treated all of it exactly the same as Baylor beating Kansas.
Pour ma défense, Liberty marquait beaucoup de points. Dans l’ASUN. Contre des équipes de l’ASUN. Colgate affichait de gros chiffres dans la Patriot League, UC Santa Barbara dans la Big West, et mon modèle traitait tout ça exactement comme Baylor battant Kansas.
Nobody had told it that conferences exist.
Personne ne lui avait dit que les conférences existent.
Part ThreePartie trois
In 2021 I filled out the bracket, watched the games, enjoyed the picks that hit, and never once added up the score. This model went five years without anybody knowing how good it was, me included.
En 2021, j’ai rempli mon pool, regardé les matchs, savouré les bons coups, et je n’ai jamais fait le total. Ce modèle a passé cinq ans sans que personne sache ce qu’il valait, moi le premier.
So: 39 right out of 66 games. 59.1%.
Alors voilà : 39 bons coups sur 66 matchs. 59,1 %.
If you had ignored all of this and just picked the better seed every time, you’d have gone 42 for 61. My model went 36 for 61 on those same games. It went against the seeds 24 times and won that argument 9 times.
Si tu avais ignoré tout ça et simplement choisi la meilleure tête de série chaque fois, tu aurais fait 42 sur 61. Mon modèle a fait 36 sur 61 sur ces mêmes matchs. Il s’est opposé aux têtes de série 24 fois et a gagné le débat 9 fois.
Gonzaga topped the board and deserved to. That team shot 61.0% effective field goal percentage, best in the field by two and a half points, and they walked into the final at 31-0 chasing the first undefeated season since Indiana in 1976.
Gonzaga dominait le classement et le méritait. Cette équipe affichait 61,0 % de réussite effective, la meilleure du tournoi par deux points et demi, et elle est entrée en finale avec une fiche de 31-0, à la poursuite de la première saison parfaite depuis Indiana en 1976.
My model liked them by 1.52 points of ODI. For scale, it liked Gonzaga over UCLA in the semifinal by 10.42. It was telling me this was the closest game of the tournament and I had no idea, because a 1.52 and a 10.42 came out of the pipeline looking identical. Baylor won 86-70 and it stopped being competitive around the eight-minute mark of the first half.
Mon modèle les favorisait par 1,52 point d’ODI. Pour comparer, il favorisait Gonzaga contre UCLA en demi-finale par 10,42. Il me disait que c’était le match le plus serré du tournoi et je n’en savais rien, parce qu’un 1,52 et un 10,42 sortaient de la machine avec exactement la même allure. Baylor a gagné 86-70 et ça a cessé d’être disputé vers la huitième minute de la première demie.
A 15-seed knocks off a 2-seed about once every four years. Oral Roberts did it in overtime, then beat Florida, then lost to Arkansas by two in the Sweet 16. My model had both of those wins.
Un 15e tête de série élimine un 2e environ une fois tous les quatre ans. Oral Roberts l’a fait en prolongation, puis a battu Florida, avant de perdre par deux points contre Arkansas en Sweet 16. Mon modèle avait ces deux victoires.
It had them because Oral Roberts scored a pile of points in the Summit League and my model didn’t know the Summit League from the NBA. The exact blindness that ranked Liberty second in America is what made it willing to back teams nobody else would touch. In 2021, a tournament with a record fourteen upsets, that turned out to be a pretty good way to be wrong.
Il les avait parce qu’Oral Roberts marquait un tas de points dans la Summit League et que mon modèle ne distinguait pas la Summit League de la NBA. L’aveuglement exact qui classait Liberty deuxième en Amérique est celui qui le rendait prêt à miser sur des équipes que personne d’autre ne touchait. En 2021, un tournoi avec un record de quatorze surprises, c’est devenu une plutôt bonne façon d’avoir tort.
Right at the bottom of the 2021 script, after everything else, sit six stray lines pulling up shooting numbers for Michigan and LSU. They look like leftover junk until you check the schedule.
Tout au bas du script de 2021, après le reste, se trouvent six lignes orphelines qui affichent les statistiques de tir de Michigan et LSU. On dirait des restes sans importance, jusqu’à ce qu’on vérifie le calendrier.
Michigan played LSU in the round of 32 on March 22, 2021. Those lines are the process in action: two teams pulled up side by side, compared by hand, the night before a real game. It is the same comparison this whole rebuild turns into a function, except back then it lived in my head and in six throwaway lines. The rule gives Michigan a 6.99 edge. Michigan won 86-78.
Michigan affrontait LSU au deuxième tour, le 22 mars 2021. Ces lignes, c’est le processus en action : deux équipes sorties côte à côte, comparées à la main, la veille d’un vrai match. C’est la comparaison exacte que cette reconstruction transforme en fonction, sauf qu’à l’époque elle vivait dans ma tête et dans six lignes jetables. La règle donne 6,99 d’avantage à Michigan. Michigan a gagné 86-78.
Part FourPartie quatre
That C is the interesting grade. When the model liked a team by more than 4 points of ODI it went 22 for 29, a solid 75.9%. On true coin flips under 1 point it went 5 for 10, which is honest work. But in the 1-to-2 range it went 3 for 10, worse than guessing. It knew what a blowout looked like and it knew what a toss-up looked like, and everything in between was noise wearing a number.
Ce C est la note intéressante. Quand le modèle favorisait une équipe par plus de 4 points d’ODI, il faisait 22 sur 29, un solide 75,9 %. Sur les vrais matchs serrés, sous 1 point, il faisait 5 sur 10, ce qui est honnête. Mais entre 1 et 2, il faisait 3 sur 10, pire que deviner. Il reconnaissait une raclée, il reconnaissait un match nul, et tout ce qui se trouvait entre les deux était du bruit déguisé en chiffre.
The first one was harmless. The defensive correlation plot fed one matrix five columns and the other four, so the significance stars landed on the wrong cells. R warned me about it. I did not read the warning.
Le premier était inoffensif. Le graphique de corrélation défensive donnait cinq colonnes à une matrice et quatre à l’autre, alors les étoiles de signification atterrissaient sur les mauvaises cases. R m’a averti. Je n’ai pas lu l’avertissement.
The second one was not harmless. The line calculating effective field goal percentage was doing math across two tables that had been filtered separately, and a merge had quietly re-sorted one of them into alphabetical order. So most teams got somebody else’s three-pointers mixed into their shooting numbers. Sixty-four teams out of sixty-eight. Average error 1.5 percentage points, worst case 7.8.
Le deuxième, non. La ligne qui calculait la réussite effective faisait des calculs entre deux tableaux filtrés séparément, et une fusion avait discrètement retrié l’un d’eux par ordre alphabétique. La plupart des équipes se retrouvaient donc avec les trois points de quelqu’un d’autre mélangés à leurs chiffres. Soixante-quatre équipes sur soixante-huit. Erreur moyenne de 1,5 point de pourcentage, maximum 7,8.
Gonzaga’s real number is 61.0%. My script said 65.0%, which would have been the best mark anybody had posted in the modern era by a mile. If I had ever printed that column and looked at it, I’d have caught it in about four seconds. But nothing in that script ever wrote anything to disk. Every number I produced lived in the RStudio plot window until I closed it, and then it was gone.
Le vrai chiffre de Gonzaga est 61,0 %. Mon script disait 65,0 %, ce qui aurait été de loin la meilleure marque de l’ère moderne. Si j’avais imprimé cette colonne une seule fois pour la regarder, je l’aurais vu en quatre secondes. Mais rien dans ce script n’écrivait quoi que ce soit sur le disque. Chaque chiffre que je produisais vivait dans la fenêtre graphique de RStudio jusqu’à ce que je la ferme, et puis il disparaissait.
Part FivePartie cinq
For five years I’ve told people the thing missing from this model was KenPom and strength of schedule. That’s true. It’s also not the real problem, which I only found by rebuilding the thing and checking what the axes were made of.
Pendant cinq ans, j’ai dit que ce qui manquait à ce modèle, c’était KenPom et la force du calendrier. C’est vrai. Ce n’est pas non plus le vrai problème, que j’ai découvert seulement en reconstruisant le tout et en vérifiant de quoi les axes étaient faits.
Minus zero point zero one. The stat that actually tells you whether a defense is good, meaning how well opponents shoot against it, has no relationship to my defense axis at all.
Moins zéro virgule zéro un. La statistique qui dit vraiment si une défense est bonne, soit l’efficacité des tirs adverses, n’a aucun lien avec mon axe défensif.
PC2 was measuring pace. High PC2 means a track meet: shots flying, rebounds everywhere, free throws, points on both ends, and worse shooting. Low PC2 means a slog. The two lowest teams on that axis in the whole field are Virginia and Loyola Chicago, which is the most 2021 sentence imaginable; those were the two grinders everybody complained about watching.
PC2 mesurait le rythme. Un PC2 élevé, c’est un match de course : tirs à profusion, rebonds partout, lancers francs, des points des deux côtés, et une efficacité moindre. Un PC2 faible, c’est un match de tranchées. Les deux équipes les plus basses sur cet axe sont Virginia et Loyola Chicago, ce qui est la phrase la plus 2021 possible; c’étaient les deux équipes que tout le monde trouvait pénibles à regarder.
And here is why I never caught it. Remember Houston, the team I used to name that axis? Houston really was the best defense in the field, first of 68 in opponent field goal percentage. Houston was also a Kelvin Sampson team, which means it played slowly on purpose. Elite defense and slow tempo, in the same team, in the same spot on the chart. My anchor sat exactly where a defense axis and a tempo axis would both put it, so it could not tell me which one I was looking at. If I had checked a fast team with a great defense, or a slow team with a bad one, the whole thing would have fallen apart in an afternoon.
Et voilà pourquoi je ne l’ai jamais vu. Tu te souviens de Houston, l’équipe qui m’a servi à nommer cet axe? Houston était vraiment la meilleure défense du tournoi, première sur 68 pour le pourcentage de tir adverse. Houston était aussi une équipe de Kelvin Sampson, donc lente par choix. Défense d’élite et rythme lent, dans la même équipe, au même endroit sur le graphique. Mon point de repère se trouvait exactement là où un axe défensif et un axe de rythme l’auraient tous les deux placé : impossible pour lui de me dire lequel des deux je regardais. Si j’avais vérifié une équipe rapide avec une bonne défense, ou une équipe lente avec une mauvaise, tout se serait effondré en un après-midi.
So the axis was real, it just wasn’t defense. Slow teams give up fewer points whether they defend well or not, and I’d built a model that couldn’t tell those two things apart. Actual defensive quality was sitting on PC3 the whole time, correlated with opponent shooting at +0.62, on the axis I never bothered to plot.
L’axe était donc réel, ce n’était simplement pas la défense. Les équipes lentes encaissent moins de points qu’elles défendent bien ou non, et j’avais bâti un modèle incapable de distinguer les deux. La vraie qualité défensive était sur PC3 depuis le début, corrélée aux tirs adverses à +0,62, sur l’axe que je n’ai jamais pris la peine de tracer.
Rate everything per possession instead of per game and the tempo confusion disappears. Adjust for who you played and Liberty stops being the second-best team in America. I could feel both of those holes in 2021 and couldn’t describe either one.
Calcule tout par possession plutôt que par match et la confusion de rythme disparaît. Ajuste selon l’adversaire et Liberty cesse d’être la deuxième meilleure équipe en Amérique. Je sentais ces deux trous en 2021 sans pouvoir décrire ni l’un ni l’autre.
Lesson OneLeçon un
This is the single biggest reason the 2026 model runs on KenPom and Barttorvik efficiency data instead of the raw per-game averages I used here.
C’est la principale raison pour laquelle le modèle 2026 roule sur les données d’efficacité de KenPom et de Barttorvik plutôt que sur les moyennes brutes par match que j’utilisais ici.
Lesson TwoLeçon deux
Five years without a number. The 2026 project has a backtester, a game-by-game ledger, and a post-mortem published the week the tournament ended.
Cinq ans sans un seul chiffre. Le projet 2026 a un test rétrospectif, un registre match par match, et un post-mortem publié la semaine de la fin du tournoi.
Lesson ThreeLeçon trois
A bug in 94% of my rows survived because every result I produced disappeared when I closed a window. Two hand-exported PDFs are all that’s left of the original run.
Un bogue touchant 94 % de mes lignes a survécu parce que chaque résultat disparaissait quand je fermais une fenêtre. Deux PDF exportés à la main sont tout ce qui reste de l’exécution originale.
Lesson FourLeçon quatre
A 1.52 and a 10.42 came out looking the same. The 2026 model outputs probabilities, which is why its post-mortem can talk about an 18.7% champion instead of a pick that failed.
Un 1,52 et un 10,42 sortaient pareils. Le modèle 2026 produit des probabilités, ce qui permet à son post-mortem de parler d’un champion à 18,7 % plutôt que d’un choix raté.
Lesson FiveLeçon cinq
I called PC2 defense because the loadings looked defensive if you glanced at them. One correlation would have caught it. That habit of confirming what a feature does instead of trusting its name is the thing I use most from this whole project.
J’ai appelé PC2 « défense » parce que les saturations en avaient l’air au premier coup d’œil. Une seule corrélation aurait suffi. Cette habitude de confirmer ce qu’une variable fait au lieu de se fier à son nom est ce que j’utilise le plus de tout ce projet.
Lesson SixLeçon six
Not knowing what a conference was cost me the bracket and won me Oral Roberts. That tension never really resolves; you just learn to price it. The 2026 model has a dedicated upset-leverage component because of what happened here.
Ignorer ce qu’était une conférence m’a coûté le pool et m’a donné Oral Roberts. Cette tension ne se résout jamais vraiment; on apprend juste à la tarifer. Le modèle 2026 a une composante dédiée aux paris à contre-courant à cause de ce qui s’est passé ici.
Five years between these two brackets. A chart I read with my eyes turned into an ensemble spitting out 132,134 probabilities. Every single upgrade along the way started as something this first attempt got wrong.
Cinq ans entre ces deux tableaux. Un graphique que je lisais à l’œil est devenu un ensemble crachant 132 134 probabilités. Chaque amélioration en chemin est partie d’une erreur de cette première tentative.
See where it ended up: March Madness 2026 →Voir l’aboutissement : March Madness 2026 →