Data Science · Klinik Klinische Datenanalyse & Machine Learning
Ansicht
Lerntiefe
Codeansicht
Farbschema

26 · Baum-Ensembles und Gradient Boosting

modellvergleich_auc.png

Abbildung · Quellcode

modellvergleich_auc

Erzeugt von fig_modellvergleich() in module/26-ensembles-boosting/code/figures.py, Zeile 98–191.

Python
def fig_modellvergleich(X, y, cv) -> None:
    """CV-AUC per model with error bars. Title/caption never hardcode a
    winner -- build.py/README quote whatever this run actually produced."""
    tree = DecisionTreeClassifier(max_depth=4, random_state=SEED)
    rf   = RandomForestClassifier(
        n_estimators=300, max_features="sqrt",
        class_weight="balanced", random_state=SEED, n_jobs=-1,
    )
    hgb  = HistGradientBoostingClassifier(
        max_iter=300, max_depth=5, learning_rate=0.05,
        class_weight="balanced", random_state=SEED,
    )

    model_specs = [
        ("Entscheidungsbaum\n(Tiefe 4)", build_pipeline(tree)),
        ("Random\nForest",               build_pipeline(rf)),
        ("HistGradBoost\n(sklearn)",      build_native_missing_pipeline(hgb)),
    ]

    # Try optional boosters
    pos_weight = float((y == 0).sum()) / float((y == 1).sum())

    try:
        import xgboost as xgb
    except Exception:
        xgb = None

    if xgb is not None:
        try:
            xgb_m = xgb.XGBClassifier(
                n_estimators=300, max_depth=5, learning_rate=0.05,
                scale_pos_weight=pos_weight,
                eval_metric="auc", random_state=SEED, verbosity=0,
                use_label_encoder=False,
            )
        except TypeError:
            xgb_m = xgb.XGBClassifier(
                n_estimators=300, max_depth=5, learning_rate=0.05,
                scale_pos_weight=pos_weight,
                eval_metric="auc", random_state=SEED, verbosity=0,
            )
        model_specs.append(("XGBoost", build_pipeline(xgb_m)))

    try:
        import lightgbm as lgb
    except Exception:
        lgb = None

    if lgb is not None:
        lgb_m = lgb.LGBMClassifier(
            n_estimators=300, max_depth=5, learning_rate=0.05,
            is_unbalance=True, random_state=SEED, verbose=-1,
        )
        model_specs.append(("LightGBM", build_pipeline(lgb_m)))

    names, means, stds = [], [], []
    for name, pipe in model_specs:
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            scores = cross_val_score(pipe, X, y, cv=cv, scoring="roc_auc")
        names.append(name)
        means.append(scores.mean())
        stds.append(scores.std())

    x = np.arange(len(names))
    colors = [PRIMARY, PALETTE[2], PALETTE[4], EVENT, PALETTE[5]][:len(names)]

    # Data-driven verdict for the title -- never a hardcoded winner.
    tree_mean = means[0]
    other_pairs = list(zip(names[1:], means[1:]))
    best_name, best_mean = max(other_pairs, key=lambda t: t[1])
    best_name_plain = best_name.replace("\n", " ").strip()
    gap = best_mean - tree_mean
    if gap > 0.02:
        verdict = f"{best_name_plain} übertrifft den einzelnen Baum"
    elif gap > -0.02:
        verdict = "Ensembles liegen etwa gleichauf mit dem einzelnen Baum"
    else:
        verdict = "der einzelne Baum schneidet hier nicht schlechter ab"

    fig, ax = plt.subplots(figsize=(max(7, len(names) * 1.5), 4.5))
    bars = ax.bar(x, means, yerr=stds, color=colors, width=0.55,
                  capsize=5, error_kw={"lw": 1.5})
    ax.axhline(0.5, color=SECONDARY, lw=0.8, ls="--", label="Zufallsklassifikator")
    for bar, m, s in zip(bars, means, stds):
        ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + s + 0.01,
                f"{m:.3f}", ha="center", va="bottom", fontsize=9, fontweight="bold")
    ax.set_xticks(x)
    ax.set_xticklabels(names, fontsize=10)
    ax.set_ylim(0.4, 1.0)
    ax.set_ylabel("Kreuzvalidierte ROC-AUC (±1 SD)")
    ax.set_title(f"Modellvergleich: Baum-Ensembles & Gradient Boosting\n({verdict}, n≈{len(y)})")
    ax.legend(loc="lower right")
    save(fig, ASSETS / "modellvergleich_auc.png")

← zurück zu Modul 26 · vollständige Datei ansehen