NumPy·Lesson 21·11 min·0/4 exercises

Summary statistics

mean vs median, spread, percentiles — and when the average lies to you.

np.median.std / .varddofnp.percentilenp.corrcoefnp.histogramnp.bincount

Watch it happen

Play it through, or step back and forth yourself.

0
50
100
150
200
250
mean 49.9
median 50.0
x.mean()49.9
np.median(x)50.0
x.std()5.2

Seven values clustered around 50. Mean and median agree almost exactly, which is what happens when data is well behaved — and why it's easy to think they're interchangeable.

The idea

You already have mean, min, max and sum from lesson 15. This lesson is about the ones that tell you something the mean can't — starting with the most important comparison in descriptive statistics.

mean versus median

The mean uses every value's magnitude, so a single extreme value drags it. The median only cares about order, so it barely notices.

times = np.array([42, 45, 47, 50, 52, 55, 58, 240])
times.mean()        # 73.6  — no request took anywhere near this long
np.median(times)    # 51.0  — a typical request

The mean here describes a request that never happened. Use it when values are roughly symmetric and every one should count; use the median when there are outliers or a long tail — response times, incomes, file sizes, anything where a few values are enormous.

Notice np.median is a function, not a method — there's no x.median(). Same for np.percentile.

Hand-drawn notes showing eight response times where one very slow value drags the mean far above every ordinary reading while the median barely moves.

Spread

times.std()          # standard deviation
times.var()          # variance — std squared
times.std(ddof=1)    # the sample version

Both are built from squared distances from the mean, which makes them even more outlier-sensitive than the mean. NumPy defaults to ddof=0, the population formula, dividing by n. Statistics courses usually mean ddof=1, dividing by n-1, which is the right choice when your data is a sample from something larger. The difference is small for big n and matters a lot for small.

Percentiles

np.percentile(times, 50)        # the median, by another name
np.percentile(times, [25, 75])  # the quartiles
np.percentile(times, 95)        # the tail — what your slowest users see

The 95th and 99th percentiles are how latency is reported, and for exactly the reason above: an average response time hides the people having a bad time. np.quantile is the same function taking 0–1 instead of 0–100.

The interquartile range — p75 - p25 — is a spread measure that ignores outliers, the way the median does.

Hand-drawn notes showing percentiles as cut points along sorted data, with p25, p50 and p75 marked and the median named as the fiftieth percentile.

Two variables at once

np.corrcoef(a, b)       # a 2x2 matrix; [0, 1] is the correlation
np.cov(a, b)            # covariance, the unnormalised cousin

corrcoef returns a matrix, not a number, because it's built to handle many variables at once. For two arrays you want np.corrcoef(a, b)[0, 1]. The value runs from -1 to 1, and it only measures linear relationship — a perfect parabola can score near zero.

Distributions without plotting

counts, edges = np.histogram(times, bins=5)
np.bincount(labels)          # fast counts for small non-negative ints
np.average(x, weights=w)     # weighted mean

np.histogram gives you the numbers a chart would draw — counts, and the bins + 1 edges that bound them. Handy for checking a distribution before you commit to plotting it, which is the whole matplotlib track away.

All of these take axis, so per-column statistics on a table are one call: cups.mean(axis=0), np.median(cups, axis=0).

Practice

Write it yourself. The answer is there when you want it.

Putting the kettle on…

Starting up…

Write it yourself

not graded

Print the mean and the median of times one after the other — the gap between them is the lesson. Then the standard deviation both ways (ddof=0 and ddof=1), the 25th and 75th percentiles, and the 95th. Bin the times into 4 with np.histogram and print the counts. Finish with np.median(cups, axis=0).

Write something and press Run — the output appears here.

Your turn

4 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.

Return the median of times.

your answer

Return the 95th percentile of times.

your answer

Return the interquartile range of times — the 75th percentile minus the 25th.

your answer

Return the median cups per stall — one value per column of cups.

your answer