Extreme Value Theory
Averages follow the central limit theorem, but maxima follow their own three-shape law. That law prices floods, outages, and worst-case latency.
Why Does This Exist?
Capacity planning never asks for the average flood. It asks for the 100-year flood: the level exceeded with probability 0.01 per year. Averages wash extremes away, and the CLT says nothing about maxima. Fitting a normal to the bulk and extrapolating underestimates the tail by multiples.
Fisher-Tippett-Gnedenko fixes the target: renormalized block maxima converge to one of three shapes, Gumbel, Frechet, or Weibull, unified as the generalized extreme value (GEV) law. It extends order statistics from exact small- formulas to large- tail limits.
The one idea you need first
A block maximum is the largest value in a block: yearly max rainfall, worst latency per deploy. A return level satisfies : the -block event. Everything here estimates .
Think of It Like This
High-jump records versus average jumps
Average jump height says who trains well. Records follow different physics: technique ceilings, outlier athletes, equipment jumps. Predicting the next record from the average misses by meters.
Block maxima are records per season. Their limit law depends on whether heights are unbounded and light (Gumbel), heavy (Frechet), or hard-capped (Weibull). Where it stops: athletes adapt and break stationarity, while the clean theorem needs identically distributed blocks.
How It Actually Works
For i.i.d. blocks with maximum , if converges, the limit is GEV: . Shape is Gumbel (light tails, e.g. normal, exponential), Frechet (heavy, e.g. Pareto), Weibull (bounded top, e.g. uniform). Practice splits into block maxima (fit GEV to yearly maxes) and peaks-over-threshold (fit generalized Pareto to exceedances of a high ).
Worked example
Take 100 daily river levels, block max . Fit Gumbel with , . The 100-block return level solves : . Since and , . The average day is near 5, the once-per-100-blocks day near 11.9: extremes live more than twice as high as the bulk.
Code
import numpy as np
rng = np.random.default_rng(7)daily = rng.exponential(2.0, size=(200, 100)) # 200 blocks of 100 daysmaxima = daily.max(axis=1)print(round(float(maxima.mean()), 2)) # -> ~11.3print(round(float(np.quantile(maxima, 0.99)), 2)) # -> ~14.9 tailExponential blocks give mean maxima near 11.3 with the top percentile near 14.9. The gap between mean-max and tail-max is the quantity capacity planners buy.
Watch Out For
Extrapolating a bulk normal into the tail
A normal fit to all daily data predicts the 100-block max far below the GEV fit, because the normal tail decays as while data may decay as or heavier. The symptom is "impossible" floods every few years.
Fit the tail on maxima or exceedances only. If the shape estimate is positive, the normal was the wrong universe.
Ignoring drift and seasonality
River baselines rise, traffic mixes shift, models redeploy. Nonstationary blocks violate the identical-distribution assumption, so a pooled GEV blends eras and misprices both.
Fit with time covariates or split eras. If block maxima trend over time, the stationary return level is fiction.
The Quick Version
- Maxima converge to Gumbel, Frechet, or Weibull; the shape is estimated, not assumed.
- Return level is the quantile of the maxima law.
- Example: Gumbel with gives a 100-block level near 11.9.
- Use block maxima or peaks-over-threshold, never bulk-normal extrapolation.
- Positive shape means heavy tails and far higher return levels.
- Stationarity is load-bearing; trend the covariates or split the eras.