Pandas Data Cleaning: Praxis-Workflow
Updated on
Schmutzige Daten blockieren Analysen früh. Ad-hoc-fillna oder String-Ersetzungen verbergen oft echte Probleme: falsche Datentypen, stille Duplikate oder Ausreißer, die Statistiken verzerren.
PAS-Rahmen:
- Problem: Gemischte Typen, fehlende Werte und doppelte Datensätze zerstören Joins und verzerren Kennzahlen.
- Agitation: Schnelle Einzel-Fixes verschleiern Probleme bis spät im Projekt und verursachen Nacharbeit.
- Lösung: Ein wiederholbarer Bereinigungs-Check: Dtypes standardisieren, Nulls bewusst behandeln, Ausreißer abfedern, Duplikate entfernen, zum Schluss validieren.
Workflow auf einen Blick
| Schritt | Was tun | Beispiel |
|---|---|---|
| 1. Profilieren | Spalten, Nulls, Uniques prüfen | df.info(), df.describe(include="all") |
| 2. Spalten normalisieren | Namen/Strings trimmen & vereinheitlichen | df.columns = df.columns.str.strip().str.lower() |
| 3. Dtypes fixen | to_datetime, to_numeric, astype("category") | df["date"] = pd.to_datetime(df["date"], errors="coerce") |
| 4. Fehlende Werte | Löschen oder gezielt füllen | df["age"] = df["age"].fillna(df["age"].median()) |
| 5. Ausreißer | Kappen oder flaggen | df["rev_cap"] = df["revenue"].clip(upper=df["revenue"].quantile(0.99)) |
| 6. Duplikate | Exakt/teilweise entfernen | df.drop_duplicates(subset=["id", "date"], keep="last") |
| 7. Validieren | Regeln erzwingen | assert df["score"].between(0,100).all() |
1) Schnell profilieren
summary = {
"rows": len(df),
"columns": df.shape[1],
"nulls": df.isna().sum(),
"unique_counts": df.nunique(),
}- Mixed Types früh erkennen (
df.info()). - Schiefe Verteilungen mit
df.describe(percentiles=[0.01,0.99])prüfen.
2) Spalten und Text normalisieren
df.columns = df.columns.str.strip().str.lower().str.replace(" ", "_")
df["country"] = df["country"].str.strip().str.title()- Standardisierte Namen vereinfachen Joins und Code.
- Bei ungewöhnlichen Zeichen:
.str.normalize("NFKC").
3) Datentypen korrigieren
df["date"] = pd.to_datetime(df["date"], errors="coerce", utc=True)
df["amount"] = pd.to_numeric(df["amount"], errors="coerce")
df["segment"] = df["segment"].astype("category")errors="coerce"macht Fehler sichtbar alsNaT/NaN.convert_dtypes()liefert nullable, speichereffiziente Typen in einem Rutsch.
4) Fehlende Werte behandeln
df["age"] = df["age"].fillna(df["age"].median())
df["city"] = df["city"].fillna("Unknown")
df = df.dropna(subset=["id"]) # Pflichtschlüssel- Pro Spalte entscheiden: numerisch → Median/Mean; kategorisch → Modus/Platzhalter.
- Signal erhalten per Flag:
df["age_imputed"] = df["age"].isna().
5) Ausreißer behandeln
upper = df["revenue"].quantile(0.99)
lower = df["revenue"].quantile(0.01)
df["revenue_capped"] = df["revenue"].clip(lower=lower, upper=upper)- Für Verhältnisse ggf. Z-Scores:
abs(z) < 3. - Finanzdaten lieber kappen statt löschen, um Counts zu bewahren.
6) Duplikate sicher entfernen
df = df.drop_duplicates(subset=["id", "date"], keep="last")- Uniqueness-Key prüfen:
assert df.duplicated(["id"]).sum() == 0. - Für unscharfe Matches vorher normalisieren (z. B. E-Mails kleinschreiben).
7) Vor Export validieren
assert df["score"].between(0, 100).all()
valid_segments = {"basic", "pro", "enterprise"}
assert df["segment"].isin(valid_segments).all()pd.testing.assert_frame_equalin Tests nutzen, um Outputs zu vergleichen.- Leichte Row- und Null-Checks in Pipelines einbauen, um Regressionen zu fangen.
End-to-End-Minipipeline
def clean(df):
df = df.copy()
df.columns = df.columns.str.strip().str.lower()
df["date"] = pd.to_datetime(df["date"], errors="coerce")
df["amount"] = pd.to_numeric(df["amount"], errors="coerce")
df["amount"] = df["amount"].fillna(df["amount"].median())
df["segment"] = df["segment"].fillna("unknown").str.lower()
df = df.dropna(subset=["id"])
df = df.drop_duplicates(subset=["id", "date"], keep="last")
assert df["amount"].ge(0).all()
return df- Zuerst kopieren, um Eingaben nicht zu mutieren.
- Mit
df.pipe(clean)bleibt der Code lesbar.
Verwandte Guides
Wichtigste Punkte
- Namen standardisieren, Dtypes erzwingen, Nulls bewusst behandeln.
- Ausreißer kappen oder flaggen statt still löschen.
- Keys und Wertebereiche validieren, bevor Daten an BI/Analytics gehen.