Praxis: scikit-learn auf PlantVillage

Die komplette Strecke in einem Skript: Features aus der Features-Lektion, Split aus der Pipeline-Lektion, dazu Scaler + Logistic Regression. Das ist die Baseline, an der sich alle weiteren Verfahren messen lassen müssen.

Faustregel: Erst die einfachste sinnvolle Baseline bauen, dann komplexer werden. Ein CNN, das die LogReg-Baseline nur um 1 Punkt schlägt, ist seine Kosten selten wert.

Das komplette Skript

PYTHONlogreg_plantvillage.py
import numpy as np
from pathlib import Path
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report

# ── 1. Pfade + Labels sammeln (siehe Pipeline-Lektion) ──
DATA_DIR = Path("plantvillage dataset/color")
pfade, labels = [], []
for ordner in sorted(DATA_DIR.iterdir()):
    for bild in ordner.glob("*.jpg"):
        pfade.append(bild)
        labels.append(ordner.name)

X_train_p, X_test_p, y_train, y_test = train_test_split(
    pfade, labels, test_size=0.20, stratify=labels, random_state=42
)

# ── 2. Features extrahieren (siehe Features-Lektion) ──
X_train = np.array([extrahiere_features(p) for p in X_train_p])
X_test  = np.array([extrahiere_features(p) for p in X_test_p])

# ── 3. Skalieren: fit NUR auf Train ──
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test  = scaler.transform(X_test)

# ── 4. Trainieren ──
modell = LogisticRegression(
    max_iter=2000,           # Default 100 reicht hier nicht
    C=1.0,                   # Regularisierungsstärke (Tuning-Lektion)
    n_jobs=-1,               # alle CPU-Kerne
)
modell.fit(X_train, y_train)

# ── 5. Evaluieren ──
y_pred = modell.predict(X_test)
print(classification_report(y_test, y_pred, digits=3))

Was dabei herauskommt

Mit 512 HSV-Histogramm-Features liegt die Accuracy typischerweise irgendwo zwischen 70 und 90 % — abhängig von Bins, Bildgröße und ob Textur-Features dazukommen. Das klingt nach viel für ein lineares Modell, ist aber vor allem ein Kompliment an PlantVillage: kontrollierte Fotos, farblich gut trennbare Klassen. Wichtiger als die eine Zahl: der Blick in den classification_report — welche Klassen funktionieren, welche nicht?

Bonus: Das Modell erklären

Der unterschätzte Vorteil der Logistic Regression: Man kann nachsehen, warum sie entscheidet. modell.coef_ hat eine Zeile pro Klasse — die größten Gewichte zeigen, welche Histogramm-Bins (= Farbbereiche) für eine Klasse sprechen:

PYTHONinterpretation.py
klassen = modell.classes_
idx = list(klassen).index("Tomato___Late_blight")
gewichte = modell.coef_[idx]

top = np.argsort(gewichte)[-5:][::-1]
print("Stärkste Farb-Bins für Late Blight:", top)
# → die Bins lassen sich zu HSV-Bereichen zurückrechnen:
#   bin // 64 = Hue-Bereich, (bin // 8) % 8 = Saturation, bin % 8 = Value
Warum eigentlich?Warum max_iter=2000?
Der Default-Solver lbfgs iteriert maximal 100-mal. Bei 512 skalierten Features und 38 Klassen konvergiert er bis dahin oft nicht und wirft eine ConvergenceWarning. Die Gewichte sind dann ein willkürlicher Zwischenstand — das Modell funktioniert scheinbar, ist aber schlechter als es sein könnte. Mehr Iterationen erlauben kostet nur Zeit; die Warnung zu ignorieren kostet Qualität.
Häufiger DenkfehlerDie Warnung wegfiltern statt beheben
Der reflexhafte Griff zu warnings.filterwarnings("ignore") ist hier ein Klassiker. Eine ConvergenceWarning hat immer eine Ursache, meist eine von drei: zu wenige Iterationen (→ max_iter hoch), unskalierte Features (→ Scaler vergessen? Häufigster Fall!) oder fast-redundante Features (→ Regularisierung erhöhen, C senken). Die Warnung ist ein Diagnose-Werkzeug, kein Lärm.
Tiefer reinSauberer: alles in eine sklearn-Pipeline

Scaler und Modell lassen sich zu einem Objekt koppeln — dann ist Leakage konstruktionsbedingt unmöglich, auch bei Cross-Validation:

make_pipeline(StandardScaler(), LogisticRegression(max_iter=2000))

Bei cross_val_score wird der Scaler dann in jedem Fold nur auf dessen Trainings-Teil gefittet — genau das, was man von Hand leicht falsch macht. Für Abgaben und Paper-Code ist die Pipeline-Variante der Standard.