Eine Hypothese testen
Kurz gesagt: Ein Hypothesentest fragt, ob ein Unterschied Zufall sein könnte: Die Nullhypothese sagt „kein Unterschied“, und der p-Wert ist, wie oft der Zufall einen mindestens so großen Unterschied liefert.
Problem
„Ist der Freitag wirklich stärker?“
Der Chef will freitags eine Person mehr an das Packen stellen und sonntags eine abziehen. Vorher fragt er: Ist der Freitag wirklich stärker, oder ist es dieses Jahr nur so gekommen? So viele Bestellungen kommen im Mittel pro Tag an, nach Wochentag (0 ist Montag, 6 ist Sonntag):
Wir zählen alle Bestellungen, auch die stornierten: Die Frage ist, wie viele ankommen, und eine stornierte Bestellung wird ebenfalls empfangen und bearbeitet. An einem Freitag kommen im Mittel 36,35 Bestellungen an, an einem Sonntag 24,62. Das Jahr hat 52 Freitage und ebenso 52 Sonntage. Jeder Tag ist ein bisschen anders: Ein Freitag bringt 22 Bestellungen, ein anderer 68. Ist ein Abstand von 11,73 Bestellungen echt, oder ist er Rauschen wie in der Lektion über Stichproben?
Die Idee
Wenn der Tag keine Rolle spielte
Die Frage „Ist der Freitag stärker als der Sonntag?“ ist eine Hypothese. Um sie zu prüfen, gehst du von der langweiligen Erklärung aus: Der Tag spielt keine Rolle, und der Abstand ist Zufall. Das ist die Nullhypothese.
Stimmt die Nullhypothese, bedeuten die Labels „Freitag“ und „Sonntag“ nichts. Du kannst sie mischen: Leg die 104 Tage auf einen Haufen, misch sie und sag, die ersten 52 seien „Freitage“ und die anderen 52 „Sonntage“. Der Abstand zwischen den beiden Hälften ist der Abstand, den der Zufall allein liefert:
Der echte Abstand ist 11,73 Bestellungen. Drei Mischungen geben 0,50, 1,23 und 1,46. np.concatenate klebt die beiden Arrays zu einem zusammen, und rng.permutation gibt eine gemischte Kopie zurück.
Die Idee
10.000 Mischungen und der p-Wert
Drei Mischungen sind zu wenig. Du machst 10.000 auf einmal: np.tile wiederholt die 104 Tage in 10.000 Zeilen, und rng.permuted(..., axis=1) mischt jede Zeile für sich. Dann liefert eine einzige Rechnung den Abstand für jede Zeile:
Der größte Abstand aus 10.000 Mischungen ist 7,50 Bestellungen. Der echte ist 11,73. Der Anteil der Mischungen mit einem mindestens so großen Abstand ist der p-Wert: Hier ist er 0, also unter 1 zu 10.000. Spielte der Tag keine Rolle, käme ein solcher Abstand fast nie vor. Die Schlussfolgerung: Der Freitag ist wirklich stärker.
Diese Methode heißt Permutationstest. np.abs steht da, weil die Frage „gibt es einen Unterschied“ lautet, ohne vorher zu sagen, in welche Richtung. Die übliche Schwelle ist 0,05: Liegt p darunter, sagst du, der Unterschied ist statistisch signifikant.
Probier es aus
Montag und Samstag
Der Abstand zwischen Montag und Samstag ist kleiner. Ist er Zufall? Speichere in gap die Differenz der durchschnittlichen Bestellungen pro Tag (Montag minus Samstag), in gaps die Abstände aus 10.000 Mischungen und in p den p-Wert.
Lösung
import numpy as np
import pandas as pd
orders = pd.read_csv('year_orders.csv')
orders['ordered_at'] = pd.to_datetime(orders['ordered_at'])
daily = orders.set_index('ordered_at').resample('D').size()
weekday = daily.index.dayofweek.rename('weekday')
mon = daily[weekday == 0].to_numpy()
sat = daily[weekday == 5].to_numpy()
gap = mon.mean() - sat.mean()
both = np.concatenate([mon, sat])
rng = np.random.default_rng(42)
shuffled = rng.permuted(np.tile(both, (10_000, 1)), axis=1)
gaps = shuffled[:, :len(mon)].mean(axis=1) - shuffled[:, len(mon):].mean(axis=1)
p = (np.abs(gaps) >= abs(gap)).mean()
print(round(gap, 2), p)Der Montag hat im Mittel 3,46 Bestellungen mehr als der Samstag. Von 10.000 Mischungen geben etwa 1 % (p = 0,0104) einen mindestens so großen Abstand. Das liegt unter 0,05: Es gibt einen Beleg dafür, dass der Samstag schwächer ist. Das Jahr hat 52 Montage und 53 Samstage, also schneidest du bei len(mon), nicht bei 52. Ohne rng.permuted sind alle Zeilen gleich und p ist 1, und ohne np.abs zählst du nur eine Richtung.
Die Idee
Wenn es keinen Unterschied gibt
Am Sonntag gibt es weniger Bestellungen. Sind auch die Bestellungen selbst kleiner? Hier werden 10.459 Bestellungen ohne die stornierten verglichen, nicht Tage, deshalb würde eine Zahlentabelle von 2.000 × 10.459 etwa 170 MB brauchen. Eine Schleife mit 2.000 Mischungen der Maske braucht unter einer Sekunde:
Es gibt 1.204 Sonntags-Bestellungen mit einem Durchschnitt von 10,83 €, und die anderen liegen im Schnitt bei 10,60 €. Der Abstand ist 0,23 €, und p = 0,425: In 42,5 % der Mischungen ist der Abstand mindestens so groß. Das ist gewöhnliches Rauschen.
Die ehrliche Schlussfolgerung lautet „es gibt keinen Beleg dafür, dass die Sonntags-Bestellung anders ist“. Sie lautet nicht „wir haben bewiesen, dass sie gleich sind“: Es kann einen kleinen Unterschied geben, nur zeigen ihn diese Daten nicht. Am Sonntag bestellen die Leute seltener, und es gibt keinen Beleg dafür, dass sie weniger bestellen.
Die Idee
Was p nicht sagt
Der p-Wert beantwortet eine enge Frage: wie überraschend die Daten sind, wenn die Nullhypothese stimmt. Er ist nicht zwei Dinge, mit denen er oft verwechselt wird:
- Er ist nicht die Wahrscheinlichkeit, dass die Hypothese stimmt: p = 0,425 heißt nicht „mit 42,5 % Wahrscheinlichkeit gibt es keinen Unterschied“;
- er ist nicht die Größe des Unterschieds: Ein sehr kleines p heißt „nicht Zufall“, nicht „ein großer Unterschied“.
Wie groß der Unterschied ist, sagt dir der Abstand selbst mit einem Intervall. Mit dem Bootstrap aus der vorigen Lektion, getrennt für die Freitage und die Sonntage:
Der Freitag hat im Mittel 11,73 Bestellungen mehr, mit einem 95-%-Intervall von 9,00 bis 14,56. Das ist das 1,48-Fache des Sonntags. Mit dieser Zahl entscheidet der Chef, wie viele Leute er einteilt, und p sagt nur, dass er nicht dem Rauschen nachjagt.
Genauer, für Neugierige
Die Schwelle von 0,05 ist eine Konvention, kein Naturgesetz. Bei p = 0,06 sind die Daten kein „fast ein Beleg“, und bei p = 0,04 sind sie nicht „sicher wahr“. Bei sehr vielen Daten gibt auch ein winziger Unterschied ein kleines p: Mit einer Million Bestellungen in jeder Gruppe und einem Abstand von 10 Cent ist der Test „signifikant“, aber daraus folgt keine Entscheidung. Schreib also immer beides auf, den Abstand und das Intervall.
Die Idee
Dasselbe mit scipy
scipy.stats hat die Tests fertig. ttest_ind (der t-Test) vergleicht die Mittelwerte zweier Gruppen mit einer Formel. permutation_test übernimmt das Mischen für dich, in Portionen (batch), damit der Speicher nicht ausgeht:
Für die Sonntags-Bestellung gibt der t-Test 0,426, permutation_test 0,419 und unsere Schleife 0,425. Die Antwort ist dieselbe: kein Beleg. Für Freitag gegen Sonntag gibt der t-Test 1,04 × 10⁻¹²: praktisch null, wie unser 0 von 10.000.
Genauer, für Neugierige
Der t-Test setzt voraus, dass der Mittelwert jeder Gruppe fast normalverteilt ist. Bei Hunderten Bestellungen in einer Gruppe stimmt das (zentraler Grenzwertsatz). Bei wenig Daten und einem langen Schwanz ist der Permutationstest sicherer, weil er nichts über die Verteilung voraussetzt. permutation_test gibt ein p, das sich leicht von unserem unterscheidet: Die Mischungen sind andere, und es zählt auch die Daten selbst als eine davon, (Anzahl + 1) / (Mischungen + 1).
Übung
Dezember und Freitag
Im Dezember verkaufen sich Geschenkkarten. Ist die Dezember-Bestellung größer als die Bestellungen in den anderen Monaten, oder ist es Zufall? Speichere in gap die Differenz der durchschnittlichen Bestellung (Dezember minus die anderen Monate) und in p den p-Wert. Du kannst einen Permutationstest oder stats.ttest_ind benutzen.
Lösung
from scipy import stats
import numpy as np
import pandas as pd
orders = pd.read_csv('year_orders.csv')
items = pd.read_csv('year_items.csv')
orders = orders[orders['status'] != 'cancelled']
items['revenue'] = items['quantity'] * items['unit_price']
totals = items.groupby('order_id')['revenue'].sum()
orders['value'] = orders['id'].map(totals)
orders['ordered_at'] = pd.to_datetime(orders['ordered_at'])
value = orders['value'].to_numpy()
is_dec = (orders['ordered_at'].dt.month == 12).to_numpy()
gap = value[is_dec].mean() - value[~is_dec].mean()
p = stats.ttest_ind(value[is_dec], value[~is_dec]).pvalue
print(is_dec.sum(), round(gap, 2), p)Es gibt 1.211 Dezember-Bestellungen, und die Bestellung ist im Mittel 2,84 € größer als die Bestellung in den anderen Monaten. Der t-Test gibt p = 5,1 × 10⁻²³: Der Zufall erklärt diesen Abstand nicht. Verglichen wird der Dezember mit den anderen 11 Monaten. Gegen das ganze Jahr würdest du den Dezember auch mit sich selbst vergleichen, und der Abstand schrumpft.
Die Freitags-Bestellung ist etwas kleiner als die Bestellung an den anderen Tagen. Gibt es einen Beleg dafür? Mach einen Permutationstest mit 2.000 Mischungen (Seed 42): gap ist die Differenz der durchschnittlichen Bestellung (Freitag minus die anderen Tage), p ist der p-Wert, und evidence sagt, ob p unter der Schwelle von 0,05 liegt.
Lösung
import numpy as np
import pandas as pd
orders = pd.read_csv('year_orders.csv')
items = pd.read_csv('year_items.csv')
orders = orders[orders['status'] != 'cancelled']
items['revenue'] = items['quantity'] * items['unit_price']
totals = items.groupby('order_id')['revenue'].sum()
orders['value'] = orders['id'].map(totals)
orders['ordered_at'] = pd.to_datetime(orders['ordered_at'])
value = orders['value'].to_numpy()
is_fri = (orders['ordered_at'].dt.dayofweek == 4).to_numpy()
gap = value[is_fri].mean() - value[~is_fri].mean()
rng = np.random.default_rng(42)
gaps = np.empty(2_000)
for i in range(2_000):
s = rng.permutation(is_fri)
gaps[i] = value[s].mean() - value[~s].mean()
p = (np.abs(gaps) >= abs(gap)).mean()
evidence = p < 0.05
print(round(gap, 2), p, evidence)Die Freitags-Bestellung ist 0,45 € kleiner, und p = 0,0645. Das liegt über 0,05: Bei der üblichen Schwelle gibt es keinen Beleg, und evidence ist False. Es ist verlockend, „fast signifikant“ zu sagen oder die Schwelle auf 0,1 zu verschieben, nachdem du p gesehen hast. Tu es nicht: Die Schwelle wird vor dem Test gewählt. Die ehrliche Antwort lautet „es kann einen kleinen Unterschied geben, aber diese Daten beweisen ihn nicht“.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Datumswerte und Zeitreihen · Die Daten beschreiben · Stichprobe und Grundgesamtheit · Konfidenzintervalle
- Geht weiter in: A/B-Test · Korrelation und Ursache · Warum ist der Umsatz gefallen?
- Aufgaben zum Thema: Statistik für Entscheidungen