W3docs

Kategoriale Daten

Kategoriale Daten in Python kodieren mit Label Encoding, Ordinal Encoding, One-Hot Encoding und pd.get_dummies – mit scikit-learn-Beispielen.

Kategoriale Daten sind Daten, die eine begrenzte, feste Menge von Werten annehmen – zum Beispiel "red", "blue", "green" in einer Farbspalte oder "low", "medium", "high" für eine Schweregradskala. Die meisten Machine-Learning-Algorithmen arbeiten mit Zahlen, daher müssen kategoriale Spalten vor dem Training in eine numerische Darstellung umgewandelt werden.

Dieses Kapitel erläutert die wichtigsten Encoding-Strategien, wann welche eingesetzt werden sollte und wie man sie in Python mit pandas und scikit-learn korrekt anwendet, ohne dabei Informationen aus dem Testset in das Modell einfließen zu lassen.

Warum Encoding wichtig ist

Wenn man rohe String-Werte an einen scikit-learn-Schätzer übergibt, wird ein ValueError ausgelöst. Selbst wenn eine Spalte bereits Zahlen enthält – wie 1, 2, 3 für "small", "medium", "large" – wird ein Algorithmus, der Merkmalswerte als kontinuierliche Zahlen behandelt, eine falsche Beziehung ableiten (z. B. dass "large" dreimal so groß wie "small" ist). Encoding ermöglicht es, die tatsächliche Beziehung korrekt darzustellen.

Die Wahl des Encodings hängt von zwei Fragen ab:

  1. Gibt es eine natürliche Reihenfolge? Farben haben keine natürliche Reihenfolge (nominal). T-Shirt-Größen haben eine natürliche Reihenfolge (ordinal). Das richtige Encoding bewahrt die Reihenfolge, wenn sie vorhanden ist, und ignoriert sie, wenn nicht.
  2. Wie viele verschiedene Werte (Kardinalität) hat die Spalte? Spalten mit hoher Kardinalität (Hunderte einzigartiger Städte, Produkt-IDs) können beim One-Hot Encoding Tausende von Dummy-Spalten erzeugen, was sowohl den Speicherbedarf als auch die Modellleistung beeinträchtigt.

Einen Beispieldatensatz vorbereiten

Die folgenden Beispiele verwenden einen kleinen Kleidungsdatensatz, sodass die Ausgabe genau nachvollzogen werden kann.

import pandas as pd

data = {
    "color":  ["red", "green", "blue", "green", "red"],
    "size":   ["S", "M", "L", "S", "M"],
    "price":  [10, 20, 30, 10, 20],
    "in_stock": [True, True, False, True, False],
}

df = pd.DataFrame(data)
print(df)

Ausgabe:

   color size  price  in_stock
0    red    S     10      True
1  green    M     20      True
2   blue    L     30     False
3  green    S     10      True
4    red    M     20     False

Label Encoding

Label Encoding ersetzt jede Kategorie durch eine ganze Zahl. scikit-learns LabelEncoder weist die Ganzzahlen alphabetisch zu.

from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
df["color_encoded"] = le.fit_transform(df["color"])

print(df[["color", "color_encoded"]])
print("Classes:", list(le.classes_))

Ausgabe:

   color  color_encoded
0    red              2
1  green              1
2   blue              0
3  green              1
4    red              2
Classes: ['blue', 'green', 'red']

blue → 0, green → 1, red → 2 (alphabetische Reihenfolge).

Wann verwenden: Label Encoding ist für die Zielvariable (y) vorgesehen, nicht für Eingabemerkmale. Auf eine nominale Merkmalsspalte angewendet, implizieren die kodierten Ganzzahlen eine Ordnung, die nicht existiert, was baumbasierte Modelle in die Irre führt und für lineare Modelle schädlich ist.

Encoding rückgängig machen:

decoded = le.inverse_transform([0, 1, 2])
print(decoded)  # ['blue' 'green' 'red']

Ordinal Encoding

Ordinal Encoding ähnelt dem Label Encoding, erlaubt aber die genaue Angabe der Reihenfolge der Kategorien. Zu verwenden bei Merkmalen, bei denen die Reihenfolge bedeutsam ist.

