Gradient Boosting mit kategorischen Merkmalen

Machine LearningMachine LearningBeginner
Jetzt üben

This tutorial is from open-source community. Access the source code

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Lab verwenden wir den Ames Housing-Datensatz, um verschiedene Methoden zum Umgang mit kategorischen Merkmalen in Gradient Boosting-Schätzern zu vergleichen. Der Datensatz enthält sowohl numerische als auch kategorische Merkmale, und das Ziel ist der Verkaufspreis der Häuser. Wir werden die Leistung von vier verschiedenen Pipelines vergleichen:

  • Das Entfernen der kategorischen Merkmale
  • Die One-Hot-Codierung der kategorischen Merkmale
  • Das Behandeln der kategorischen Merkmale als ordinalwerte
  • Das Verwenden der nativen Kategorieunterstützung in der Gradient Boosting-Schätzung

Wir werden die Pipelines in Bezug auf ihre Anpassungszeiten und Vorhersageleistungen mithilfe von Kreuzvalidierung bewerten.

Tipps für die VM

Nachdem der VM-Start abgeschlossen ist, klicken Sie in der oberen linken Ecke, um zur Registerkarte Notebook zu wechseln und Jupyter Notebook für die Übung zu öffnen.

Manchmal müssen Sie einige Sekunden warten, bis Jupyter Notebook vollständig geladen ist. Die Validierung von Vorgängen kann aufgrund der Einschränkungen in Jupyter Notebook nicht automatisiert werden.

Wenn Sie bei der Lernphase Probleme haben, können Sie Labby gerne fragen. Geben Sie nach der Sitzung Feedback, und wir werden das Problem für Sie prompt beheben.

Lade den Datensatz

Wir werden den Ames Housing-Datensatz mit der fetch_openml-Funktion von Scikit-Learn laden und einen Teilsatz der Merkmale auswählen, um das Beispiel schneller auszuführen. Wir werden auch die kategorischen Merkmale in den Datentyp 'category' umwandeln.

from sklearn.datasets import fetch_openml

X, y = fetch_openml(data_id=42165, as_frame=True, return_X_y=True, parser="pandas")

## Wähle nur einen Teilsatz der Merkmale von X, um das Beispiel schneller auszuführen
categorical_columns_subset = [
    "BldgType",
    "GarageFinish",
    "LotConfig",
    "Functional",
    "MasVnrType",
    "HouseStyle",
    "FireplaceQu",
    "ExterCond",
    "ExterQual",
    "PoolQC",
]

numerical_columns_subset = [
    "3SsnPorch",
    "Fireplaces",
    "BsmtHalfBath",
    "HalfBath",
    "GarageCars",
    "TotRmsAbvGrd",
    "BsmtFinSF1",
    "BsmtFinSF2",
    "GrLivArea",
    "ScreenPorch",
]

X = X[categorical_columns_subset + numerical_columns_subset]
X[categorical_columns_subset] = X[categorical_columns_subset].astype("category")

Baseline-Pipeline - Kategorische Merkmale entfernen

Wir werden eine Pipeline erstellen, in der wir die kategorischen Merkmale entfernen und einen HistGradientBoostingRegressor-Schätzer trainieren.

from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.pipeline import make_pipeline
from sklearn.compose import make_column_transformer
from sklearn.compose import make_column_selector

dropper = make_column_transformer(
    ("drop", make_column_selector(dtype_include="category")), remainder="passthrough"
)
hist_dropped = make_pipeline(dropper, HistGradientBoostingRegressor(random_state=42))

One-Hot-Codierungspipeline

Wir werden eine Pipeline erstellen, in der wir die kategorischen Merkmale mit One-Hot-Codierung kodieren und einen HistGradientBoostingRegressor-Schätzer trainieren.

from sklearn.preprocessing import OneHotEncoder

one_hot_encoder = make_column_transformer(
    (
        OneHotEncoder(sparse_output=False, handle_unknown="ignore"),
        make_column_selector(dtype_include="category"),
    ),
    remainder="passthrough",
)

hist_one_hot = make_pipeline(
    one_hot_encoder, HistGradientBoostingRegressor(random_state=42)
)

Ordinal-Codierungspipeline

Wir werden eine Pipeline erstellen, in der wir die kategorischen Merkmale als ordinalwerte behandeln und einen HistGradientBoostingRegressor-Schätzer trainieren. Wir werden einen OrdinalEncoder verwenden, um die kategorischen Merkmale zu kodieren.

from sklearn.preprocessing import OrdinalEncoder
import numpy as np

