Verteilungen
Kurz gesagt: Eine Verteilung zeigt, wie alle Werte auf einmal verteilt sind: Ein Histogramm und ein Boxplot zeigen sie für eine Variable, ein Streudiagramm zeigt den Zusammenhang zwischen zwei.
Problem
„Wie viel ist eine Bestellung wert?“
Der Chef will wissen, was eine Bestellung wert ist. Der Mittelwert ist berechnet: 10,63 €. Die Werbung wird für „den typischen Kunden mit einer Bestellung von etwa 10 €“ geplant.
Es gibt 10.459 verkaufte Bestellungen (ohne die stornierten), und 6.736 davon liegen unter dem Mittelwert. Fast zwei von drei. Wie kann der „Durchschnitt“ über den meisten liegen? Die Antwort siehst du, wenn du alle Bestellungen auf einmal ansiehst statt einer Zahl.
Die Idee
Histogramm
Wie sich die Werte verteilen, welche häufig und welche selten sind, heißt Verteilung. Ihr Bild ist das Histogramm: Die x-Achse ist in gleiche Intervalle geteilt, und jeder Balken zeigt, wie viele Bestellungen in sein Intervall fallen.
ax.hist(values, bins=30) macht 30 Intervalle vom kleinsten bis zum größten Wert und zählt sie. Es liefert drei Dinge: die Anzahl in jedem Intervall, die Ränder und die Balken selbst.
Der erste Balken reicht von 0,80 € bis 3,40 € und enthält 1.915 Bestellungen. Der zweite, von 3,40 € bis 5,99 €, ist der höchste: 2.122. Danach fallen die Balken, und rechts bleibt ein dünner Streifen seltener Bestellungen, bis hin zu 78,70 €. Dieser Streifen heißt Schwanz. Eine Verteilung mit einem langen Schwanz nach rechts ist bei Geld normal: viele kleine Käufe und wenige große.
Die Idee
Die Anzahl der Klassen ändert das Bild
Du wählst bins, und eine andere Zahl erzählt eine andere Geschichte. Hier dieselben Bestellungen mit 4 und mit 80 Klassen:
Mit 4 Klassen siehst du nur, dass 9.091 Bestellungen unter 20,28 € liegen, 1.182 bis 39,75 € und danach kaum noch welche. Mit 80 Klassen siehst du, dass die meisten Bestellungen zwischen 2 € und 8 € liegen und die Anzahl zum Schwanz hin gleichmäßig abfällt. Die Spitzen (ein Balken hoch, sein Nachbar niedrig) kommen von den Preisen: Manche Summen ergeben sich häufiger als andere.
Es gibt keine einzige richtige Zahl. Probier ein paar aus und nimm die, bei der die Form sichtbar wird und das Rauschen sie nicht verdeckt. Für ein paar tausend Werte sind 30–60 Klassen meist ein guter Anfang.
Genauer, für Neugierige
bins kann auch eine Liste von Rändern sein: bins=[0, 5, 10, 20, 40, 80]. Dann sind die Klassen nicht gleich breit, und die Höhe führt in die Irre: Eine breite Klasse sammelt mehr Bestellungen, nur weil sie breit ist. Mit density=True wird die Höhe durch die Breite der Klasse geteilt, und die breiten Klassen führen nicht mehr in die Irre.
Probier es aus
Der Dezember aus der Nähe
Wie sehen die Bestellungen im Dezember aus? Leg die verkauften Bestellungen aus dem Dezember in december ab und zeichne ein Histogramm ihres Werts mit 40 Klassen. Beschrifte die x-Achse.
Lösung
import pandas as pd
import matplotlib.pyplot as plt
orders = pd.read_csv('year_orders.csv', parse_dates=['ordered_at'])
items = pd.read_csv('year_items.csv')
items['revenue'] = items['quantity'] * items['unit_price']
per_order = items.groupby('order_id', as_index=False).agg(
revenue=('revenue', 'sum'), lines=('product_id', 'size'), pieces=('quantity', 'sum'))
orders = orders.merge(per_order, left_on='id', right_on='order_id', how='left', validate='one_to_one')
# Der Umsatz lässt die stornierten Bestellungen weg.
sold = orders[orders['status'] != 'cancelled']
values = sold['revenue']
december = sold[sold['ordered_at'].dt.month == 12]
fig, ax = plt.subplots()
ax.hist(december['revenue'], bins=40)
ax.set_title('Bestellungen im Dezember')
ax.set_xlabel('Bestellwert, €')
ax.set_ylabel('Anzahl der Bestellungen')sold[sold["ordered_at"].dt.month == 12] liefert 1.211 Bestellungen, und ax.hist(december["revenue"], bins=40) verteilt sie von 0,80 € bis 78,00 €. Neben dem Gipfel links gibt es einen zweiten Buckel bei etwa 20–30 €: Viele dieser Bestellungen enthalten eine Geschenkkarte über 20 €, die sich meist im Dezember verkauft. Ohne bins nimmt matplotlib 10 Klassen, und die Form geht verloren. Wenn du die Bestellungen aus orders nimmst, enthält das Histogramm auch 74 stornierte: 1.285 statt 1.211.
Die Idee
Mittelwert und Median
Sortiere alle Bestellungen vom kleinsten zum größten Wert. Der Wert genau in der Mitte ist der Median: Die Hälfte der Bestellungen liegt darunter, die Hälfte darüber. values.median() liefert ihn.
Zeichne den Mittelwert und den Median als senkrechte Linien in das Histogramm. ax.axvline(x) zeichnet eine Linie über die ganze Höhe des Diagramms am Punkt x:
Der Mittelwert ist 10,63 €, und der Median ist 7,70 €. Der Median sitzt dort, wo die meisten Balken sind. Der Mittelwert liegt rechts davon: Der Schwanz großer Bestellungen zieht ihn hoch, weil jeder Euro davon in die Summe geht. Dem Median ist es egal, ob die größte Bestellung 78 € oder 7.800 € ist.
Bei Geld, Zeiten und Größen, wo es einen Schwanz gibt, sieh dir also beide an. Wenn sie weit auseinanderliegen, ist der Median näher am „typischen Kunden“.
Die Idee
Boxplot
Ein Histogramm ist detailliert, aber zwei oder fünf Histogramme nebeneinander lassen sich schwer vergleichen. Ein Boxplot schrumpft eine Verteilung auf fünf Dinge. Der Dezember ist der stärkste Monat: Sind seine Bestellungen größer, oder gibt es nur mehr davon?
So liest du es:
- die Linie in der Box ist der Median: 8,60 € im Dezember und 7,60 € in den anderen Monaten;
- die Box ist die mittlere Hälfte der Bestellungen: Ein Viertel liegt darunter, ein Viertel darüber;
- die Whisker reichen bis zu den letzten üblichen Werten;
- die Kreise sind ungewöhnlich große Bestellungen.
Die Box des Dezembers ist höher und reicht weiter nach oben: Dort gibt es mehr große Bestellungen (Geschenke, Pfannen, Messer). Also ändert sich der Mittelwert stärker als der Median: 13,14 € gegen 10,30 €, während der Median 8,60 € gegen 7,60 € ist. Der Dezember hat mehr Bestellungen und größere, aber der Unterschied liegt hauptsächlich im Schwanz.
Genauer, für Neugierige
Ein Whisker reicht bis zur am weitesten entfernten Bestellung, die höchstens 1,5 Boxhöhen von der Box entfernt ist. Alles Weitere ist ein Kreis. Diese Regel und die Boxhöhe (IQR) rechnest du in der Lektion über das Beschreiben von Daten mit Zahlen aus.
In älteren Versionen von matplotlib (vor 3.9) gibst du die Beschriftungen mit labels= statt tick_labels= an.
Die Idee
Streudiagramm: zwei Zahlen pro Bestellung
Wächst das Geld mit der Anzahl der Zeilen in der Bestellung? Hier hast du zwei Zahlen pro Bestellung, und die Frage ist, wie sie zusammenhängen. Das Bild ist ein Streudiagramm: Jede Bestellung ist ein Punkt, x ist die eine Zahl, y die andere. ax.scatter(x, y) zeichnet es.
Links ist alles in massiven Säulen. Tausende Punkte liegen übereinander, und du siehst nicht, wo viele und wo wenige sind. Das heißt Overplotting. Rechts macht alpha=0.03 jeden Punkt fast durchsichtig: Wo es viele gibt, baut sich die Farbe auf, und es ist dunkel.
Jetzt siehst du, dass die Bestellung mit jeder Zeile im Schnitt um etwa 4–5 € wächst: von 4,27 € mit einer Zeile (2.517 Bestellungen) auf 27,48 € mit sechs (145 Bestellungen). Aber die Punkte jeder Zeilenzahl streuen nach oben: Ein teures Produkt kostet so viel wie zehn billige.
sharey=True gibt den zwei Diagrammen dieselbe y-Achse, damit sie fair vergleichen.
Probier es aus
Stück und Wert
Die Spalte pieces ist die Anzahl der Stück in der Bestellung (die Summe von quantity). Zeichne ein Streudiagramm: die Stück auf x, den Bestellwert auf y, mit Transparenz, damit man sieht, wo viele Bestellungen liegen. Beschrifte beide Achsen.
Lösung
import pandas as pd
import matplotlib.pyplot as plt
orders = pd.read_csv('year_orders.csv', parse_dates=['ordered_at'])
items = pd.read_csv('year_items.csv')
items['revenue'] = items['quantity'] * items['unit_price']
per_order = items.groupby('order_id', as_index=False).agg(
revenue=('revenue', 'sum'), lines=('product_id', 'size'), pieces=('quantity', 'sum'))
orders = orders.merge(per_order, left_on='id', right_on='order_id', how='left', validate='one_to_one')
# Der Umsatz lässt die stornierten Bestellungen weg.
sold = orders[orders['status'] != 'cancelled']
values = sold['revenue']
fig, ax = plt.subplots()
ax.scatter(sold['pieces'], sold['revenue'], alpha=0.05)
ax.set_title('Stück und Bestellwert')
ax.set_xlabel('Stück in der Bestellung')
ax.set_ylabel('Bestellwert, €')ax.scatter(sold["pieces"], sold["revenue"], alpha=0.05) zeichnet 10.459 Punkte. Die Stück gehen von 1 bis 14, und die Punkte sind am dichtesten zwischen 1 und 5 Stück und unter 20 €. Ohne alpha sind die Säulen massiv, und eine Bestellung mit 14 Stück sieht so wichtig aus wie die Tausenden mit 2.
Übung
Die Antwort für den Chef
Der Chef will ein einziges Diagramm: was die Bestellungen wert sind und wo Mittelwert und Median liegen. Leg den Mittelwert des Werts der verkauften Bestellungen in mean_value ab und den Median in median_value. Zeichne ein Histogramm mit 50 Klassen und die zwei Werte als senkrechte Linien, mit einer Legende.
Lösung
import pandas as pd
import matplotlib.pyplot as plt
orders = pd.read_csv('year_orders.csv', parse_dates=['ordered_at'])
items = pd.read_csv('year_items.csv')
items['revenue'] = items['quantity'] * items['unit_price']
per_order = items.groupby('order_id', as_index=False).agg(
revenue=('revenue', 'sum'), lines=('product_id', 'size'), pieces=('quantity', 'sum'))
orders = orders.merge(per_order, left_on='id', right_on='order_id', how='left', validate='one_to_one')
# Der Umsatz lässt die stornierten Bestellungen weg.
sold = orders[orders['status'] != 'cancelled']
values = sold['revenue']
mean_value = values.mean()
median_value = values.median()
fig, ax = plt.subplots()
ax.hist(values, bins=50, color='lightgray')
ax.axvline(mean_value, color='black', label='Mittelwert')
ax.axvline(median_value, color='black', linestyle='--', label='Median')
ax.set_title('Was eine Bestellung wert ist')
ax.set_xlabel('Bestellwert, €')
ax.legend()
print(round(mean_value, 2), round(median_value, 2))Der Mittelwert ist 10,63 €, und der Median ist 7,70 €. Die Hälfte der Bestellungen liegt unter 7,70 €, und 6.736 von 10.459 liegen unter dem Mittelwert. Die typische Bestellung liegt näher bei 7,70 €, und der Mittelwert ist wegen des Schwanzes großer Bestellungen bis 78,70 € höher. Wenn du mit orders rechnest, geraten auch die stornierten in die Zahlen: Der Mittelwert kommt auf 10,61 €.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Gruppen: groupby · Verbinden: merge · Das erste Diagramm · Welches Diagramm für welche Frage
- Geht weiter in: Die Daten beschreiben · Stichprobe und Grundgesamtheit · Konfidenzintervalle · Korrelation und Ursache
- Aufgaben zum Thema: Diagramme