6 · Histograms & percentiles
See the whole distribution at once — and understand why the p99 latency matters more than the average.
A histogram shows what a single number can never tell you — the full shape of your distribution.
Without this:
Without histograms, you can't detect bimodal distributions, heavy tails, or the log-transform signal hiding in your data.
Two summary numbers — mean and std dev — can describe a dataset that is completely Gaussian, or one that is wildly bimodal, or one so right-skewed it spans six orders of magnitude. They cannot tell you which is which. A histogram can.
A histogram bins the data into intervals (called bins), counts the observations in each bin, and draws a bar whose height is proportional to that count (or frequency/density). The result is a visual fingerprint of the distribution's shape.
Bin count is a parameter. Too few bins: fine-grained structure disappears into a single wide block. Too many bins: every bar is just 0 or 1 observation and the plot looks like a comb. Common heuristics:
| Rule | Formula | Best for | |---|---|---| | Sturges | k = ⌈log₂(n)⌉ + 1 | Small normal-ish datasets | | Freedman–Diaconis | h = 2·IQR / n^(1/3) | Larger, skewed datasets | | Scott | h = 3.5·σ / n^(1/3) | General purpose |
matplotlib's bins='auto' uses the max of Sturges and Freedman–Diaconis.
A percentile (or quantile) answers: "what value separates the bottom p% of the data from the top (100−p)%?" The 50th percentile is the median. The 25th and 75th are Q1 and Q3. The 99th percentile latency means exactly one thing: 1% of requests take longer than this value.
Python (in browser)
The bell shape confirms normality. Red dashed = mean, blue dotted = median — for a symmetric distribution they almost coincide. Open /tmp/hist_normal.png in the output panel to view.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
np.percentile(x, q) returns the q-th percentile. The 99th percentile (p99) is the number below which 99% of observations fall — the 1% slowest requests breach it.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
The same exponential data plotted with 5 vs 50 bins. Five bins hides the long tail completely; fifty bins reveals the decay clearly. Binning choice is an editorial decision. Open /tmp/hist_bins.png to compare.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Three bin-count rules: Sturges (fast, assumes normality), Scott (optimal for Gaussian), Freedman–Diaconis (robust, preferred for skewed or large datasets). matplotlib's bins='auto' is a good default.
If a request's response time is at the 99th percentile of the distribution, that means...
- A **histogram** reveals shape (skew, modes, tails) that summary statistics hide. Bin count is a parameter — try a few values.
- The **p-th percentile** is the value below which p% of the data falls. The 99th percentile latency (p99) is the canonical tail-latency metric in production ML systems.
- matplotlib's `bins='auto'` (max of Sturges and Freedman–Diaconis) is a solid default. Use Freedman–Diaconis explicitly for large or skewed datasets.
Histograms are the first plot in every EDA notebook — they reveal modes, skew, and outliers at a glance and tell you whether to apply a log transform. p99 latency targets shape model-serving infrastructure budgets and SLA contracts.
If you remove it: You can't visually detect a bimodal distribution, a heavy tail, or estimate the right transformation (log, sqrt) to apply before training.