Using the Data You Have Twice
Last timeRunning the Whole Process
There is no formula for the error bar on most statistics worth computing. Resampling your own measurements supplies one, using nothing but the data already collected.
A team reports that the median response time is 214 milliseconds. How much
would that number move if the same week were lived again?
There is a formula for the error on an average. There is no usable one for a
median, and none at all for most of what gets reported.
| textbook formula exists? | holds on real data? | resampling works? | |
|---|---|---|---|
| the average of a sample | 1 | 1 | 1 |
| the median | 1 | 0 | 1 |
| the ninety fifth percent | 0 | 0 | 1 |
| the ratio of two measure | 0 | 0 | 1 |
| the gap between two grou | 0 | 0 | 1 |
| the largest value seen | 0 | 0 | 0 |
| step | step | what happens | result |
|---|---|---|---|
| 1 | start | a sample of 500 measured response times | median is 214 ms |
| 2 | resample | draw 500 of them at random, with replacement | some appear twice, about a third never appear |
| 3 | recompute | take the median of the resampled set | 209 ms |
| 4 | again | a second resample and median | 221 ms |
| 5 | repeat | two thousand times in all | two thousand medians, spread from about 198 to 231 |
| 6 | sort and read off | the 2.5 and 97.5 per cent points of those medians | 203 ms to 226 ms |
| 7 | report | the median with its interval | 214 ms, between 203 and 226 |
import numpy as np
rng = np.random.default_rng(2)
times = rng.lognormal(5.3, 0.6, 500) # a skewed sample of 500
boots = [float(np.median(rng.choice(times, 500, replace=True))) for _ in range(2_000)]
print(round(float(np.median(times))), np.round(np.percentile(boots, [2.5, 97.5])))
sess = np.repeat(np.arange(50), 10) # 50 sessions, 10 requests each
vals = np.repeat(rng.lognormal(5.3, 0.6, 50), 10) * rng.lognormal(0, 0.1, 500)
rows = [float(np.mean(rng.choice(vals, 500, replace=True))) for _ in range(2_000)]
grps = [float(np.mean(vals[np.isin(sess, rng.choice(50, 50, replace=True))]))
for _ in range(2_000)]
print(np.ptp(np.percentile(rows, [2.5, 97.5])), np.ptp(np.percentile(grps, [2.5, 97.5])))What it assumes
The sample has to stand in for the population, which it does badly when it is
very small. Resampling thirty measurements gives an interval, and that
interval inherits every peculiarity of those thirty.
The measurements also have to be independent, or the resampling has to respect
whatever groups they fall into. This is the failure that occurs most often in
practice, because data collected from real systems almost always arrives in
clusters: requests within a session, measurements within a user, trades within
a day.
And statistics that depend on the extremes are outside the method entirely.
The lesson stops here
1 more paragraph to go
You have read the opening. The rest of the argument, the problems that check whether it landed, and the lines worth keeping at the end all come with a plan.
The first lesson of every course in the library reads the whole way through, free, so you can see exactly what the rest of them are.
See the planThe contentsThis is the reading half
Starting the course gives you your own copy of it. Every idea on every page has problems standing under it, marked with a reason rather than a tick, and any sentence you do not believe can be opened and argued with. None of that can happen on a page nobody owns.
The contents