Zum Inhalt
wannacode

Typen und fehlende Werte

Kurz gesagt: Jede Spalte in pandas hat einen Typ (dtype), der entscheidet, was du damit tun kannst, und fehlende Werte (NaN) findest du mit isna und füllst sie mit fillna oder entfernst sie mit dropna.

Problem

„An welchem Tag wird am meisten bestellt?“

Der Chef will wissen, wann mehr Leute im Lager sein sollen. Die Datei year_orders.csv hat 11.116 Bestellungen eines Jahres, jede mit Datum und Uhrzeit. Es sieht aus wie ein einziger Befehl: den Tag aus dem Datum nehmen und zählen.

PythonDaten: die Tabellen des Shops

Ein Fehler. dtypes sagt, warum: ordered_at ist str, Text. Für uns ist „2025-11-01 07:20“ ein Datum, aber read_csv sieht Ziffern, Striche und einen Doppelpunkt und rät nicht.

Der Typ einer Spalte entscheidet, was du damit tun kannst. In dieser Lektion siehst du, wie man ihn ändert, welche Typen Speicher sparen und eine Reihenfolge geben und was passiert, wenn ein Wert fehlt.

Die Idee

Jede Spalte hat einen Typ: astype

Jede Spalte eines DataFrames hat einen Typ (dtype). Du hast int64 und float64 für Zahlen und str für Text gesehen. Es gibt auch bool für True und False, datetime64 für Datumsangaben und category für wenige Werte, die sich wiederholen.

read_csv rät den Typ aus dem Text in der Datei. Wenn es falsch rät oder du einen anderen brauchst, macht astype eine Spalte eines neuen Typs. In products ist die Kategorie float64, weil die Geschenkkarte keine Kategorie hat und NaN eine Dezimalzahl ist. Ganze Zahlen mit Lücken hält der Typ Int64 (mit großem I):

PythonDaten: die Tabellen des Shops

Die Zahlen sind wieder ganz, und die Lücke ist <NA>: das Zeichen für „nichts“ in den neueren pandas-Typen. Mit astype(int) bekämst du den Fehler IntCastingNaNError, weil ein gewöhnliches int keinen Platz für eine Lücke hat.

1. prices enthält die Preise der ersten vier Produkte: 1.2, 1.9, 0.8 und 2.5. Was liefert prices.astype(int)?

Sieh es dir an

Wenige Werte, viele Zeilen: category

Die Spalte status hat 11.116 Zeilen, aber nur fünf verschiedene Wörter. Als Text wird jedes Wort in jeder Zeile gespeichert. Der Typ category hält die fünf Wörter einmal und für jede Zeile nur die Nummer ihres Wortes:

PythonDaten: die Tabellen des Shops

377.057 Byte werden zu 11.345, etwa 33-mal weniger. Im Jahr des Shops ist das wenig, aber in einer Tabelle mit Millionen Zeilen ist es der Unterschied zwischen „passt in den Speicher“ und „passt nicht“.

Eine Kategorie hat noch einen zweiten Nutzen: eine Reihenfolge. Die Status sind kein Alphabet, sondern ein Weg: new, paid, shipped, delivered. CategoricalDtype mit ordered=True legt diese Reihenfolge fest:

PythonDaten: die Tabellen des Shops

value_counts(sort=False) zählt in der Reihenfolge des Wegs, nicht nach Häufigkeit. Der Vergleich < 'delivered' heißt „vor der Lieferung“: 205 Bestellungen sind noch unterwegs. Die stornierten stehen am Ende, abseits des Wegs.

Probier es aus

Die Status entlang des Wegs

Mach die Spalte status zu einer Kategorie mit der Reihenfolge new, paid, shipped, delivered, cancelled und lege in status_counts ab, wie viele Bestellungen es auf jeder Stufe gibt, in dieser Reihenfolge.

PythonDaten: die Tabellen des Shops

Die Idee

Datumsangaben: pd.to_datetime und .dt

pd.to_datetime macht aus dem Text Datumsangaben. Die Spalte bekommt den Typ datetime64 und kennt jetzt den Kalender. Die Teile eines Datums kommen aus .dt: .dt.year, .dt.month, .dt.day_name() und viele mehr:

PythonDaten: die Tabellen des Shops

Das Jahr läuft vom 1. November 2025, 7:20 Uhr, bis zum 31. Oktober 2026, 23:01 Uhr. Die erste Bestellung ist an einem Samstag (Saturday: day_name() liefert die englischen Namen der Wochentage). .dt funktioniert nur bei Datumsangaben: Beim Text am Anfang hat es den Fehler geliefert.

Mehr zu Datumsangaben (nach Woche, nach Monat, ein gleitender Durchschnitt) steht in der Lektion über Zeit.

1. when ist eine Spalte mit Datumsangaben. Die erste Bestellung ist vom 1. November 2025, einem Samstag. Was liefert when.dt.day dafür?

Die Idee

Text: .str

Was .dt für Datumsangaben ist, ist .str für Text: Es wendet eine String-Methode auf jede Zeile auf einmal an. str.contains hast du bei den Filtern gesehen. Es gibt auch str.lower() und str.upper(), str.strip() (entfernt die Leerzeichen an den Enden), str.len(), str.split() und das Schneiden wie bei einem String: str[:13].

