Lesson 19 of 20
Building a p-value by hand — the permutation test
if you do not trust the formula, shuffle
In lesson 14 we got z and then a p-value from 2 × norm.sf(|z|).
That one line hides a large assumption — that z follows a standard normal distribution.
The assumption holds when the sample is large enough and conditions are right. But how do we know ours is?
By building it ourselves.
Stomach was p = 0.87 in lesson 14 — a place with nothing in it. Good for watching a situation where the null is true.
Python
Runs in your browser
Mean 0.01, sd 0.95, tails 4.5%. Close enough to theory (0, 1, 5%) — we have built ourselves the evidence that the normal approximation is fine here.
Python
Runs in your browser
The melanoma z never once appears in 1,000 shuffles. Permutation p < 0.001.
Python
Runs in your browser
Here is where a permutation test really earns its keep — you can shuffle an entire procedure, whatever it is.
Remember the cutoff hacking of lesson 15: try seventeen cut points and keep the best p. There is no formula for that procedure's p-value. But a permutation gives you one —
- shuffle the labels
- on the shuffled data, try all seventeen cut points and keep the smallest p
- repeat 1,000 times to get the distribution of "best p"
- see how extreme our own "best p" is in that distribution
That gives you an honest p-value that includes the searching. It takes a while to compute, but the principle is exactly what we just did.
🤔 Check yourself
What world does shuffling the labels create in a permutation test?
Answer Shuffling severs the link between the infiltration group and the survival data. What remains is the real shape of the survival data — and that is the world of the null hypothesis.
🤔 Check yourself
What is the strongest reason to use a permutation test?
Answer Checking whether the normal approximation holds is a good use too, but the real power is being able to repeat the whole procedure in the null world — including the searching.