Skip to content
wannacode

Testing a hypothesis

In short: A hypothesis test asks whether a difference could be chance: the null hypothesis says “no difference”, and the p-value is how often chance gives a difference at least that big.

Problem

“Is Friday really stronger?”

The manager wants to put one more person on packing on Friday and take one away on Sunday. Before that, they ask: is Friday really stronger, or did it just turn out that way this year? Here is how many orders come in per day on average, by day of the week (0 is Monday, 6 is Sunday):

Pythondata: the shop tables

We count all the orders, the cancelled ones too: the question is how many arrive, and a cancelled order is also received and handled. On a Friday 36.35 orders come in on average, and on a Sunday 24.62. There are 52 Fridays in the year and 52 Sundays too. Every day is a little different: one Friday brings 22 orders, another 68. Is a gap of 11.73 orders real, or is it noise like in the lesson on samples?

The idea

If the day did not matter

The question “is Friday stronger than Sunday?” is a hypothesis. To check it, you start from the boring explanation: the day does not matter and the gap is chance. This is the null hypothesis.

If the null hypothesis is true, the labels “Friday” and “Sunday” mean nothing. You can shuffle them: put the 104 days on one pile, shuffle them and say that the first 52 are “Fridays” and the other 52 “Sundays”. The gap between the two halves is how much gap chance alone gives:

Pythondata: the shop tables

The real gap is 11.73 orders. Three shuffles give 0.50, 1.23 and 1.46. np.concatenate glues the two arrays into one, and rng.permutation returns a shuffled copy.

The idea

10,000 shuffles and the p-value

Three shuffles are too few. You make 10,000 at once: np.tile repeats the 104 days in 10,000 rows, and rng.permuted(..., axis=1) shuffles every row on its own. Then one calculation gives the gap for every row:

Pythondata: the shop tables

The biggest gap out of 10,000 shuffles is 7.50 orders. The real one is 11.73. The share of shuffles with a gap at least this big is the p-value: here it is 0, meaning under 1 in 10,000. If the day did not matter, such a gap would almost never come up. The conclusion: Friday really is stronger.

This approach is called a permutation test. np.abs is there because the question is “is there a difference”, without saying in advance in which direction. The usual threshold is 0.05: below it you say that the difference is statistically significant.

Try it

Monday and Saturday

1. The permutation test for Friday against Sunday gives p = 0 out of 10,000 shuffles. What does that mean?

The gap between Monday and Saturday is smaller. Is it chance? Put in gap the difference in the average number of orders per day (Monday minus Saturday), in gaps the gaps from 10,000 shuffles, and in p the p-value.

Pythondata: the shop tables

The idea

When there is no difference

Sunday has fewer orders. Are the orders themselves smaller too? Here 10,459 orders without the cancelled ones are compared, not days, so a 2,000 × 10,459 table of numbers would take about 170 MB. A loop with 2,000 shuffles of the mask takes under a second:

Pythondata: the shop tables

There are 1,204 Sunday orders, with an average of €10.83, and the others average €10.60. The gap is €0.23 and p = 0.425: in 42.5% of the shuffles the gap is at least this big. This is ordinary noise.

The honest conclusion is “there is no evidence that the Sunday order is different”. It is not “we proved they are equal”: there may be a small difference, only this data cannot show it. On Sunday people order less often, and there is no evidence that they order less.

The idea

What p does not say

The p-value answers one narrow question: how surprising the data is if the null hypothesis is true. It is not two things it is often confused with:

  • it is not the probability that the hypothesis is true: p = 0.425 does not mean “a 42.5% chance there is no difference”;
  • it is not the size of the difference: a very small p means “not chance”, not “a big difference”.

How big the difference is, the gap itself with an interval tells you. With the bootstrap from the previous lesson, separately for the Fridays and the Sundays:

Pythondata: the shop tables

Friday has on average 11.73 orders more, with a 95% interval from 9.00 to 14.56. That is 1.48 times as many as Sunday. With this number the manager decides how many people to put on, and p only says that they are not chasing noise.

More precisely, if you are curious

The 0.05 threshold is a convention, not a law of nature. At p = 0.06 the data is not “almost evidence”, and at p = 0.04 it is not “surely true”. With a lot of data a tiny difference gives a small p too: with a million orders in each group and a gap of 10 cents the test will be “significant”, but no decision follows from it. So always write both the gap and the interval.

The idea

The same with scipy

scipy.stats has the tests ready. ttest_ind (the t-test) compares the means of two groups by a formula. permutation_test does the shuffling for you, in chunks (batch), so that the memory does not run out:

Pythondata: the shop tables

For the Sunday order the t-test gives 0.426, permutation_test 0.419, and our loop 0.425. The answer is the same: no evidence. For Friday against Sunday the t-test gives 1.04 × 10⁻¹²: zero for all practical purposes, like our 0 out of 10,000.

More precisely, if you are curious

The t-test assumes that the mean of each group is distributed almost normally. With hundreds of orders in a group that is true (the central limit theorem). With little data and a long tail the permutation test is safer, because it assumes nothing about the distribution. permutation_test gives a p slightly different from ours: the shuffles are different, and it also counts the data itself as one of them, (count + 1) / (shuffles + 1).

Exercise

December and Friday

In December gift cards sell. Is the December order bigger than the orders in the other months, or is it chance? Put in gap the difference in the average order (December minus the other months), and in p the p-value. You can use a permutation test or stats.ttest_ind.

Pythondata: the shop tables

The Friday order is a little smaller than the order on the other days. Is there evidence for that? Run a permutation test with 2,000 shuffles (seed 42): gap is the difference in the average order (Friday minus the other days), p is the p-value, and evidence is whether p is under the 0.05 threshold.

Pythondata: the shop tables

Test

Test yourself

1. What is the null hypothesis when you compare the average order on Sunday and on the other days?
2. For the Sunday order p = 0.425. Which conclusion is honest?
3. Why is p computed with np.abs(gaps) >= abs(gap), not with gaps >= gap?
4. p for December is 5.1 × 10⁻²³, and for Friday against Sunday 1.0 × 10⁻¹². Does that mean December is the bigger difference?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·