Die Regaletiketten fassen 13 Zeichen. Welche Namen passen nicht, und wie sehen sie abgeschnitten aus?

PythonDaten: die Tabellen des Shops

4 Namen sind länger als 13 Zeichen. str[:13] schneidet sie ab, und str.upper() setzt sie für das Etikett in Großbuchstaben. Das Ergebnis ist wieder eine Spalte, also setzt assign sie neben den Namen.

Die Idee

Fehlende Werte: isna und notna

Fast jede echte Tabelle hat etwas, das fehlt: Ein Kunde hat seine Stadt nicht angegeben, die Kasse hat keinen Bericht geschickt. pandas schreibt die Lücke als NaN (NaT bei Datumsangaben, <NA> bei den neueren Typen). isna() liefert eine Maske, die True ist, wo ein Wert fehlt, und .sum() darauf zählt die Lücken in jeder Spalte:

PythonDaten: die Tabellen des Shops

Ein Kunde hat keine Stadt. notna() ist die umgekehrte Maske: True, wo ein Wert da ist. Mit beiden Masken filterst du wie mit jeder Bedingung.

Sieh es dir an

Warum 0 nicht „fehlend“ ist

Die Banitsa und die Gurken haben den Bestand 0. Ist das eine Lücke?

PythonDaten: die Tabellen des Shops

isna() findet in stock nichts: Die Nullen sind echte Werte. 0 heißt „wir wissen, dass keines da ist“, und NaN heißt „wir wissen es nicht“.

Jetzt die Einnahmen pro Tag aus der Lektion über Zusammenfassungen, aber als pandas-Series. Ein wichtiger Unterschied: NumPy lieferte für den Mittelwert nan, und pandas überspringt die Lücken:

PythonDaten: die Tabellen des Shops

count() zählt 6 bekannte Tage von 7. Ihr Mittelwert ist 494,70 €, wie bei np.nanmean. Die Summe, 2.968,20 €, lässt aber still den Mittwoch aus: pandas warnt dich nicht. Mit fillna(0) sinkt der Mittelwert auf 424,03 €, weil die Null sagt „am Mittwoch haben wir nichts verkauft“, und das stimmt nicht.

Genauer, für Neugierige

Das Überspringen steuert der Parameter skipna: revenue.mean(skipna=False) liefert nan, wie NumPy. Das ist nützlich, wenn du lieber hättest, dass das Ergebnis eine Lücke anzeigt, statt still eine kleinere Zahl zu liefern.

Die Idee

fillna, dropna oder nichts

Es gibt drei Wege, mit einer Lücke umzugehen, und die Wahl hängt von der Frage ab, nicht vom Code:

  • fillna(wert), wenn du weißt, was die Lücke bedeutet. In einem Bericht „Kunden nach Stadt“ ist eine fehlende Stadt „unbekannt“: Das ist eine Antwort, keine Erfindung.
  • dropna(), wenn die Zeile die Frage nicht beantworten kann. In einem Bericht nach Kategorie weiß die Geschenkkarte nicht, wohin. subset=[...] schaut nur auf die angegebenen Spalten.
  • Nichts, wenn du es nicht weißt. Die Einnahmen vom Mittwoch sind nicht 0, und der Mittelwert der bekannten Tage ist ehrlicher.
PythonDaten: die Tabellen des Shops

dropna hat die Geschenkkarte entfernt: Von 25 Produkten bleiben 24, so viele, wie notna() bei der Kategorie zählt. In einem Bericht „wie viele Produkte wir verkaufen“ wäre das ein Fehler. fillna('unbekannt') macht die fehlende Stadt in value_counts zu einer eigenen Zeile.

Probier es aus

Kunden nach Stadt

Das Marketing will wissen, woher die Kunden kommen. Lege in missing_city ab, wie viele Kunden keine Stadt haben, und in by_city, wie viele Kunden es in jeder Stadt gibt, wobei die fehlende Stadt als „unbekannt“ gezählt wird.

PythonDaten: die Tabellen des Shops

Übung

Der Tag mit den meisten Bestellungen

Beantworte die Frage des Chefs. Mach ordered_at zu einem Datum, lege den Namen des Wochentags in eine neue Spalte day, lege in by_day ab, wie viele Bestellungen es an jedem Tag gibt, und in best_day den Tag mit den meisten Bestellungen.

PythonDaten: die Tabellen des Shops

Test

Teste dich

1. Die Spalte ordered_at wurde aus einer CSV gelesen und hat den Typ str. Warum liefert orders['ordered_at'].dt.month einen Fehler?
2. Die Spalte status hat 11.116 Zeilen, aber nur 5 verschiedene Werte. Was gewinnst du mit astype('category')?
3. In den Einnahmen pro Tag ist ein Tag NaN. Was liefert revenue.mean() in pandas?
4. Zwei Produkte haben den Bestand 0, und eines hat die Kategorie NaN. Welches davon ist „fehlend“?
5. Du machst einen Bericht „wie viele Produkte wir verkaufen“, und die Geschenkkarte hat keine Kategorie. Was tust du damit?

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