Minimum Description Length
The best model compresses hardest: model bits plus data-given-model bits is the total, and the smallest total wins without a validation split.
Why Does This Exist?
Model selection without held-out data looks impossible: training loss always favors complexity. Cross-validation answers with compute and variance; Bayes answers with debatable priors. MDL answers with codelength: the model that compresses data most (itself included) generalizes, because compression is prediction in bits.
Two-part form: . Complex models shrink the second term and explode the first. It connects source and channel coding to selection, and BIC falls out as its large- price.
The one idea you need first
: better fit, fewer bits. : each of parameters costs half a log- in bits. Add and minimize.
Think of It Like This
Shipping furniture flat-pack
Two sellers ship a shelf: one ships air (big box, tiny manual), the other flat-packs (small box, thick manual). Total shipping volume decides, not either part alone.
Complex models ship air: short manual (great fit) in a huge box (parameters). MDL measures the truck, not the shelf. Where it stops: real manuals approximate with BIC crudeness; exact codelengths need careful codes (NML, Bayesian mixtures).
How It Actually Works
Refinements: crude two-part (plug BIC), NML (minimax regret ), Bayesian mixtures (). BIC is MDL in nats with unit-information prior: each parameter pays . Prequential (online) MDL accumulates : compress sequentially, no code design. All punish near per parameter asymptotically.
Worked example
Hundred points, true line plus noise. Linear model (): bits, residuals bits, total . Tenth-degree (): extra... model bits, residuals bits, total . MDL picks linear () though the tenth-degree fits better. BIC check in nats: linear , penalty ... precisely vs : the 41-nat gap tracks the 20-bit codelength verdict up to constants.
Code
linear, complex_ = (40, 90), (120, 30) # (model, data) bitsprint(sum(linear), sum(complex_)) # -> (130, 150)print("linear" if sum(linear) < sum(complex_) else "complex") # -> linearTotals 130 versus 150 pick the simpler model. Fit alone would crown the complex one at 30 data bits.
Watch Out For
Comparing codelengths across different codes
Bits from mismatched codes (different precisions, different priors) do not compare: the "winner" may just use a coarser ruler. Selection then launders quantization as science.
Fix the coding scheme (same precision, same NML family) before comparing. If changing float precision flips the winner, the comparison was void.
Using MDL where compute is the constraint
Shortest description can be slow to decode (huge ensembles, deep searches). Edge and latency budgets care about FLOPs and memory, not bits.
Constrain the model class by deployability first, then MDL inside it. If the winner cannot ship, the bits were academic.
The Quick Version
- Total bits model bits data-given-model bits; minimize the sum.
- Example: 130-bit simple beats 150-bit complex despite worse fit.
- BIC is large- MDL at per parameter.
- NML, mixtures, and prequential refine the crude two-part code.
- Fix the code before comparing; mismatched rulers void verdicts.
- Constrain by deployability first, compress inside second.