Stichprobe und Grundgesamtheit
Kurz gesagt: Eine Stichprobe ist ein Teil der Grundgesamtheit, und ihr Mittelwert springt von Stichprobe zu Stichprobe; das Rauschen schrumpft mit der Wurzel aus der Größe: 4-mal so viele Daten geben halb so viel Rauschen.
Problem
Zwei Stichproben, zwei Mittelwerte
Der Chef will die mittlere Bestellung wissen. Auf den Jahresbericht will er nicht warten: Er nimmt 30 Bestellungen aus dem System und bekommt 12,11 €. Seine Kollegin nimmt weitere 30 und bekommt 10,33 €.
Wer hat recht? Keiner von beiden hat sich verrechnet. Nur die Bestellungen, die sie genommen haben, sind verschieden. Wie sehr kannst du einem Mittelwert aus 30 Bestellungen trauen? Und aus 3.000?
Die Idee
Grundgesamtheit und Stichprobe
Alles, wonach du fragst, heißt Grundgesamtheit: hier alle Bestellungen des Jahres ohne die stornierten. Der Teil, den du dir angeschaut hast, ist eine Stichprobe.
Meist siehst du die ganze Grundgesamtheit nicht: alle Kunden, alle künftigen Bestellungen. Hier hast du sie, also kannst du prüfen, wie falsch eine Stichprobe liegt. Die Wahrheit ist:
Der Mittelwert aller 10.459 Bestellungen ist 10,63 €. Mit dieser Zahl wird jede Stichprobe verglichen.
Die Idee
Eine Zufallsstichprobe mit NumPy
np.random.default_rng(42) erzeugt einen Zufallszahlengenerator. 42 ist der Seed: der Startpunkt. Mit demselben Seed gibt jeder Lauf dieselben Zahlen. Darum zeigen die Beispiele hier immer dasselbe, und du kannst jedes Ergebnis nachprüfen.
rng.choice(values, size=30, replace=False) wählt zufällig 30 verschiedene Bestellungen aus. Drei Stichproben jeder Größe:
Die Mittelwerte von 30 Bestellungen sind 11,33 €, 12,11 € und 10,33 €: die Zahlen des Chefs und der Kollegin. Bei 300 Bestellungen reichen sie von 10,07 € bis 11,42 €. Bei 3.000 reichen sie von 10,65 € bis 11,02 €: näher beieinander und näher an der Wahrheit von 10,63 €.
Die Idee
Tausend Stichproben
Drei Stichproben sind zu wenig, um zu sehen, wie stark der Mittelwert springt. Nehmen wir 1.000 von jeder Größe. rng.choice(values, size=(1000, n)) gibt eine Tabelle mit 1.000 × n: Jede Zeile ist eine Stichprobe. mean(axis=1) gibt den Mittelwert jeder Zeile: 1.000 Mittelwerte.
Jedes Histogramm sind 1.000 Mittelwerte, und die schwarze Linie ist die Wahrheit. Bei 30 Bestellungen liegen 90 % der Mittelwerte zwischen 7,99 € und 13,85 €: Eine Stichprobe von 30 kann fast alles zeigen. Bei 300 liegen sie zwischen 9,80 € und 11,50 €, und bei 3.000 zwischen 10,35 € und 10,91 €.
sharex=True gibt den drei Diagrammen dieselbe waagerechte Achse, damit man sie vergleichen kann. Ohne sie würde sich jedes Diagramm auf seine eigenen Mittelwerte strecken, und alle drei wirkten gleich breit.
Genauer, für Neugierige
Hier sind die Stichproben mit Zurücklegen (replace=True ist der Standard): Eine Bestellung kann in einer Stichprobe zweimal vorkommen. Das erlaubt 1.000 Stichproben auf einmal, in einer Tabelle. Bei 30 oder 3.000 von 10.459 Bestellungen ist der Unterschied zu einer Stichprobe ohne Zurücklegen klein.
Die Bestellungen haben einen langen Schwanz nach rechts, doch die Histogramme der Mittelwerte sind symmetrisch wie eine Glocke. Der Mittelwert genügend vieler Bestellungen verhält sich fast unabhängig davon so, wie die Bestellungen selbst aussehen: Je länger der Schwanz, desto mehr Bestellungen braucht die Glocke. Das heißt zentraler Grenzwertsatz.
Die Idee
Das Gesetz der großen Zahlen
Was passiert, wenn du Bestellungen eine nach der anderen aufhäufst und nach jeder den bisherigen Mittelwert berechnest? np.cumsum gibt die Summe bis zu jeder Position. Teile sie durch die Anzahl bis dort (np.arange(1, 3001)), und du hast den Mittelwert nach 1, 2, … 3.000 Bestellungen:
Nach 10 Bestellungen ist der Mittelwert 11,29 €, nach 100 ist er 9,82 €, nach 1.000 ist er 10,96 €, und nach 3.000 ist er 10,65 €. Anfangs springt er stark, dann beruhigt er sich um die Wahrheit. Das ist das Gesetz der großen Zahlen: Je größer eine Zufallsstichprobe, desto näher liegt ihr Mittelwert am Mittelwert der Grundgesamtheit.
set_xscale('log') setzt 1, 10, 100, 1.000 in gleichen Abständen auf die waagerechte Achse. So sind sowohl der Anfang, wo alles passiert, als auch das Ende zu sehen.
Die Idee
Das Rauschen schrumpft mit der Wurzel aus n
Um wie viel genauer wird der Mittelwert, wenn du mehr Bestellungen nimmst? Vergleiche 100, 400 und 1.600: Jede Größe ist das Vierfache der vorigen.
Das Rauschen ist die std der 1.000 Mittelwerte: 0,93 € bei 100 Bestellungen, 0,447 € bei 400 und 0,238 € bei 1.600. Jedes Mal geben 4-mal so viele Bestellungen etwa halb so viel Rauschen. Das Rauschen schrumpft mit der Wurzel der Größe, nicht mit der Größe selbst.
Es gibt also einen kurzen Weg ohne Simulation: die Standardabweichung der Bestellungen geteilt durch die Wurzel aus n. Das heißt Standardfehler: 9,43 / √100 ≈ 0,94 €. Formel und Simulation geben fast dasselbe (0,472 € gegenüber 0,447 € bei 400; die Lücke ist das Rauschen der Simulation selbst).
Der Preis ist hoch: Ein doppelt so genauer Mittelwert braucht 4-mal so viele Daten, ein zehnmal so genauer 100-mal so viele.
Probier es aus
Das Rauschen von 400 Bestellungen
Wie groß ist das Rauschen des Mittelwerts von 400 Bestellungen? Zieh 1.000 Stichproben mit je 400 Bestellungen und speichere die Standardabweichung ihrer Mittelwerte in noise.
Lösung
import numpy as np
import pandas as pd
orders = pd.read_csv('year_orders.csv')
items = pd.read_csv('year_items.csv')
items['revenue'] = items['quantity'] * items['unit_price']
orders['value'] = orders['id'].map(items.groupby('order_id')['revenue'].sum())
# Stornierte Bestellungen sind kein Umsatz: weglassen.
values = orders[orders['status'] != 'cancelled']['value'].to_numpy()
true_mean = values.mean()
rng = np.random.default_rng(1)
means = rng.choice(values, size=(1000, 400)).mean(axis=1)
noise = means.std()
print(round(noise, 3))rng.choice(values, size=(1000, 400)).mean(axis=1) gibt 1.000 Mittelwerte, und ihre std ist etwa 0,45 €. Die Formel sagt 9,43 / √400 = 9,43 / 20 ≈ 0,47 €. Die std einer Stichprobe (etwa 9,4 €) ist die Streuung der Bestellungen selbst, nicht die des Mittelwerts. Und 9,43 / 400 ≈ 0,02 € teilt durch n statt durch √n.
Die Idee
„Der Dezember ist auf ein Zehntel gefallen“
In der ersten Lektion des Kurses war der Umsatz des kleinen Shops im Dezember 22,70 € und im Oktober 255 €. Die Tabelle hat 53 Bestellungen ohne die stornierten, über 14 Monate: etwa 4 im Monat. Der Dezember hat 2 davon, der Oktober 7.
Wären alle Monate gleich, welche Lücke würde der Zufall allein geben? Wir schicken jede der 53 Bestellungen in einen zufälligen Monat und berechnen den Umsatz jedes Monats. 1.000-mal:
rng.integers(0, 14, ...) gibt jeder Bestellung eine Monatsnummer von 0 bis 13. np.where(month == m, values, 0) behält den Wert nur für die Bestellungen des Monats m, und sum(axis=1) addiert sie für jedes ausgedachte Jahr.
In 85,6 % der ausgedachten Jahre ist der stärkste Monat mindestens zehnmal so stark wie der schwächste. Und in ihnen sind die Monate per Konstruktion gleich. Der Absturz auf ein Zehntel ist ein Zeichen für nichts: Bei 4 Bestellungen im Monat ist es das übliche Rauschen.
In den Jahresdaten hat ein Monat im Mittel etwa 870 Bestellungen, und das Rauschen ist viel kleiner. Deshalb ist der Dezember dort wirklich der stärkste. Der Einbruch im September ist eine andere Frage: Ob es Rauschen ist und warum es passiert ist, finden wir im Projekt heraus.
Übung
Wie viele Bestellungen reichen?
Der Chef will die mittlere Bestellung auf ±0,50 € genau, in 95 von 100 Fällen. Zieh für Stichproben von 100, 300, 1.000, 2.000 und 3.000 Bestellungen je 1.000 Stichproben und speichere in close (ein Dict: Größe → Anteil), wie viele der Mittelwerte höchstens 0,50 € vom wahren entfernt sind. Speichere die kleinste ausreichende Größe in enough.
Lösung
import numpy as np
import pandas as pd
orders = pd.read_csv('year_orders.csv')
items = pd.read_csv('year_items.csv')
items['revenue'] = items['quantity'] * items['unit_price']
orders['value'] = orders['id'].map(items.groupby('order_id')['revenue'].sum())
# Stornierte Bestellungen sind kein Umsatz: weglassen.
values = orders[orders['status'] != 'cancelled']['value'].to_numpy()
true_mean = values.mean()
rng = np.random.default_rng(3)
close = {}
for n in [100, 300, 1000, 2000, 3000]:
means = rng.choice(values, size=(1000, n)).mean(axis=1)
close[n] = float((np.abs(means - true_mean) <= 0.5).mean())
print(close)
enough = min(n for n in close if close[n] >= 0.95)
print(enough)Mit rng = np.random.default_rng(3) ist der Anteil 41,5 % bei 100 Bestellungen, 63,9 % bei 300, 92,7 % bei 1.000, 97,6 % bei 2.000 und 99,5 % bei 3.000. 1.000 Bestellungen reichen für 95 % nicht, 2.000 reichen. Mit dem Standardfehler: Bei 2.000 Bestellungen ist er 9,43 / √2.000 ≈ 0,21 €, und 0,50 € sind etwa 2,4 davon. Wenn du den Mittelwert aller 1.000 Mittelwerte mit der Wahrheit vergleichst, liegt er immer nah dran: Das sagt nichts darüber, wie falsch eine einzelne Stichprobe liegt.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Gruppen: groupby · Das erste Diagramm · Verteilungen · Die Daten beschreiben
- Geht weiter in: Konfidenzintervalle · Eine Hypothese testen · A/B-Test · Kreuzvalidierung
- Aufgaben zum Thema: Statistik für Entscheidungen