Machine Learning mit logistischer Regression in Python
Lernen Sie, wie logistische Regression funktioniert, wie Sie binäre und Mehrklassen-Klassifikatoren in Python mit scikit-learn trainieren und evaluieren.
Logistische Regression ist ein überwachter Klassifikationsalgorithmus, der die Wahrscheinlichkeit schätzt, dass eine Stichprobe zu einer bestimmten Klasse gehört. Trotz des Begriffs „Regression" im Namen wird sie für Klassifikationsaufgaben verwendet – zur Vorhersage eines kategorialen Labels wie Spam/kein Spam, Krankheit/gesund oder Klick/kein Klick.
Dieses Kapitel behandelt:
- Wie logistische Regression funktioniert (die Sigmoid-Funktion und Log-Odds)
- Aufbau eines binären Klassifikators in Python mit
scikit-learn - Bewertung eines Klassifikators jenseits der reinen Genauigkeit
- Umgang mit Mehrklassen-Problemen
- Regularisierung und wann sie angepasst werden sollte
- Feature-Skalierung und warum sie wichtig ist
- Wann logistische Regression gegenüber anderen Klassifikatoren zu bevorzugen ist
So funktioniert logistische Regression
Von linearer Regression zu Wahrscheinlichkeiten
Lineare Regression sagt einen kontinuierlichen Wert vorher. Würde man sie für Klassifikation verwenden, könnten die Vorhersagen außerhalb von [0, 1] liegen und wären als Wahrscheinlichkeiten nicht interpretierbar. Logistische Regression löst dieses Problem, indem die lineare Kombination durch die Sigmoid-Funktion geleitet wird:
σ(z) = 1 / (1 + e^(-z))Dabei ist z = w₀ + w₁x₁ + w₂x₂ + … + wₙxₙ die gewichtete Summe der Eingabe-Features. Die Sigmoid-Funktion quetscht jede reelle Zahl in den Bereich (0, 1) und liefert so eine gültige Wahrscheinlichkeitsschätzung.
Entscheidungsgrenze
Das Modell sagt Klasse 1 vorher, wenn die Wahrscheinlichkeit einen Schwellenwert (Standard 0,5) überschreitet, andernfalls Klasse 0:
ŷ = 1 if σ(z) ≥ 0.5
ŷ = 0 if σ(z) < 0.5Der Schwellenwert σ(z) = 0.5 entspricht z = 0, der die Entscheidungsgrenze definiert – eine Hyperebene im Feature-Raum, die die beiden Klassen trennt.
Log-Odds (Logit)
Der Logarithmus des Quotenverhältnisses zeigt, warum das Modell in den Parametern linear ist:
log(p / (1 - p)) = w₀ + w₁x₁ + … + wₙxₙJeder Koeffizient wᵢ gibt die Änderung der Log-Odds für eine Einheitserhöhung in Feature xᵢ an, wenn alle anderen Features konstant gehalten werden. Das macht die logistische Regression interpretierbar.
Wie Parameter gelernt werden
Anders als bei der linearen Regression gibt es keine geschlossene Lösung. Das Modell minimiert die Log-Loss-Kostenfunktion (Kreuzentropie) mit einem iterativen Optimierer (standardmäßig lbfgs in scikit-learn):
Loss = -1/m Σ [ yᵢ log(p̂ᵢ) + (1 - yᵢ) log(1 - p̂ᵢ) ]Ein niedrigerer Log-Loss bedeutet, dass die vorhergesagten Wahrscheinlichkeiten besser auf die tatsächlichen Labels kalibriert sind.
Binäre Klassifikation in Python
Das folgende Beispiel verwendet den Breast-Cancer-Wisconsin-Datensatz – 569 Stichproben, 30 numerische Features, binäres Ziel (bösartig = 1, gutartig = 0). Er ist in scikit-learn enthalten, sodass keine externen Dateien benötigt werden.
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, classification_report
# 1. Load data
data = load_breast_cancer()
X, y = data.data, data.target # X: (569, 30) y: 0=malignant, 1=benign
# 2. Split into train (80 %) and test (20 %)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 3. Scale features — logistic regression converges faster and more reliably
# when features are on a similar scale
scaler = StandardScaler()
X_train_sc = scaler.fit_transform(X_train)
X_test_sc = scaler.transform(X_test)
# 4. Train
clf = LogisticRegression(max_iter=1000, random_state=42)
clf.fit(X_train_sc, y_train)
# 5. Evaluate
y_pred = clf.predict(X_test_sc)
print(f"Accuracy: {accuracy_score(y_test, y_pred):.3f}")
print(classification_report(y_test, y_pred, target_names=data.target_names))Erwartete Ausgabe:
Accuracy: 0.974
precision recall f1-score support
malignant 0.98 0.95 0.96 43
benign 0.97 0.99 0.98 71
accuracy 0.97 114
macro avg 0.97 0.97 0.97 114
weighted avg 0.97 0.97 0.97 114Das Modell erreicht ~97 % Genauigkeit auf den zurückgehaltenen Daten. Beachten Sie, dass scikit-learns LogisticRegression standardmäßig L2-Regularisierung hinzufügt (C=1.0), was die Generalisierung verbessert.
Warum Feature-Skalierung wichtig ist
Logistische Regression verwendet gradientenbasierte Optimierung. Ohne Skalierung dominiert ein Feature mit großen Werten (z. B. mittlerer Radius ~14) die Gradientenaktualisierungen, verlangsamt die Konvergenz oder lässt den Solver versagen. StandardScaler transformiert jedes Feature auf null Mittelwert und Einheitsvarianz.
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
data = load_breast_cancer()
X, y = data.data, data.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# Without scaling — needs more iterations, may warn about convergence
clf_raw = LogisticRegression(max_iter=200, random_state=42)
clf_raw.fit(X_train, y_train)
print(f"Unscaled accuracy : {clf_raw.score(X_test, y_test):.3f}")
# With scaling
scaler = StandardScaler()
clf_sc = LogisticRegression(max_iter=200, random_state=42)
clf_sc.fit(scaler.fit_transform(X_train), y_train)
print(f"Scaled accuracy : {clf_sc.score(scaler.transform(X_test), y_test):.3f}")Passen Sie den Scaler immer nur auf den Trainingsdatensatz an und verwenden Sie denselben angepassten Scaler zum Transformieren von Trainings- und Testdaten – das verhindert Datenlecks.
Bewertung eines Klassifikators
Genauigkeit allein kann irreführend sein, wenn die Klassen unausgewogen sind. Verwenden Sie eine Konfusionsmatrix und die daraus abgeleiteten Metriken.
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt
data = load_breast_cancer()
X, y = data.data, data.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
scaler = StandardScaler()
X_train_sc = scaler.fit_transform(X_train)
X_test_sc = scaler.transform(X_test)
clf = LogisticRegression(max_iter=1000, random_state=42)
clf.fit(X_train_sc, y_train)
y_pred = clf.predict(X_test_sc)
cm = confusion_matrix(y_test, y_pred)
disp = ConfusionMatrixDisplay(cm, display_labels=data.target_names)
disp.plot(cmap="Blues")
plt.title("Logistic Regression — Breast Cancer")
plt.tight_layout()
plt.savefig("confusion_matrix.png", dpi=150)
plt.show()Wichtige Metriken aus der Konfusionsmatrix:
| Metrik | Formel | Bedeutung |
|---|---|---|
| Präzision | TP / (TP + FP) | Von allen vorhergesagten Positiven, wie viele sind wirklich positiv |
| Recall (Sensitivität) | TP / (TP + FN) | Von allen tatsächlichen Positiven, wie viele hat das Modell erkannt |
| F1-Score | 2 × (P × R) / (P + R) | Harmonisches Mittel aus Präzision und Recall |
| Spezifität | TN / (TN + FP) | Von allen tatsächlichen Negativen, wie viele hat das Modell korrekt abgelehnt |
Bei der medizinischen Diagnose ist der Recall (Sensitivität) oft wichtiger als die Präzision – ein übersehener bösartiger Befund ist schlimmer als ein falscher Alarm.
Wahrscheinlichkeits-Scores und die AUC-ROC-Kurve
Anstelle einer harten Vorhersage kann die Wahrscheinlichkeit der positiven Klasse mit predict_proba() abgerufen werden:
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import roc_auc_score
data = load_breast_cancer()
X, y = data.data, data.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
scaler = StandardScaler()
clf = LogisticRegression(max_iter=1000, random_state=42)
clf.fit(scaler.fit_transform(X_train), y_train)
# Probability of the positive class (benign = 1)
y_proba = clf.predict_proba(scaler.transform(X_test))[:, 1]
print(f"AUC-ROC: {roc_auc_score(y_test, y_proba):.3f}")Erwartete Ausgabe:
AUC-ROC: 0.997Ein AUC-Wert nahe 1,0 bedeutet, dass das Modell positive Stichproben fast perfekt über negative einordnet. Im Kapitel zur AUC-ROC-Kurve erfahren Sie, wie die vollständige Kurve gezeichnet und interpretiert wird.
Mehrklassen-Klassifikation
Wenn das Ziel mehr als zwei Klassen hat, erweitert scikit-learn die logistische Regression automatisch. Ab scikit-learn 1.5 verwendet der lbfgs-Solver immer den Multinomial-(Softmax-)Ansatz, der ein einzelnes Modell mit einer Softmax-Ausgabeschicht trainiert und die Kreuzentropie über alle Klassen gemeinsam minimiert. Dies ist im Allgemeinen genauer als die ältere One-vs-Rest-(OvR-)Strategie, die einen separaten binären Klassifikator pro Klasse trainierte.
Der Iris-Datensatz enthält drei Blumenarten – ein natürliches Mehrklassen-Beispiel:
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score
data = load_iris()
X, y = data.data, data.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
scaler = StandardScaler()
X_train_sc = scaler.fit_transform(X_train)
X_test_sc = scaler.transform(X_test)
# From scikit-learn 1.5+, multinomial softmax is the default for lbfgs
clf = LogisticRegression(solver="lbfgs", max_iter=1000, random_state=42)
clf.fit(X_train_sc, y_train)
y_pred = clf.predict(X_test_sc)
print(f"Accuracy: {accuracy_score(y_test, y_pred):.3f}")
# Class probabilities for the first three test samples
print("\nClass probabilities (first 3 samples):")
for proba in clf.predict_proba(X_test_sc)[:3]:
print([f"{p:.3f}" for p in proba])Erwartete Ausgabe:
Accuracy: 1.000
Class probabilities (first 3 samples):
['0.011', '0.876', '0.113']
['0.964', '0.036', '0.000']
['0.000', '0.003', '0.997']Regularisierung
Regularisierung bestraft große Koeffizienten, um Overfitting zu verhindern. scikit-learn bietet zwei Typen über den Parameter penalty:
| Parameter | Typ | Auswirkung |
|---|---|---|
penalty='l2' (Standard) | Ridge | Schrumpft alle Koeffizienten gegen null; behält alle Features |
penalty='l1' | Lasso | Treibt einige Koeffizienten genau auf null; implizite Feature-Selektion |
penalty='elasticnet' | Mix | Kombiniert L1 und L2; erfordert solver='saga' |
penalty=None | Keine | Keine Regularisierung; nur verwenden, wenn die Daten groß und sauber sind |
Die Stärke der Regularisierung wird durch C gesteuert (der Kehrwert der Regularisierungsstärke – kleineres C bedeutet stärkere Regularisierung):
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
import numpy as np
data = load_breast_cancer()
X, y = data.data, data.target
results = {}
for C in [0.001, 0.01, 0.1, 1.0, 10.0, 100.0]:
pipe = Pipeline([
("scaler", StandardScaler()),
("clf", LogisticRegression(C=C, max_iter=1000, random_state=42)),
])
scores = cross_val_score(pipe, X, y, cv=5, scoring="accuracy")
results[C] = scores.mean()
print(f"C={C:7.3f} CV accuracy: {scores.mean():.4f} ± {scores.std():.4f}")Dabei wird Kreuzvalidierung verwendet, um den C-Wert zu finden, der am besten generalisiert. Für eine systematische Suche über mehrere Hyperparameter siehe Grid Search.
Verwendung einer Pipeline
Eine Pipeline verbindet die Vorverarbeitung und das Modell zu einem einzigen Objekt. Das verhindert versehentliche Datenlecks und vereinfacht Kreuzvalidierung und Deployment:
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
data = load_breast_cancer()
X, y = data.data, data.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
pipe = Pipeline([
("scaler", StandardScaler()),
("clf", LogisticRegression(C=1.0, max_iter=1000, random_state=42)),
])
pipe.fit(X_train, y_train)
y_pred = pipe.predict(X_test)
print(f"Accuracy: {accuracy_score(y_test, y_pred):.3f}")
# Predict probabilities on a new sample (raw, unscaled)
new_sample = X_test[:1] # first test sample
print(f"Predicted class : {pipe.predict(new_sample)[0]}")
print(f"Class probability : {pipe.predict_proba(new_sample)[0]}")Erwartete Ausgabe:
Accuracy: 0.974
Predicted class : 1
Class probability : [0.11359025 0.88640975]Die Pipeline übernimmt die Skalierung intern – Sie rufen predict() mit rohen Feature-Werten auf.
Koeffizienten inspizieren
Die trainierten Koeffizienten zeigen, welche Features die Vorhersage in Richtung jeder Klasse treiben. Größere absolute Werte bedeuten einen stärkeren Einfluss:
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
import numpy as np
data = load_breast_cancer()
X, y = data.data, data.target
scaler = StandardScaler()
clf = LogisticRegression(max_iter=1000, random_state=42)
clf.fit(scaler.fit_transform(X), y)
# Sort by absolute coefficient value
coefs = clf.coef_[0] # shape (n_features,) for binary classification
sorted_idx = np.argsort(np.abs(coefs))[::-1]
print(f"{'Feature':<35} {'Coefficient':>12}")
print("-" * 48)
for i in sorted_idx[:5]:
print(f"{data.feature_names[i]:<35} {coefs[i]:>12.4f}")Erwartete Ausgabe (Top-5-Features nach absolutem Gewicht):
Feature Coefficient
------------------------------------------------
worst texture -1.3206
radius error -1.2893
worst radius -1.0266
area error -0.9989
worst area -0.9947Negative Koeffizienten (nach Skalierung) treiben in Richtung Klasse 0 (bösartig); positive Koeffizienten treiben in Richtung Klasse 1 (gutartig).
Vorteile und Einschränkungen
Wann logistische Regression verwendet werden sollte
- Sie benötigen Wahrscheinlichkeitsschätzungen, nicht nur Klassen-Labels.
- Die Beziehung zwischen Features und den Log-Odds ist annähernd linear.
- Sie benötigen ein interpretierbares Modell – Koeffizienten sind aussagekräftig.
- Als schnelle Basislinie, bevor komplexere Modelle wie Entscheidungsbäume oder Ensemble-Methoden ausprobiert werden.
- Datensätze sind groß (logistische Regression skaliert gut mit vielen Stichproben).
Einschränkungen
| Einschränkung | Abhilfemaßnahme |
|---|---|
| Setzt eine lineare Entscheidungsgrenze voraus | Verwenden Sie Polynomfeatures oder wechseln Sie zu Entscheidungsbaum / K-Nearest Neighbors |
| Empfindlich gegenüber Feature-Skalierung | Wenden Sie immer StandardScaler oder MinMaxScaler an |
| Probleme bei stark korrelierten Features | Entfernen oder regularisieren Sie mit L1 (penalty='l1') |
| Nicht geeignet für sehr komplexe Feature-Interaktionen | Verwenden Sie Ensemble-Methoden oder neuronale Netze |
Logistische Regression vs. verwandte Klassifikatoren
| Algorithmus | Entscheidungsgrenze | Skalierung erforderlich | Probabilistische Ausgabe |
|---|---|---|---|
| Logistische Regression | Linear | Ja | Ja (kalibriert) |
| Entscheidungsbaum | Nichtlinear (achsenausgerichtet) | Nein | Ja (weniger kalibriert) |
| K-Nearest Neighbors | Nichtlinear (instanzbasiert) | Ja | Ja |
| Lineare Regression | Linear (kontinuierliche Ausgabe) | Ja | Nein |
Wichtigste Erkenntnisse
- Logistische Regression schätzt eine Wahrscheinlichkeit mithilfe der Sigmoid-Funktion; die Klasse wird durch Schwellenwertbildung dieser Wahrscheinlichkeit zugewiesen.
- Skalieren Sie Features immer mit
StandardScalervor dem Training – es beschleunigt die Konvergenz und verbessert die Genauigkeit. - Verwenden Sie eine Pipeline, um Skalierung und Modell zu bündeln; sie verhindert Datenlecks und vereinfacht das Deployment.
- Bewerten Sie mit Präzision, Recall, F1 und AUC-ROC statt nur mit Genauigkeit, besonders bei unausgewogenen Daten. Siehe die Kapitel zur Konfusionsmatrix und AUC-ROC-Kurve.
- Kontrollieren Sie Overfitting mit dem Parameter
C(kleiner = stärkere Regularisierung); verwenden Sie Kreuzvalidierung oder Grid Search zur Abstimmung. - Für Mehrklassen-Probleme verwenden Sie
solver="lbfgs"(Standard); scikit-learn 1.5+ verwendet immer Softmax (multinomial), das überlappende Klassen gut behandelt.