Zum Inhalt
wannacode

Zusammenfassungen und fehlende Werte

Kurz gesagt: Aggregationen in NumPy (sum, mean, max, argmax) machen aus vielen Zahlen eine, axis sagt, welche Dimension verschwindet, und NaN markiert einen fehlenden Wert.

Problem

„Was verkaufen wir am meisten?“

Die Kasse schickt einen Bericht: wie viele Stück von vier Produkten wir in jeder der letzten sechs Wochen verkauft haben. Jede Zeile ist eine Woche, jede Spalte ein Produkt:

PythonDaten: die Tabellen des Shops

Der Chef fragt drei Dinge: wie viel wir insgesamt verkauft haben, welches Produkt am besten läuft und welche Woche die stärkste war. Danach schickt er auch noch die Einnahmen pro Tag, wobei ein Tag fehlt.

Jede Antwort ist eine Zahl (oder eine pro Produkt), berechnet aus vielen Zahlen. Das nennt man eine Aggregation.

Die Idee

Eine Zahl aus vielen: sum, mean, min, max

Ein Array hat Methoden, die alle seine Werte zusammenfassen: sum() für die Summe, mean() für den Mittelwert, min() und max() für den kleinsten und den größten Wert. Hier sind sie an den Preisen der 25 Produkte. to_numpy() nimmt die Spalte als NumPy-Array:

PythonDaten: die Tabellen des Shops

Die Summe der Preise kommt als 175.89999999999998 heraus, nicht als 175,9. Der Computer speichert Dezimalzahlen binär, und 0,1 lässt sich nicht genau schreiben, deshalb summieren sich winzige Fehler. Das sind keine Fehler in den Daten.

Für einen Bericht rundest du: round(x, 2) liefert 2 Nachkommastellen. Der mittlere Preis wird 7,04 €, wie bei describe() im ersten Blick.

Genauer, für Neugierige

round ist die Funktion von Python und arbeitet mit einer einzelnen Zahl. Ein Array hat die Methode .round(2) (oder np.round(arr, 2)), die jede Zahl darin rundet. Runde am Ende, zur Anzeige: Wenn du mittendrin rundest, geht der Rundungsfehler in die nächsten Schritte ein.

Die Idee

Welches, nicht wie viel: argmax und argmin

max() sagt dir, wie viel das teuerste Produkt kostet. Der Chef fragt aber, welches es ist. argmax() liefert die Position des größten Werts und argmin() die des kleinsten. Mit der Position nimmst du den Namen aus dem Array der Namen:

PythonDaten: die Tabellen des Shops

Das teuerste ist das Messerset an Position 22 (39 €), das billigste das Butterbrötchen an Position 2 (0,80 €). Positionen beginnen bei 0, wie bei Listen.

1. prices.max() liefert 39.0 und prices.argmax() liefert 22. Was ist 22?
Genauer, für Neugierige

Kommt der größte Wert mehrmals vor, liefert argmax seine erste Position. Im Kassenbericht haben die Wochen 1 und 4 je 103 Stück, und argmin über die Wochen liefert nur Woche 1. Wenn Gleichstände wichtig sind, prüfe sie mit einer Maske: week_totals == week_totals.min().

Sieh es dir an

Entlang welcher Dimension: axis

sales.sum() addiert alle 24 Zellen: 654 Stück in sechs Wochen. Für „welches Produkt“ brauchst du eine Summe für jede Spalte, für „welche Woche“ eine Summe für jede Zeile. Der Parameter axis sagt, welche:

PythonDaten: die Tabellen des Shops
  • axis=0 ist die Dimension der Zeilen (die Wochen). Die Wochen verschmelzen, und eine Zahl pro Produkt bleibt: Brot sind 263 Stück, Kaffee 39.
  • axis=1 ist die Dimension der Spalten (die Produkte). Die Produkte verschmelzen, und eine Zahl pro Woche bleibt: von 103 bis 120.

Hier verwirrt sich jeder, denn „axis=0“ klingt nach „zeilenweise“ und liefert doch ein Ergebnis pro Spalte. Die Regel, die nicht lügt: axis ist die Dimension, die verschwindet. Die Form (6, 4) verliert mit axis=0 die 6 und wird zu (4,), und mit axis=1 verliert sie die 4 und wird zu (6,).

Dasselbe gilt für mean, min, max, argmax und den Rest. Der Mittelwert pro Woche für jedes Produkt, auf eine Nachkommastelle gerundet:

PythonDaten: die Tabellen des Shops

Probier es aus

Die stärkste Woche

Welche Woche hat insgesamt die meisten Stück verkauft? Lege die Summe jeder Woche in week_totals ab und ihre Nummer (1 bis 6) in best_week.

PythonDaten: die Tabellen des Shops

Die Idee

Wie viel bisher: cumsum

Manchmal fragt der Chef nicht „wie viel in dieser Woche“, sondern „wie viel vom Anfang bis zu dieser Woche“. Das ist die laufende Summe: cumsum() addiert die Zahlen nacheinander und behält jede Teilsumme:

PythonDaten: die Tabellen des Shops

Nach der dritten Woche haben wir 319 Stück verkauft, und die letzte Zahl, 654, ist die Gesamtsumme aus sales.sum(). Die laufende Summe ist die Linie, die in Diagrammen der „Verkäufe seit Jahresbeginn“ wächst.

Die Idee

Ein fehlender Tag: NaN

Jetzt die Einnahmen pro Tag der letzten Woche. Am Mittwoch hat die Kasse keinen Bericht geschickt, deshalb steht an der Stelle des Mittwochs np.nan: der Wert für „fehlend“, den du im ersten Blick gesehen hast. Das passiert mit dem Mittelwert:

PythonDaten: die Tabellen des Shops

Der gewöhnliche Mittelwert ist nan. Jede Rechnung mit NaN ergibt NaN: Was ist 412,5 plus „ich weiß nicht“? Ich weiß nicht. NumPy löst keinen Fehler aus; es liefert still nan, und in einem langen Bericht fällt das nicht auf.

np.isnan(revenue) ist eine Maske, die sagt, wo Werte fehlen, und .sum() darauf zählt sie: 1 Tag. np.nanmean und np.nansum überspringen NaN: Die mittleren Einnahmen der sechs bekannten Tage sind 494,70 €, ihre Summe ist 2.968,20 €. Diese Summe ist „was wir bisher wissen“, nicht die Einnahmen der ganzen Woche: Der Mittwoch ist nicht darin.

Sieh es dir an

Warum nicht 0

Die Versuchung ist, den fehlenden Wert durch 0 zu ersetzen und weiterzumachen. np.nan_to_num tut genau das:

PythonDaten: die Tabellen des Shops

Der Mittelwert fällt von 494,70 € auf 424,03 €. Die Null sagt „am Mittwoch haben wir nichts verkauft“, und das stimmt nicht: Der Shop war geöffnet, nur der Bericht fehlt. 0 ist nicht „fehlend“. Null ist ein Wert, und NaN ist das Fehlen eines Werts.

0 ist nur dann der richtige Ersatz, wenn es wirklich null bedeutet. Schickt die Kasse für ein Produkt, das niemand gekauft hat, keine Zeile, dann ist die Lücke null Verkäufe. Das entscheidet die Bedeutung der Daten, nicht der Code.

Probier es aus

Eine Woche ohne Zählung

Die Kasse hat nicht geschickt, wie viele Packungen Kaffee wir in der dritten Woche verkauft haben. Lege in avg_coffee ab, wie viele Packungen wir pro Woche im Durchschnitt verkaufen.

PythonDaten: die Tabellen des Shops

Übung

Der Bericht für den Chef

Beantworte die Fragen des Chefs aus dem Kassenbericht. Lege in product_totals die Stück jedes Produkts über die sechs Wochen ab, in best_product den Namen des meistverkauften Produkts und in avg_per_week, wie viele Stück jedes Produkt pro Woche im Durchschnitt verkauft, auf eine Nachkommastelle gerundet.

PythonDaten: die Tabellen des Shops

Test

Teste dich

1. sales hat die Form (6, 4): 6 Wochen und 4 Produkte. Welche Form hat sales.mean(axis=0)?
2. In einem Array mit den Tageseinnahmen ist ein Wert np.nan. Was liefert revenue.sum()?
3. Warum ist es falsch, die fehlenden Einnahmen durch 0 zu ersetzen und dann den Mittelwert zu nehmen?
4. Die Stückzahlen pro Woche sind [103, 104, 112]. Was liefert .cumsum()?

Erstellt von Ivo Gergov im Rahmen der Kampagne von Evo Tech für zugängliche Programmierausbildung ·