ordinal_encoder = make_column_transformer(
    (
        OrdinalEncoder(handle_unknown="use_encoded_value", unknown_value=np.nan),
        make_column_selector(dtype_include="category"),
    ),
    remainder="passthrough",
    verbose_feature_names_out=False,
)

hist_ordinal = make_pipeline(
    ordinal_encoder, HistGradientBoostingRegressor(random_state=42)
)

Pipeline mit nativer Kategorienunterstützung

Wir werden eine Pipeline erstellen, in der wir die native Kategorienunterstützung des HistGradientBoostingRegressor-Schätzers verwenden, um kategorische Merkmale zu behandeln. Wir werden weiterhin einen OrdinalEncoder verwenden, um die Daten vorzubereiten.

hist_native = make_pipeline(
    ordinal_encoder,
    HistGradientBoostingRegressor(
        random_state=42,
        categorical_features=categorical_columns,
    ),
).set_output(transform="pandas")

Modellvergleich

Wir werden die Leistung der vier Pipelines mithilfe von Kreuzvalidierung vergleichen und die Anpassungszeiten und die mittleren absoluten prozentualen Fehlerwerte grafisch darstellen.

from sklearn.model_selection import cross_validate
import matplotlib.pyplot as plt

scoring = "neg_mean_absolute_percentage_error"
n_cv_folds = 3

dropped_result = cross_validate(hist_dropped, X, y, cv=n_cv_folds, scoring=scoring)
one_hot_result = cross_validate(hist_one_hot, X, y, cv=n_cv_folds, scoring=scoring)
ordinal_result = cross_validate(hist_ordinal, X, y, cv=n_cv_folds, scoring=scoring)
native_result = cross_validate(hist_native, X, y, cv=n_cv_folds, scoring=scoring)

def plot_results(figure_title):
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 8))

    plot_info = [
        ("fit_time", "Anpassungszeiten (s)", ax1, None),
        ("test_score", "Mittlerer absoluter prozentualer Fehler", ax2, None),
    ]

    x, width = np.arange(4), 0.9
    for key, title, ax, y_limit in plot_info:
        items = [
            dropped_result[key],
            one_hot_result[key],
            ordinal_result[key],
            native_result[key],
        ]

        mape_cv_mean = [np.mean(np.abs(item)) for item in items]
        mape_cv_std = [np.std(item) for item in items]

        ax.bar(
            x=x,
            height=mape_cv_mean,
            width=width,
            yerr=mape_cv_std,
            color=["C0", "C1", "C2", "C3"],
        )
        ax.set(
            xlabel="Modell",
            title=title,
            xticks=x,
            xticklabels=["Entfernt", "One Hot", "Ordinal", "Nativ"],
            ylim=y_limit,
        )
    fig.suptitle(figure_title)

plot_results("Gradient Boosting auf Ames Housing")

Begrenzung der Anzahl der Aufteilungen

Wir werden die gleiche Analyse mit unteranpassenden Modellen wiederholen, bei denen wir die Gesamtzahl der Aufteilungen künstlich begrenzen, indem wir sowohl die Anzahl der Bäume als auch die Tiefe jedes Baumes begrenzen.

for pipe in (hist_dropped, hist_one_hot, hist_ordinal, hist_native):
    pipe.set_params(
        histgradientboostingregressor__max_depth=3,
        histgradientboostingregressor__max_iter=15,
    )

dropped_result = cross_validate(hist_dropped, X, y, cv=n_cv_folds, scoring=scoring)
one_hot_result = cross_validate(hist_one_hot, X, y, cv=n_cv_folds, scoring=scoring)
ordinal_result = cross_validate(hist_ordinal, X, y, cv=n_cv_folds, scoring=scoring)
native_result = cross_validate(hist_native, X, y, cv=n_cv_folds, scoring=scoring)

plot_results("Gradient Boosting auf Ames Housing (wenige und kleine Bäume)")

Zusammenfassung

In diesem Lab haben wir vier verschiedene Pipelines zur Behandlung von kategorischen Merkmalen in Gradient-Boosting-Schätzern mithilfe des Ames Housing-Datensatzes verglichen. Wir haben festgestellt, dass das Entfernen von kategorischen Merkmalen zu einer schlechteren Vorhersageleistung führt und dass die drei Modelle, die kategorische Merkmale verwendeten, vergleichbare Fehlerraten hatten. Das One-Hot-Codieren der kategorischen Merkmale war bei weitem die langsamste Methode, während das Behandeln der kategorischen Merkmale als ordinalwerte und die Verwendung der nativen Kategorienunterstützung des HistGradientBoostingRegressor-Schätzers ähnliche Anpassungszeiten hatten. Wenn die Gesamtzahl der Aufteilungen begrenzt war, performierte die Strategie der nativen Kategorienunterstützung am besten.