from sklearn.preprocessing import OrdinalEncoder

# Define the order explicitly: S < M < L
oe = OrdinalEncoder(categories=[["S", "M", "L"]])
df["size_encoded"] = oe.fit_transform(df[["size"]])

print(df[["size", "size_encoded"]])

Ausgabe:

  size  size_encoded
0    S           0.0
1    M           1.0
2    L           2.0
3    S           0.0
4    M           1.0

Das Modell kann nun korrekt ableiten, dass L (2) > M (1) > S (0) gilt.

Umgang mit unbekannten Kategorien zur Vorhersagezeit:

# Use handle_unknown='use_encoded_value' with unknown_value=-1
oe_safe = OrdinalEncoder(
    categories=[["S", "M", "L"]],
    handle_unknown="use_encoded_value",
    unknown_value=-1,
)
oe_safe.fit(df[["size"]])
print(oe_safe.transform([["XL"]]))  # [[-1.]]

One-Hot Encoding

One-Hot Encoding erzeugt eine binäre Spalte pro Kategorie. Eine 1 in einer Spalte bedeutet, dass die Zeile zu dieser Kategorie gehört; alle anderen Spalten erhalten den Wert 0. Dies ist die Standardwahl für nominale (ungeordnete) Merkmale, die linearen Modellen, SVMs und neuronalen Netzen übergeben werden.

from sklearn.preprocessing import OneHotEncoder
import numpy as np

ohe = OneHotEncoder(sparse_output=False, handle_unknown="ignore")
color_encoded = ohe.fit_transform(df[["color"]])

# Build a labelled DataFrame from the result
col_names = ohe.get_feature_names_out(["color"])
color_df = pd.DataFrame(color_encoded, columns=col_names, dtype=int)

print(color_df)

Ausgabe:

   color_blue  color_green  color_red
0           0            0          1
1           0            1          0
2           1            0          0
3           0            1          0
4           0            0          1

handle_unknown='ignore' füllt unbekannte Kategorien mit lauter Nullen, anstatt bei neuen Daten zur Vorhersagezeit einen Fehler auszulösen.

Eine Spalte weglassen, um Multikollinearität zu vermeiden

Bei drei Kategorien erhält man drei binäre Spalten, aber die dritte ist aus den anderen beiden vollständig vorhersagbar (blue = 1 − green − red). Diese Dummy-Variablen-Falle kann bei linearen Modellen zu Problemen führen. Eine Spalte mit drop='first' weglassen:

ohe_nodrop = OneHotEncoder(sparse_output=False, drop="first", handle_unknown="ignore")
reduced = ohe_nodrop.fit_transform(df[["color"]])
print(pd.DataFrame(reduced, columns=ohe_nodrop.get_feature_names_out(["color"]), dtype=int))

Ausgabe (eine Spalte weggelassen):

   color_green  color_red
0            0          1
1            1          0
2            0          0
3            1          0
4            0          1

Baumbasierte Modelle (Entscheidungsbäume, Random Forests, Gradient Boosting) sind gegen die Dummy-Variablen-Falle immun, daher ist das Weglassen einer Spalte bei ihnen optional.

pd.get_dummies — Die schnelle pandas-Alternative

Für explorative Arbeit ist pd.get_dummies() der schnellste Weg, einen DataFrame per One-Hot zu kodieren:

dummies = pd.get_dummies(df[["color", "size"]], dtype=int)
print(dummies)

Ausgabe:

   color_blue  color_green  color_red  size_L  size_M  size_S
0           0            0          1       0       0       1
1           0            1          0       0       1       0
2           1            0          0       1       0       0
3           0            1          0       0       0       1
4           0            0          1       0       1       0

Einschränkung: pd.get_dummies() ist kein trainierter Transformer. Es kann nicht garantieren, dass zwischen Trainings- und Testaufteilungen dieselbe Spaltenstruktur entsteht, und es unterstützt kein handle_unknown. Für Produktions-Pipelines sollte OneHotEncoder innerhalb einer scikit-learn Pipeline bevorzugt werden.

