<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Aditya Chaubey — AI Daily</title><description>One AI concept a day, explained in plain language.</description><link>https://readitya.com/</link><item><title>What a Matmul Actually Costs</title><link>https://readitya.com/ai/2026-10-30-what-a-matmul-actually-costs/</link><guid isPermaLink="true">https://readitya.com/ai/2026-10-30-what-a-matmul-actually-costs/</guid><description>A matrix multiply pays two bills at once, one in arithmetic and one in memory traffic. The arithmetic depends only on three integers. The memory usually decides the clock.</description><pubDate>Fri, 30 Oct 2026 03:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Take a 4,096 by 4,096 matrix of weights. Push 128 token vectors through it in half precision, on an A100.&lt;/p&gt;
&lt;p&gt;The arithmetic is easy to count. Every output value is a dot product of length 4,096, and there are 128 by 4,096 of them. So the card has 4.3 billion multiply-adds to chew through. Spread over its rated 312 trillion operations a second, that is 13.8 microseconds.&lt;/p&gt;
&lt;p&gt;Then you run it, and it takes about 17.5 microseconds.&lt;/p&gt;
&lt;p&gt;For one afternoon the gap looks like launch overhead, or the operating system, or whatever your profiler labels as noise. Then you run the same multiply on a shape half a percent larger, and it takes twice as long. The floating point count did not move nearly enough to explain that.&lt;/p&gt;
&lt;p&gt;Two bills arrive at once here. Neither of them is the arithmetic you just counted.&lt;/p&gt;
&lt;h2 id=&quot;the-first-bill&quot;&gt;The first bill&lt;/h2&gt;
&lt;p&gt;A multiply of an m by k matrix with a k by n matrix has a cost you can write down. It is &lt;code&gt;2 × m × n × k&lt;/code&gt; floating point operations.&lt;/p&gt;
&lt;p&gt;The 2 is honest. Each output value is a dot product of length k, which takes k multiply-adds, and hardware fuses each pair into one instruction. NVIDIA’s performance guide counts the fused operation as two, because the multiply and the add are both real work on real numbers.&lt;/p&gt;
&lt;p&gt;Sit with what that formula can see. It takes three integers. It cannot see the values inside the arrays.&lt;/p&gt;
&lt;p&gt;Multiply matrices full of random noise, and you get that bill. Multiply matrices full of the number one, and you get the same bill. Multiply matrices that are ninety percent zeros, and you get the same bill again.&lt;/p&gt;
&lt;p&gt;That last case makes people stumble. A sparse matrix is not cheaper to multiply unless the chip is built to notice the zeros. NVIDIA’s A100 datasheet lists 312 TFLOPS for half precision, and 624 with an asterisk for sparsity. The second number describes a card that can prove half the weights are zeros, and then decline to multiply them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ai/ai-2026-10-30-matmul-diagram.png&quot; alt=&quot;Each entry of the output is one row of the first matrix meeting one column of the second&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Every output entry is a dot product of length k, and there are m times n of them. That is where &lt;code&gt;2 × m × n × k&lt;/code&gt; comes from. Image: User1042, CC BY-SA 4.0, via Wikimedia Commons.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-second-bill&quot;&gt;The second bill&lt;/h2&gt;
&lt;p&gt;The arithmetic is only half of it. Every number the chip multiplies has to arrive from memory first, and memory is a slower road than the arithmetic units beside it.&lt;/p&gt;
&lt;p&gt;Count the arrivals for one multiply. The inputs are m by k and k by n. The output is m by n. If nothing is reused from cache, that is &lt;code&gt;m×k + k×n + m×n&lt;/code&gt; values read or written, whatever their size in bytes.&lt;/p&gt;
&lt;p&gt;Divide the two and you get a ratio with a name. Arithmetic intensity for a matmul works out to &lt;code&gt;m×n×k / (m×k + k×n + m×n)&lt;/code&gt;. NVIDIA prints that same expression in their guide, and works two examples. Their 8192 by 128 by 8192 case scores 124. Their 8192 by 8192 by 8192 case scores 2,730.&lt;/p&gt;
&lt;p&gt;Now you need something to compare it against, and that number belongs to the card rather than the problem. Take peak arithmetic and divide by peak bandwidth. The A100 with 80 gigabytes runs at 312 TFLOPS and 2,039 gigabytes a second, so &lt;code&gt;312e12 / 2.039e12&lt;/code&gt; gives 153.&lt;/p&gt;
&lt;p&gt;That 153 is flops per byte. Above it, arithmetic limits you. Below it, memory does.&lt;/p&gt;
&lt;p&gt;The idea is old and has a good name. Samuel Williams, Andrew Waterman and David Patterson published it as the roofline model in 2009. The flat part of the roof is the arithmetic you cannot exceed. The sloped part is the memory you cannot feed any faster.&lt;/p&gt;
&lt;p&gt;Our 128-token multiply lands at 120 flops per byte. That is under 153, so memory sets the pace. Count the bytes and you get 35.7 megabytes moving, which at 2,039 gigabytes a second takes 17.5 microseconds. That is the number the stopwatch gave us. The arithmetic was never the constraint.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ai/ai-2026-10-30-matmul-1.png&quot; alt=&quot;A curve rising steeply and then flattening at 312 TFLOPS&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The same 4,096-wide layer, pushed harder. Attainable throughput climbs almost linearly until the batch clears about 165 tokens, then the card is full however many tokens you add.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There is a clean consequence. A square half-precision matmul needs a side of at least 459, since &lt;code&gt;3 × 153 = 459&lt;/code&gt;, before arithmetic becomes the limit. Anything smaller cannot reach peak, however good the code.&lt;/p&gt;
&lt;p&gt;And a matrix times a single vector, the case where n is 1, has an intensity below 1. That is a model generating one token at a time. Its ceiling on this card works out to about 2 TFLOPS out of 312, because the processors spend nearly all their time waiting for weights to arrive. This is the entire reason batching exists.&lt;/p&gt;
&lt;h2 id=&quot;the-cliff&quot;&gt;The cliff&lt;/h2&gt;
&lt;p&gt;Now the shape that breaks the stopwatch, and intensity has nothing to do with it.&lt;/p&gt;
&lt;p&gt;An A100 has 108 streaming multiprocessors. cuBLAS cuts the output into tiles, and its preferred tile is 256 by 128. Fix m at 2,304. That divides into nine tiles down the columns.&lt;/p&gt;
&lt;p&gt;Set n to 1,536. Across the rows you get twelve tiles, and &lt;code&gt;9 × 12 = 108&lt;/code&gt;. One wave of tiles, every processor busy, nothing left over.&lt;/p&gt;
&lt;p&gt;Set n to 1,544, which is eight columns more. Now you get thirteen tiles across and 117 in total. One full wave, then a tail wave of nine tiles using 9 of the 108 processors. NVIDIA measured this and reports that throughput roughly halves, while duration roughly doubles. Half a percent more work, twice the clock.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ai/ai-2026-10-30-matmul-2.png&quot; alt=&quot;Four bars, 108, 117, 216 and 225, for output widths 1536, 1544, 3072 and 3080&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Tile counts for m = 2,304 with 256 by 128 tiles. 108 fills one wave exactly. 117 needs a second wave, and only nine of its tiles have work to do.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There is a smaller version of the same trap. With 128 by 128 tiles, two dimensions that miss the boundary by a little make the hardware run 1.5 times the arithmetic the maths needs. The problem itself is 0.39 percent bigger.&lt;/p&gt;
&lt;p&gt;None of this shows up in the flop count. All of it shows up in the shape.&lt;/p&gt;
&lt;h2 id=&quot;ten-times-the-bill-for-the-same-answer&quot;&gt;Ten times the bill for the same answer&lt;/h2&gt;
&lt;p&gt;Matrix multiplication is associative, so a chain of them can be bracketed any way you like. The result is the same. The cost is not.&lt;/p&gt;
&lt;p&gt;Take three matrices of size 10 by 100, 100 by 5, and 5 by 50. Bracket them as &lt;code&gt;(A × B) × C&lt;/code&gt; and you do 5,000 multiplications, get a 10 by 5 result, then spend 2,500 more. Total, 7,500.&lt;/p&gt;
&lt;p&gt;Bracket the same three as &lt;code&gt;A × (B × C)&lt;/code&gt; and you do 25,000 multiplications to build a 100 by 50 middle, then 50,000 more to finish. Total, 75,000.&lt;/p&gt;
&lt;p&gt;Same answer, ten times the bill. Cormen, Leiserson, Rivest and Stein use exactly this chain, and call the first order “10 times faster”.&lt;/p&gt;
&lt;p&gt;The cost of a matmul is a function of its shapes and its brackets. The values never enter.&lt;/p&gt;
&lt;h2 id=&quot;where-a-training-runs-bill-goes&quot;&gt;Where a training run’s bill goes&lt;/h2&gt;
&lt;p&gt;Put enough matmuls together and you get a language model, and the count stays just as simple.&lt;/p&gt;
&lt;p&gt;One parameter touches one token in the forward pass and costs two flops. The backward pass needs twice that, which is four. So training costs about six flops per parameter per token, written &lt;code&gt;6 × N × D&lt;/code&gt;. The OpenAI scaling laws paper of 2020 put it as &lt;code&gt;C ≈ 6NBS&lt;/code&gt; and named the 6 outright: the forward and backward passes.&lt;/p&gt;
&lt;p&gt;Chinchilla is the tidy example. Seventy billion parameters, 1.4 trillion tokens, so &lt;code&gt;6 × 70e9 × 1.4e12&lt;/code&gt;, which is 5.9e23 flops. Gopher was four times larger and burned a near-identical budget. The smaller model won nearly every benchmark.&lt;/p&gt;
&lt;p&gt;That rule has a hole, and the people who wrote it said so. Kaplan and his coauthors admit that their estimate “did not include contributions proportional to n_ctx”. They warn that the scaling may be confounded once context length climbs past roughly twelve times the model width.&lt;/p&gt;
&lt;p&gt;Here is how slowly that arrives. Attention’s cost grows with the square of the context. The JAX scaling guide derives the ratio of attention flops to the rest as &lt;code&gt;T / 8D&lt;/code&gt;, with T the context and D the model width. For a width of 4,096, attention only overtakes the dense layers at 32,768 tokens. At a width of 8,192, it takes 65,536.&lt;/p&gt;
&lt;p&gt;The quadratic blowup is real. It arrives at the context lengths people were arguing about in 2026, rather than the ones most of us train at.&lt;/p&gt;
&lt;h2 id=&quot;what-the-clock-is-made-of&quot;&gt;What the clock is made of&lt;/h2&gt;
&lt;p&gt;Go back to the 4,096 by 4,096 matrix and the 128 tokens, and the 17.5 microseconds.&lt;/p&gt;
&lt;p&gt;You could rewrite every value in those two arrays and the time would not move by a nanosecond. You could fill them with zeros. You could multiply them in a different language, on a better compiler, and shave a little off. The values are free.&lt;/p&gt;
&lt;p&gt;Change the shapes, and the bill moves by a factor of ten. Change the brackets, and it moves again. Round the dimensions up to the tile boundary, and it halves.&lt;/p&gt;
&lt;p&gt;A matmul costs what it is shaped like.&lt;/p&gt;
</content:encoded><category>foundations</category><category>gpu</category><category>performance</category><category>flops</category></item><item><title>How to Split Your Data Without Lying to Yourself</title><link>https://readitya.com/ai/2026-10-28-how-to-split-data-without-lying-to-yourself/</link><guid isPermaLink="true">https://readitya.com/ai/2026-10-28-how-to-split-data-without-lying-to-yourself/</guid><description>A cross-validation score is a promise about a future you have not seen. The split decides which future, and the quiet ways it goes wrong all break one rule.</description><pubDate>Wed, 28 Oct 2026 03:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Priya has repaired laptops from the room above the shop for two years. She has 240 enquiries to show for it, from sixty customers, because most people come back.&lt;/p&gt;
&lt;p&gt;She wants one thing from those messages: a guess, made before she quotes, about whether a customer will approve the repair or flinch at the price and go quiet.&lt;/p&gt;
&lt;p&gt;So she does what every tutorial says. She writes each enquiry down next to what happened next. She holds back every fifth message, trains a small model on the other four fifths, and scores it on the ones it never saw. Then she rotates which fifth is held back, four more times, and averages the five scores.&lt;/p&gt;
&lt;p&gt;The number comes back good. It is also wrong, and the model is not what went wrong.&lt;/p&gt;
&lt;p&gt;Her sixty customers sent four messages each on average. When she deals the messages out like cards, a held-out message usually has siblings in the training pile. Take one held-out message: three other messages from that customer exist somewhere, and the chance that at least one of them sits in the 192 rows used for training works out to this.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;1 - (47 × 46 × 45) / (239 × 238 × 237) = 0.993&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Ninety-nine point three percent. The model is almost never asked about a stranger.&lt;/p&gt;
&lt;h2 id=&quot;the-loop-and-the-one-rule-inside-it&quot;&gt;The loop, and the one rule inside it&lt;/h2&gt;
&lt;p&gt;Cross-validation rests on a small idea. You cannot test a model on the data that taught it, so you take turns.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ai/ai-2026-10-28-cv-fold.jpg&quot; alt=&quot;Four folds of one dataset, each taking a turn as the test set while the other three train the model&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The same data, four times over. Each fold takes its turn as the test set while the other three train, and the four scores get averaged. Image: Joan.domenech91, CC BY-SA 3.0, via Wikimedia Commons.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Five folds means five passes. Forty-eight messages are held out each time, a hundred and ninety-two train, and every message is held out exactly once. The code is four lines.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes gruvbox-light-medium gruvbox-dark-medium&quot; style=&quot;background-color:#fbf1c7;--shiki-dark-bg:#282828;color:#3c3836;--shiki-dark:#ebdbb2; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9D0006;--shiki-dark:#FB4934&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#3C3836;--shiki-dark:#EBDBB2&quot;&gt; sklearn&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#3C3836;--shiki-dark:#EBDBB2&quot;&gt;model_selection &lt;/span&gt;&lt;span style=&quot;color:#9D0006;--shiki-dark:#FB4934&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#3C3836;--shiki-dark:#EBDBB2&quot;&gt; cross_val_score&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9D0006;--shiki-dark:#FB4934&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#3C3836;--shiki-dark:#EBDBB2&quot;&gt; sklearn&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#3C3836;--shiki-dark:#EBDBB2&quot;&gt;neighbors &lt;/span&gt;&lt;span style=&quot;color:#9D0006;--shiki-dark:#FB4934&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#3C3836;--shiki-dark:#EBDBB2&quot;&gt; KNeighborsClassifier&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#3C3836;--shiki-dark:#EBDBB2&quot;&gt;scores &lt;/span&gt;&lt;span style=&quot;color:#427B58;--shiki-dark:#8EC07C&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#076678;--shiki-dark:#83A598&quot;&gt; cross_val_score&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#076678;--shiki-dark:#83A598&quot;&gt;KNeighborsClassifier&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#8F3F71;--shiki-dark:#D3869B&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;),&lt;/span&gt;&lt;span style=&quot;color:#504945;--shiki-dark:#D5C4A1&quot;&gt; X&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#504945;--shiki-dark:#D5C4A1&quot;&gt; y&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#076678;--shiki-dark:#83A598&quot;&gt; cv&lt;/span&gt;&lt;span style=&quot;color:#427B58;--shiki-dark:#8EC07C&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#8F3F71;--shiki-dark:#D3869B&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#AF3A03;--shiki-dark:#FE8019&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#504945;--shiki-dark:#D5C4A1&quot;&gt;scores&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#076678;--shiki-dark:#83A598&quot;&gt;mean&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;(),&lt;/span&gt;&lt;span style=&quot;color:#504945;--shiki-dark:#D5C4A1&quot;&gt; scores&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#076678;--shiki-dark:#83A598&quot;&gt;std&lt;/span&gt;&lt;span style=&quot;color:#7C6F64;--shiki-dark:#A89984&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rule that makes those numbers mean anything is smaller than the machinery. &lt;mark&gt;Everything the model learns, it has to learn again inside each fold, from the training part only&lt;/mark&gt;.&lt;/p&gt;
&lt;p&gt;Scaling, feature selection, the number of neighbours, the decision threshold, the cleaning steps you chose after looking at the data. All of it belongs inside the loop. Move one step outside and the fold stops being a test.&lt;/p&gt;
&lt;h2 id=&quot;why-five-folds-and-not-one&quot;&gt;Why five folds, and not one&lt;/h2&gt;
&lt;p&gt;A single split gives you one number from one arrangement of the data. Deal the cards again and it moves, often by several points. Averaging five arrangements costs five trainings and buys most of the stability you need.&lt;/p&gt;
&lt;p&gt;You could go further and hold out one row at a time. Leave-one-out trains on 239 rows instead of 192, so it squeezes more value from a small dataset, and on paper it is almost unbiased.&lt;/p&gt;
&lt;p&gt;It fails in a way worth seeing. Ron Kohavi trained two classifiers over half a million times on real datasets and found that ten-fold stratified cross-validation beat leave-one-out for choosing between models, even when computation was free.&lt;/p&gt;
&lt;p&gt;His sharpest example is a trick rather than a benchmark. Take Fisher’s iris, fifty flowers of each of three species, and give it a classifier whose only rule is: predict the most common label in the training set.&lt;/p&gt;
&lt;p&gt;On the full dataset that rule scores about 33 percent. Now remove one flower at a time. Remove a setosa and the training set still holds fifty versicolor and fifty virginica, so setosa is no longer the largest class. The classifier predicts the wrong species for that flower, and for every other flower too.&lt;/p&gt;
&lt;p&gt;Leave-one-out reports zero percent accuracy for the majority rule on iris.&lt;/p&gt;
&lt;p&gt;Then it reports zero variance across the folds, and that is the part that should bother you. The estimate arrives with a confident spread of literally nothing.&lt;/p&gt;
&lt;h2 id=&quot;when-the-shuffle-lies&quot;&gt;When the shuffle lies&lt;/h2&gt;
&lt;p&gt;One library document says the quiet part out loud. scikit-learn’s guide calls the assumption behind shuffling “Independent and Identically Distributed”, and spells it out: every sample comes from the same process, “and the generative process is assumed to have no memory of past generated samples.”&lt;/p&gt;
&lt;p&gt;Priya’s data has memory. Every message remembers the customer who typed it.&lt;/p&gt;
&lt;p&gt;The fix is to split on the thing that repeats. &lt;code&gt;GroupKFold&lt;/code&gt; takes a column of group ids and keeps each group whole, so a customer’s four messages all land on the same side of the wall.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ai/ai-2026-10-28-cv-group-gap.png&quot; alt=&quot;Three bars: 73 percent with shuffled folds, 51 percent split by customer, 50 percent on sixty unseen customers&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A version of Priya’s problem built to test this: sixty customers, four messages each, a nearest-neighbour model, two hundred repeats of the whole experiment. Shuffled folds scored 73 percent. Splitting by customer scored 51, and sixty customers the model had never met scored 50.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The gap was recognition doing the work, not knowledge. The model had learned to tell one regular apart from another, and a new customer is nobody it has met.&lt;/p&gt;
&lt;p&gt;This is not a corner case. In 2023, Sayash Kapoor and Arvind Narayanan surveyed the published reviews and found data leakage in 294 papers across 17 scientific fields. They sorted it into eight kinds. In the civil war prediction literature, where newer models were reported to beat logistic regression outright, they re-ran the comparisons with the leakage removed. The difference in ranking quality between the complex models and the old regression fell from 0.14 to 0.01.&lt;/p&gt;
&lt;h2 id=&quot;when-the-shuffle-lies-twice-time&quot;&gt;When the shuffle lies twice: time&lt;/h2&gt;
&lt;p&gt;Time has the same memory problem, in a form shuffling cannot see.&lt;/p&gt;
&lt;p&gt;scikit-learn is blunt about it. Classic folds on time series data “would result in unreasonable correlation between training and testing instances”, producing poor estimates, and the right test is always the future observations “least like those that are used to train the model”.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TimeSeriesSplit&lt;/code&gt; does this by growing the training window. The first fold trains on January and tests on February. The second trains on January and February and tests on March. Nothing ever runs backwards, so the model never gets to read next week’s news and then predict this week.&lt;/p&gt;
&lt;h2 id=&quot;the-number-under-the-number&quot;&gt;The number under the number&lt;/h2&gt;
&lt;p&gt;Suppose the split is right, the groups are whole and the order is honest. The score is still an estimate from a sample, and a sample has a width.&lt;/p&gt;
&lt;p&gt;Gaël Varoquaux measured that width directly. He ran cross-validation on simulated data of known difficulty, then compared the estimate against the accuracy on ten thousand fresh points. At thirty samples, ninety percent of the errors fell within about nineteen percentage points of the truth. At a hundred samples the spread narrowed to nine. At a thousand, to three.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ai/ai-2026-10-28-cv-errorbars.png&quot; alt=&quot;A line falling from nineteen percentage points at thirty samples to three at a thousand&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;How far a cross-validation estimate misses, from Varoquaux’s simulations: about nineteen points at thirty samples, nine at a hundred, seven at two hundred, six at three hundred and three at a thousand.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The spread you get by averaging across folds does not show this. Varoquaux’s summary is that the standard error across folds “strongly underestimates” the real error, because the folds share a training set and their mistakes travel together.&lt;/p&gt;
&lt;p&gt;Some of the width is pure arithmetic, and it belongs to nobody’s model. Predicting a class at 75 percent accuracy, measured on a hundred test items, has a standard deviation of 4.3 points from sampling alone. A 95 percent interval around that 75 percent is 17 points wide. On thirty test items it is 31 points wide.&lt;/p&gt;
&lt;p&gt;Real datasets behave the same way. In a Kaggle competition on brain scans of schizophrenia patients, the gap between a method’s score on the public and private test sets ran to about 15 points. And in the civil war re-analysis, one reported ranking score of 0.85 came with a bootstrapped 95 percent interval of 0.66 to 0.95. Nine of the twelve papers they could fully check reported no significance test or uncertainty measure for the comparison.&lt;/p&gt;
&lt;h2 id=&quot;the-folds-you-tuned-on&quot;&gt;The folds you tuned on&lt;/h2&gt;
&lt;p&gt;Here is a subtler leak, and a common one. You run five-fold cross-validation across a grid of settings, pick the setting with the best score, and report that score.&lt;/p&gt;
&lt;p&gt;That best score is the maximum of several noisy numbers. Maxima sit above average by construction.&lt;/p&gt;
&lt;p&gt;Sudhir Varma and Richard Simon tested this on data where the two classes were identical by design. There was nothing to learn, so a fair estimate had to come out at chance. Tuning by cross-validation and reporting the winning score gave an error under 30 percent on 18.5 percent of the simulated datasets for one classifier, and on 38 percent for another. On genuinely independent data, both did no better than a coin.&lt;/p&gt;
&lt;p&gt;Their fix is a loop inside the loop. The inner folds choose the settings, the outer folds measure. That nested estimate came out close to the independent test set for both classifiers. The plain version had been answering a different question: how well does the best of these settings do on the data that chose it.&lt;/p&gt;
&lt;h2 id=&quot;what-to-do-on-monday&quot;&gt;What to do on Monday&lt;/h2&gt;
&lt;p&gt;Decide what the score is a promise to, then make the split keep it.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;If this repeats in your data&lt;/th&gt;
&lt;th&gt;Split with&lt;/th&gt;
&lt;th&gt;The score then describes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;KFold&lt;/code&gt;, or &lt;code&gt;StratifiedKFold&lt;/code&gt; for classes&lt;/td&gt;
&lt;td&gt;a new row like these&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A person, patient, writer or shop&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GroupKFold&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a new person&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TimeSeriesSplit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;next month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nothing, but you tuned settings&lt;/td&gt;
&lt;td&gt;nested cross-validation&lt;/td&gt;
&lt;td&gt;a new dataset&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Then hold back one set you touch once, at the end, and report an interval rather than a point.&lt;/p&gt;
&lt;h2 id=&quot;back-to-priya&quot;&gt;Back to Priya&lt;/h2&gt;
&lt;p&gt;Her number was never wrong about her own records. It was answering a question she had not asked: how well can you recognise a customer you have already met, from the messages they already sent you.&lt;/p&gt;
&lt;p&gt;The customer at the counter is not that customer. He has never written to her before, and the only thing the model can use is the sentence in front of her.&lt;/p&gt;
&lt;p&gt;Keep him out of the training data from the start, and the number you get back is small, unflattering, and about him.&lt;/p&gt;
</content:encoded><category>classical-ml</category><category>evaluation</category><category>basics</category></item><item><title>The Word Everyone Uses Is Worth Nothing</title><link>https://readitya.com/ai/2026-10-27-the-word-everyone-uses-is-worth-nothing/</link><guid isPermaLink="true">https://readitya.com/ai/2026-10-27-the-word-everyone-uses-is-worth-nothing/</guid><description>Count the words in each message, throw away the order, then charge a word less the more often it appears elsewhere. That two-line idea from 1972 is still the baseline neural search struggles to beat.</description><pubDate>Tue, 27 Oct 2026 03:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Priya repairs laptops from a room above a shop in Thane. Customers send one-line complaints on WhatsApp, and by Friday the messages pile up faster than she can read them.&lt;/p&gt;
&lt;p&gt;She keeps four of them in a text file to test a search box she is building.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;my laptop battery drains in an hour.&lt;/p&gt;
&lt;p&gt;laptop battery drains fast after the update and now the battery dies by noon.&lt;/p&gt;
&lt;p&gt;the update killed my laptop speaker.&lt;/p&gt;
&lt;p&gt;my laptop screen flickers when it is warm.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then she types the three words she always types: &lt;code&gt;laptop battery drains&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The first of those words cannot help her. Every message in the file is about a laptop. A word that appears in all four messages tells you nothing about which one to open.&lt;/p&gt;
&lt;p&gt;That silence is the design.&lt;/p&gt;
&lt;h2 id=&quot;a-bag-holds-words-not-sentences&quot;&gt;A bag holds words, not sentences&lt;/h2&gt;
&lt;p&gt;Every search system, old or new, begins by turning text into numbers. The oldest way is to tip each message into a bag and count what falls out.&lt;/p&gt;
&lt;p&gt;Word order goes first. In the bag, &lt;code&gt;battery drains laptop&lt;/code&gt; and &lt;code&gt;laptop battery drains&lt;/code&gt; hold the same three words. The bag cannot tell a question from an answer, or a complaint from its fix.&lt;/p&gt;
&lt;p&gt;Grammar goes next. The bag does not know that &lt;code&gt;drains&lt;/code&gt; is a verb in message one and a noun in a plumbing manual.&lt;/p&gt;
&lt;p&gt;What is left is a small table. One row per message, one column per word that appears anywhere in the file, a number in each cell. Most cells hold zero.&lt;/p&gt;
&lt;p&gt;That table alone ranks badly, because a long message beats a short one just by having more cells filled. Two corrections fix it, and the second is where the famous weight comes from.&lt;/p&gt;
&lt;h2 id=&quot;what-a-word-is-worth&quot;&gt;What a word is worth&lt;/h2&gt;
&lt;p&gt;Start by asking how rare each word is. Count the messages that contain it. That count is the document frequency, and the first correction is to divide the number of messages by it, then take a logarithm.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;weight = ln(messages in the file / messages containing the word)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;With four messages the arithmetic comes out like this.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Word&lt;/th&gt;
&lt;th&gt;Messages containing it&lt;/th&gt;
&lt;th&gt;Weight&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;laptop&lt;/td&gt;
&lt;td&gt;4 of 4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;my&lt;/td&gt;
&lt;td&gt;3 of 4&lt;/td&gt;
&lt;td&gt;0.288&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;battery, drains, update, the&lt;/td&gt;
&lt;td&gt;2 of 4&lt;/td&gt;
&lt;td&gt;0.693&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fast, speaker, screen, hour&lt;/td&gt;
&lt;td&gt;1 of 4&lt;/td&gt;
&lt;td&gt;1.386&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Read the bottom row, then the top. A word in one message weighs 1.386. A word in half the messages weighs 0.693, exactly half. A word in three of four weighs 0.288. The word in all four weighs nothing, because the logarithm of one is zero.&lt;/p&gt;
&lt;p&gt;&lt;mark&gt;Every time a word’s reach doubles, its weight halves, and a word that appears in every message is worth exactly nothing.&lt;/mark&gt;&lt;/p&gt;
&lt;p&gt;Nobody wrote a stopword list for that to happen. Nothing punished “laptop” for being boring. What punished it was sheer reach, and reach is a number you can count.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ai/ai-2026-10-27-idf-ladder.png&quot; alt=&quot;Four bars stepping down from 1.386 for a word in one message to zero for a word in all four&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Each doubling of a word’s reach costs it half its weight. The rule needs no dictionary of English, only a message count.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Real collections look like this at scale. A small number of words sit in almost every document, and a long tail sits in one.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ai/ai-2026-10-27-zipf.png&quot; alt=&quot;Word frequency against rank for War and Peace on log axes, with a fitted Zipf line and a lower panel showing the leftover pattern&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Every word in War and Peace, ranked by how often it appears. The fitted line is Zipf’s law, and the lower panel is what that line leaves unexplained. Image: Cosmia Nebula, CC BY-SA 4.0, via Wikimedia Commons.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;why-take-a-logarithm&quot;&gt;Why take a logarithm&lt;/h2&gt;
&lt;p&gt;The first reason is the ladder. Reach doubles, weight halves, and the steps stay gentle enough to compare words whose reach differs by a thousandfold.&lt;/p&gt;
&lt;p&gt;The second is arithmetic housekeeping. If you assume words appear independently, the chance of seeing two of them together is a product. Take logs and products become sums, so a document score can be the sum of one weight per word. Every ranking system after this one kept that shape. The base of the logarithm never matters, only the ratio inside it.&lt;/p&gt;
&lt;p&gt;There is a popular story that this weight measures the information a word carries, in Shannon’s sense. Stephen Robertson went through those arguments in 2004 and found them wanting. His better answer: the weight is what a naive Bayes model hands you when you know nothing about which documents are relevant. It predicts relevance without ever being told what relevance is.&lt;/p&gt;
&lt;h2 id=&quot;four-messages-scored&quot;&gt;Four messages, scored&lt;/h2&gt;
&lt;p&gt;Score a message by adding the weights of the query words it contains.&lt;/p&gt;
&lt;p&gt;Message one contains &lt;code&gt;laptop&lt;/code&gt;, &lt;code&gt;battery&lt;/code&gt; and &lt;code&gt;drains&lt;/code&gt;. That is 0 plus 0.693 plus 0.693, so 1.386.&lt;/p&gt;
&lt;p&gt;Message two contains the same three words, so 1.386 as well.&lt;/p&gt;
&lt;p&gt;Messages three and four contain only &lt;code&gt;laptop&lt;/code&gt;. Both score zero, correctly. One is about a speaker, the other about a screen, and Priya did not ask about either.&lt;/p&gt;
&lt;p&gt;So the arithmetic returns a tie, and it shouldn’t. Message two is the one that says the battery dies by noon. It is also the only message that names the battery twice.&lt;/p&gt;
&lt;p&gt;Count mentions as well as presence and the tie breaks. Inside message two, &lt;code&gt;battery&lt;/code&gt; contributes 0.693 twice, so the message scores 2.079 against 1.386.&lt;/p&gt;
&lt;p&gt;Message two wins, which is right. It wins by 50 percent, which is too much. It earned that lead by repeating a word, and it is twice as long as message one, fourteen words against seven. Two sloppy reasons to be confident.&lt;/p&gt;
&lt;h2 id=&quot;the-experiment-that-failed&quot;&gt;The experiment that failed&lt;/h2&gt;
&lt;p&gt;In 1972 a researcher at Cambridge named Karen Spärck Jones published a short paper in the Journal of Documentation. She was trying to explain a failure of her own.&lt;/p&gt;
&lt;p&gt;She had been grouping terms into clusters to help a search find more of what it should. The clusters kept getting taken over by terms that appear in many documents, and anything that made those terms match more documents pulled in noise with it.&lt;/p&gt;
&lt;p&gt;The obvious fix was to delete them, and she tested that. On the Cranfield collection one term appears in 144 of 200 documents. Cutting frequent terms from INSPEC meant deleting 73 words of 1,341, and it lowered the ceiling on recall by at least 30 percent. On the Keen collection, recall fell from 75 percent to 25 percent.&lt;/p&gt;
&lt;p&gt;People write requests in common words. In the Cranfield collection the average vocabulary term pointed at nine documents, while the average term used in a request pointed at 31.6.&lt;/p&gt;
&lt;p&gt;So delete nothing, and pay the frequent words less. Her own version was cruder than the formula above: a whole number built by rounding to powers of two, with logarithms to base 2. On Cranfield’s 200 documents a term in 90 of them scored 2, and a term in 3 scored 7. She credits the smooth version we use today to Roger Needham, a Cambridge colleague.&lt;/p&gt;
&lt;p&gt;She also notes how long it took to matter: AltaVista used this weighting from the start, about twenty-five years after the paper.&lt;/p&gt;
&lt;p&gt;The paper justified its weights with a nod to Zipf’s law, and Robertson’s later analysis finds that argument weak. The measure outlived every explanation offered for it, including the one printed with it.&lt;/p&gt;
&lt;h2 id=&quot;where-the-other-half-of-the-name-came-from&quot;&gt;Where the other half of the name came from&lt;/h2&gt;
&lt;p&gt;The 1972 paper has no term frequency in it. That half came from Gerard Salton’s group at Cornell, who worked with abstracts and short texts, where how often a word appears inside one document carried signal. Salton and Yang published the combination experiments in 1973.&lt;/p&gt;
&lt;p&gt;Two researchers, two kinds of data. Spärck Jones read presence and absence in word lists, so the number of documents was her variable. Salton read prose, so the number of mentions was his.&lt;/p&gt;
&lt;p&gt;Multiply the two and you get tf-idf, though the multiplication was never derived from anything. It was assembled and then tested.&lt;/p&gt;
&lt;h2 id=&quot;the-ceiling&quot;&gt;The ceiling&lt;/h2&gt;
&lt;p&gt;The last correction made this family of scores survive contact with real search engines. It is called BM25, published in 1994, and it adds one thing to tf-idf: a curve.&lt;/p&gt;
&lt;p&gt;Counting mentions pays a flat rate forever. Six mentions are worth six times one. BM25 pays a lot for the first mention, less for the second, and approaches a ceiling it can never cross.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;credit = (k1 + 1) × count / (k1 + count)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;k1&lt;/code&gt; at 1.2, the value Lucene uses by default, one mention is worth 1.0, two mentions are worth 1.375, and ten are worth 1.964. The ceiling is 2.2 no matter how many times the word appears.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ai/ai-2026-10-27-tf-ceiling.png&quot; alt=&quot;A straight diagonal for raw counting and a curve for BM25 that flattens towards 2.2&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Raw counting never stops paying. BM25 gives the first mention most of the credit and then creeps towards a ceiling of 2.2.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Run Priya’s message two through that curve. Its doubled &lt;code&gt;battery&lt;/code&gt; drops from 1.386 to 0.953, the message total falls from 2.079 to 1.646, and its lead over message one shrinks from 50 percent to 19 percent. The ranking does not change. The confidence behind the ranking does, and that is the honest thing to adjust.&lt;/p&gt;
&lt;p&gt;There is a second dial for length, &lt;code&gt;b&lt;/code&gt; = 0.75 by default, which discounts the length of a message against the average length of the collection. Message two is twice as long as message one, and that extra length earns it almost nothing.&lt;/p&gt;
&lt;p&gt;Both dials were tuned by experiment. Robertson describes them as global parameters that are generally unknown and may be fitted to evaluation data, which is a polite way of saying the field guessed, measured, and kept what worked.&lt;/p&gt;
&lt;h2 id=&quot;still-the-baseline-to-beat&quot;&gt;Still the baseline to beat&lt;/h2&gt;
&lt;p&gt;In 2021 five researchers at Darmstadt published BEIR, a benchmark of 18 retrieval datasets across nine tasks, and ran ten systems on them with no in-domain training. The average change in ranking quality against plain BM25:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Average change vs BM25&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;BM25 plus a cross-encoder re-ranker&lt;/td&gt;
&lt;td&gt;+11.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ColBERT&lt;/td&gt;
&lt;td&gt;+2.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;docT5query&lt;/td&gt;
&lt;td&gt;+1.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TAS-B&lt;/td&gt;
&lt;td&gt;−2.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GenQ&lt;/td&gt;
&lt;td&gt;−3.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ANCE&lt;/td&gt;
&lt;td&gt;−7.4%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SPARTA&lt;/td&gt;
&lt;td&gt;−20.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeepCT&lt;/td&gt;
&lt;td&gt;−27.9%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DPR&lt;/td&gt;
&lt;td&gt;−47.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Read the bottom row twice. DPR, a BERT-based dense retriever, averaged 47.7 percent below a formula with no neural network in it at all.&lt;/p&gt;
&lt;p&gt;The cost is worse for the newcomers. BM25 answers a query over a million documents in 20 milliseconds on a CPU, with a 0.4 GB index. The winning combination needs 450 milliseconds on a GPU, or 6.1 seconds on CPU. On the 15-million-document BioASQ collection, ColBERT’s index runs to about 900 GB against BM25’s 18 GB.&lt;/p&gt;
&lt;p&gt;The benchmark also flatters the old method. On the TREC-COVID dataset, 6.4 percent of BM25’s top ten had never been judged relevant or not, against 31.8 percent of TAS-B’s. When the researchers annotated 980 of those missing pairs by hand, ANCE climbed from 0.654 to 0.735, which put it 6.7 points above BM25 on the same data.&lt;/p&gt;
&lt;p&gt;Both things hold at once. A formula from 1994, sitting on top of one from 1972, is a serious baseline, and the test sets that make it look unbeatable were built with formula-shaped tools.&lt;/p&gt;
&lt;h2 id=&quot;what-the-bag-cannot-see&quot;&gt;What the bag cannot see&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Order.&lt;/strong&gt; &lt;code&gt;battery drains&lt;/code&gt; and &lt;code&gt;drains battery&lt;/code&gt; are one bag. Adding &lt;code&gt;no&lt;/code&gt; to a complaint raises its score, because &lt;code&gt;no&lt;/code&gt; is another word in the bag.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Synonyms.&lt;/strong&gt; A customer who writes &lt;code&gt;power&lt;/code&gt; instead of &lt;code&gt;battery&lt;/code&gt; matches nothing. Zero overlap, zero score. This gap is the entire reason dense retrieval exists.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Word relationships.&lt;/strong&gt; Every word is scored on its own, so nothing in the model knows that &lt;code&gt;screen&lt;/code&gt; and &lt;code&gt;flickers&lt;/code&gt; belong to the same fault.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The library you will probably use gives numbers that do not match mine, and not because I made a mistake.&lt;/p&gt;
&lt;p&gt;scikit-learn adds one to the top and bottom of the fraction before taking the log, as if it had seen an extra message containing every word. Its documentation says the effect is that words occurring in all documents “will not be entirely ignored”. So &lt;code&gt;laptop&lt;/code&gt; comes out at 1.0 instead of zero, &lt;code&gt;my&lt;/code&gt; at 1.223, a word in half the messages at 1.511, and a word in one at 1.916. The ladder survives. Only the zero disappears.&lt;/p&gt;
&lt;p&gt;Robertson also notes that the older formulas, which keep the collection size on top, give a word in more than half the documents a negative weight, meaning its presence counts against you.&lt;/p&gt;
&lt;h2 id=&quot;try-it-on-your-own-messages&quot;&gt;Try it on your own messages&lt;/h2&gt;
&lt;p&gt;Export a hundred of your own messages and count how many contain each word. Sort the list and look at the top twenty. You will find the words that describe your situation in general and none of your actual problem.&lt;/p&gt;
&lt;p&gt;Then put two search words in reverse order and watch what your own search tool does with them.&lt;/p&gt;
&lt;h2 id=&quot;back-to-priya&quot;&gt;Back to Priya&lt;/h2&gt;
&lt;p&gt;Her search box has never read a sentence of English. It has no idea what a laptop is, or that a battery dies by noon. It knows which words sit in which messages, and that in this particular file, this particular week, &lt;code&gt;battery&lt;/code&gt; is worth paying for and &lt;code&gt;laptop&lt;/code&gt; is worth nothing.&lt;/p&gt;
&lt;p&gt;She types the three words she always types. Message two comes back first, and it should.&lt;/p&gt;
&lt;p&gt;Relevance turns out to be mostly a question of what is rare in the room you are searching.&lt;/p&gt;
</content:encoded><category>classical-ml</category><category>retrieval</category><category>basics</category></item><item><title>The Machine That Only Asks Yes or No</title><link>https://readitya.com/ai/2026-10-26-the-machine-that-only-asks-yes-or-no/</link><guid isPermaLink="true">https://readitya.com/ai/2026-10-26-the-machine-that-only-asks-yes-or-no/</guid><description>A decision tree learns by asking one simple yes-or-no question at a time. It is the oldest idea in machine learning, and still the hardest thing to beat when your data lives in a spreadsheet.</description><pubDate>Mon, 26 Oct 2026 14:30:00 GMT</pubDate><content:encoded>&lt;p&gt;You have played this game. Somebody thinks of a person, a place or an object, and you get twenty questions to find it. Every question has to be answerable with a yes or a no.&lt;/p&gt;
&lt;p&gt;Watch someone who is good at it. They do not guess. Their first question splits the world roughly in half, is it alive, and their second halves whatever is left. Someone who is bad at it asks whether the thing is smaller than a bus, rules out almost nothing, and has spent a question for free.&lt;/p&gt;
&lt;p&gt;That instinct, the one you already have, is the whole algorithm behind a &lt;strong&gt;decision tree&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-only-move-it-knows&quot;&gt;The only move it knows&lt;/h2&gt;
&lt;p&gt;A decision tree predicts by walking you down a chain of questions. Each one compares a single column of your table against a number: is the distance above twenty kilometres, is the hours-studied figure above four. You answer, you go left or right, you answer the next one, and wherever the chain runs out, the prediction is waiting.&lt;/p&gt;
&lt;p&gt;A column here means one fact recorded for every row. Hours studied is a column. Whether a student turned up to lectures is another. The tree can ask about hours, and it can ask about lectures. It cannot ask whether the cost is more than twice the distance, because that question mixes two columns at once.&lt;/p&gt;
&lt;p&gt;That restriction sounds like a weakness. In practice it is where most of the tree’s strengths come from, and most of its limits too.&lt;/p&gt;
&lt;h2 id=&quot;ten-students-walk-into-an-exam&quot;&gt;Ten students walk into an exam&lt;/h2&gt;
&lt;p&gt;Ten students sat a mock exam. We know how many hours each of them studied, whether they attended lectures, and whether they passed.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hours studied&lt;/th&gt;
&lt;th&gt;Went to lectures&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;fail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;fail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;fail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;fail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;fail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;pass&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Five passed and five failed. Student seven is the awkward one: seven hours of study, no lectures, and a fail anyway. Tables are full of rows like that, and the whole lesson of this article lives in what a tree does with them.&lt;/p&gt;
&lt;h2 id=&quot;how-mixed-is-this-pile&quot;&gt;How mixed is this pile?&lt;/h2&gt;
&lt;p&gt;The tree builds itself by asking a question of its own at every step: which cut leaves the two new piles less mixed than the pile I started with?&lt;/p&gt;
&lt;p&gt;So it needs a number for mixed. The usual one is the &lt;strong&gt;Gini impurity&lt;/strong&gt;. Before any symbols, here it is in a sentence. If you picked two students out of a pile at random, how likely is it that one passed and the other failed?&lt;/p&gt;
&lt;p&gt;Our ten students are five and five. Pick two at random and they disagree about half the time, so the pile scores 0.5. A pile of four students who all failed can never disagree with itself, so it scores 0. Everything else lands somewhere in between.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ai/ai-2026-10-26-1.png&quot; alt=&quot;A curve showing impurity peaking when a pile is half and half&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A pile where everyone passed is perfectly clean, scoring 0. A fifty-fifty pile is as mixed as it gets, scoring 0.5. Every cut is an attempt to move left along this curve.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The formula is &lt;code&gt;Gini = 1 - (p1² + p2²)&lt;/code&gt;, where &lt;code&gt;p1&lt;/code&gt; and &lt;code&gt;p2&lt;/code&gt; are the shares of each class in the pile. Take the share of passes, square it, take the share of fails, square it, add the two together, and subtract the total from one. Half and half gives 1 minus 0.5, which is 0.5. A single class gives 1 minus 1, which is 0.&lt;/p&gt;
&lt;p&gt;The squaring is the useful part. It punishes small shares, so a lopsided pile scores low and a balanced one scores high.&lt;/p&gt;
&lt;h2 id=&quot;the-first-cut&quot;&gt;The first cut&lt;/h2&gt;
&lt;p&gt;Now the tree tries every column at every threshold, and keeps whichever cut lowers that number the most.&lt;/p&gt;
&lt;p&gt;Cut on hours, at four. The left pile is students one to four, all four of whom failed, so it scores 0. The right pile has one fail among five passes, which scores about 0.278. Combining them means weighting by size, four students left and six right, so &lt;code&gt;0.4 × 0 + 0.6 × 0.278 = 0.167&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The pile began at 0.5 and is now 0.167. That is a drop of &lt;strong&gt;0.333&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Cut on lectures instead. The students who attended split into one fail and five passes, scoring 0.278. Those who skipped split into three fails and one pass, scoring 0.375. Weighted: &lt;code&gt;0.6 × 0.278 + 0.4 × 0.375 = 0.317&lt;/code&gt;. A drop of &lt;strong&gt;0.183&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Hours wins, 0.333 against 0.183, so hours becomes the first question. Neither cut is clean, and that is fine. The tree only ever needs the cut that is best available.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ai/ai-2026-10-26-2.png&quot; alt=&quot;A decision tree with two questions and three leaves&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The first question does most of the work. The second buys a little more, and the box on the right is still mixed. One failed student is hiding in there.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-rule-that-exists-to-be-wrong-about-one-person&quot;&gt;The rule that exists to be wrong about one person&lt;/h2&gt;
&lt;p&gt;The leftover box holds four students, three passes and one fail. It is student seven again.&lt;/p&gt;
&lt;p&gt;The tree can fix this. Ask one more question, hours at seven, and student seven drops into a leaf of his own: perfectly pure, impurity zero. The score improves. The model gets worse.&lt;/p&gt;
&lt;p&gt;This is &lt;strong&gt;overfitting&lt;/strong&gt;, and that single-row leaf is the disease in miniature. A rule whose only job is to be wrong about one student fewer on an exam you have already marked teaches you nothing about the next exam. Leave a tree to grow without limits and it will keep splitting until every leaf is pure, which on real data means roughly one rule per training row.&lt;/p&gt;
&lt;p&gt;Every library gives you the same three brakes, and the defaults are loose enough that you get the overfitted tree unless you intervene. Cap the depth. Demand a minimum number of rows in each leaf. Or prune afterwards, charging the tree a fee for every leaf it keeps. If your leaves hold one or two rows, you did not fit a model. You indexed a spreadsheet.&lt;/p&gt;
&lt;h2 id=&quot;what-the-tree-is-really-doing-to-your-data&quot;&gt;What the tree is really doing to your data&lt;/h2&gt;
&lt;p&gt;Step back from the students and look at the shape of the thing.&lt;/p&gt;
&lt;p&gt;Plot two columns as a flat sheet of paper. A question about hours is a vertical line. A question about lectures is a horizontal line. Every cut is a wall parallel to one axis or the other, and the leaves are the rectangular rooms those walls enclose.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/ai/ai-iris-classification-tree.png&quot; alt=&quot;A trained decision tree for the iris dataset, with splits and leaf statistics&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A real tree, trained on the iris dataset: 150 flowers, four measurements, three species. Do not bother reading every number. Look at the shape. A handful of yes-or-no questions is enough to separate three species almost perfectly. Image: Dvd8719, CC BY-SA 4.0, via Wikimedia Commons.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That picture explains what a tree cannot do. Suppose the rule is “pass if the hours and the attendance agree, fail if they disagree”, which gives you two diagonal stripes. No vertical or horizontal wall separates diagonal stripes, so the tree has to cut again and again, building a staircase to imitate a diagonal.&lt;/p&gt;
&lt;p&gt;scikit-learn’s own documentation says so plainly: the algorithm is greedy, it makes the best-looking choice at each node, it cannot promise the best possible tree, and it struggles with concepts like XOR and parity. Greed is what keeps a tree fast and readable.&lt;/p&gt;
&lt;h2 id=&quot;why-it-still-beats-neural-networks-on-spreadsheets&quot;&gt;Why it still beats neural networks on spreadsheets&lt;/h2&gt;
&lt;p&gt;In 2022, three researchers assembled 45 datasets shaped like spreadsheets and tuned every model properly, neural networks included. Tree-based models still came out on top on medium-sized tables of around ten thousand rows, before anyone counted how much faster they run.&lt;/p&gt;
&lt;p&gt;The explanation comes down to three things, and all three follow from the staircase.&lt;/p&gt;
&lt;p&gt;Neural networks expect smoothness: nearby inputs should give nearby outputs. That is a gift for images. Tables are not smooth. A credit score of 699 is fine and 700 is refused. Trees expect nothing smooth, because they are flat by construction.&lt;/p&gt;
&lt;p&gt;Neural networks also suffer when a table carries useless columns, since they have to spend capacity learning that a column is noise. A tree never picks it, because a useless column produces no gain.&lt;/p&gt;
&lt;p&gt;And tables are built by people, one column at a time, so the useful directions already line up with the axes. Trees cut along those axes. Neural networks mix the columns together first and lose that alignment.&lt;/p&gt;
&lt;p&gt;Quinlan’s 1986 paper on the ID3 algorithm has been cited around fourteen thousand times, which tells you how long this idea has been earning its keep.&lt;/p&gt;
&lt;h2 id=&quot;three-things-it-cannot-do&quot;&gt;Three things it cannot do&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It cannot extrapolate.&lt;/strong&gt; Every prediction is the average of the rows that landed in that leaf, so it never returns a value beyond the range it saw. Show it a house twice as large as anything in training and it hands back the most expensive box’s average.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It is twitchy.&lt;/strong&gt; Change a few rows and the top question can flip, reshuffling everything below it. Two trees fitted on different halves of the same data can look unrelated. Averaging many of them into a random forest is the standard fix.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Its probabilities are coarse.&lt;/strong&gt; A leaf with three passes and one fail reports 0.75, which is a frequency taken from four students. Treat it as a rough ranking rather than a risk score.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;where-to-go-next&quot;&gt;Where to go next&lt;/h2&gt;
&lt;p&gt;A few good places, roughly in the order I would take them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Watch it drawn by hand.&lt;/strong&gt; &lt;a href=&quot;https://www.youtube.com/watch?v=7VeUPuFGJHk&quot;&gt;StatQuest: Decision Trees&lt;/a&gt; walks through impurity and splitting on a whiteboard in about seventeen minutes. If the Gini paragraph above felt slippery, this fixes it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Play with a real tree.&lt;/strong&gt; &lt;a href=&quot;https://explained.ai/decision-tree-viz/&quot;&gt;explained.ai’s tree visualiser&lt;/a&gt; lets you change a split and watch the predictions move. It is the fastest way to feel what a cut does.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Take the free short course.&lt;/strong&gt; &lt;a href=&quot;https://www.kaggle.com/learn/intro-to-machine-learning&quot;&gt;Kaggle’s Intro to Machine Learning&lt;/a&gt; is about four hours and ends with you training your own tree in a browser.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run the iris example yourself.&lt;/strong&gt; &lt;a href=&quot;https://scikit-learn.org/stable/auto_examples/tree/plot_iris_dtc.html&quot;&gt;scikit-learn’s decision tree plot&lt;/a&gt; is the picture from this article, generated by a short script you can copy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read a book, if you want the maths.&lt;/strong&gt; &lt;a href=&quot;https://www.statlearning.com/&quot;&gt;An Introduction to Statistical Learning&lt;/a&gt; is free to download. Chapter 8 covers trees and forests properly, and it assumes less than the title suggests.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-last-question&quot;&gt;The last question&lt;/h2&gt;
&lt;p&gt;Every model in the family, the forest and the boosted ensemble that wins most Kaggle tables and the ones with names you have not met yet, is a variation on one move: &lt;strong&gt;where do I cut?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Learn the tree as a staircase and the rest of the family reads as refinements of the same question.&lt;/p&gt;
&lt;p&gt;So the next time an insurance form asks you five yes or no questions and then quotes you a price, you will know what just happened. You walked down a decision tree, and somebody chose where the walls go.&lt;/p&gt;
</content:encoded><category>classical-ml</category><category>basics</category><category>intuition</category></item></channel></rss>