Datenlecks vermeiden

Datenlecks (Data Leakage) entstehen, wenn Informationen aus dem Testset die Vorbereitung der Trainingsdaten beeinflussen. Das Ergebnis ist ein übermäßig optimistischer Evaluierungswert, der die reale Leistung nicht widerspiegelt.

Das korrekte Vorgehen ist:

  1. Die Daten zunächst in Trainings- und Testsets aufteilen.
  2. Jeden Encoder ausschließlich auf dem Trainingsset trainieren (fit).
  3. transform() (nicht fit_transform()) auf das Testset anwenden.
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder

X = df[["color", "size"]]
y = df["price"]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=42)

ohe = OneHotEncoder(sparse_output=False, handle_unknown="ignore")
ohe.fit(X_train)                       # fit on training data only

X_train_enc = ohe.transform(X_train)  # transform training set
X_test_enc  = ohe.transform(X_test)   # transform test set using training-fit encoder

Weitere Details zur Trainings-/Testaufteilung finden sich im Kapitel Train/Test Split.

Pipeline zur Kombination von Encoding und Modell verwenden

Eine scikit-learn Pipeline verkettet einen Transformer und einen Schätzer. Dadurch wird sichergestellt, dass der Encoder immer nur auf den Trainingsdaten trainiert wird, auch bei der Kreuzvalidierung.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
from sklearn.linear_model import LinearRegression
from sklearn.compose import ColumnTransformer
from sklearn.model_selection import train_test_split

categorical_cols = ["color", "size"]
numeric_cols     = ["in_stock"]

X_full = df[categorical_cols + numeric_cols]
y_full = df["price"]

X_tr, X_te, y_tr, y_te = train_test_split(X_full, y_full, test_size=0.4, random_state=42)

preprocessor = ColumnTransformer(transformers=[
    ("ohe", OneHotEncoder(handle_unknown="ignore"), categorical_cols),
    ("pass", "passthrough", numeric_cols),
])

pipe = Pipeline(steps=[
    ("preprocessor", preprocessor),
    ("model", LinearRegression()),
])

pipe.fit(X_tr, y_tr)
print("Test predictions:", pipe.predict(X_te))

Der ColumnTransformer wendet in einem Durchgang unterschiedliche Vorverarbeitungsschritte auf verschiedene Spalten an. Die Pipeline ist das empfohlene Muster für alle produktionsreifen Machine-Learning-Workflows.

Das richtige Encoding wählen

SituationEmpfohlenes Encoding
Zielvariable (y)LabelEncoder
Ordinales Merkmal (natürliche Reihenfolge vorhanden)OrdinalEncoder mit expliziten categories
Nominales Merkmal, niedrige KardinalitätOneHotEncoder (oder pd.get_dummies für Erkundung)
Nominales Merkmal, hohe KardinalitätTarget Encoding oder Frequency Encoding (siehe Hinweis unten)
Produktions-PipelineOneHotEncoder innerhalb einer Pipeline / ColumnTransformer

Target Encoding ersetzt jede Kategorie durch den Mittelwert der Zielvariable für diese Kategorie. Es bewältigt hohe Kardinalität gut, ist aber besonders anfällig für Datenlecks – immer mit Kreuzvalidierungs-Folds anwenden oder eine Bibliotheksimplementierung verwenden (z. B. category_encoders.TargetEncoder), die dies automatisch handhabt.

Verwandte Kapitel

  • Scale — numerische Merkmale vor der Modellierung normalisieren und standardisieren
  • Train/Test Split — Daten vor jedem Vorverarbeitungsschritt korrekt aufteilen
  • Linear Regression — ein Modell, das von korrektem kategorialem Encoding profitiert
  • Cross Validation — Modelle zuverlässig evaluieren, wenn sie mit Encoding-Pipelines kombiniert werden
  • Confusion Matrix — Klassifikationsmodell-Performance nach der Kodierung von Zielvariablen messen
  • Pandas Tutorial — pandas-Grundlagen einschließlich DataFrame-Erstellung und -Manipulation
Was this page helpful?