Spec-Zone.ru › scikit-learn

Примечание

Перейти к концу для скачивания полного примера кода. или запустить этот пример в вашем браузере через JupyterLite или Binder

Комбинирование предикторов с помощью стекинга

Стекинг представляет собой метод объединения оценок. В этой стратегии некоторые оценки индивидуально подгоняются к некоторым обучающим данным, а конечная оценка обучается с использованием прогнозов этих базовых оценок.

В этом примере мы иллюстрируем случай, когда различные регрессоры объединяются вместе, а для вывода прогноза используется конечный линейный регрессор с регуляризацией. Мы сравниваем производительность каждого отдельного регрессора со стратегией стекинга. Стекинг немного улучшает общую производительность.

# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause

Загрузка набора данных

Мы будем использовать набор данных о ценах на жилье в Амесе (Ames Housing), который был первоначально собран Дином де Коком и стал более известным после использования в конкурсе Kaggle. Это набор из 1460 домов в Амесе, штат Айова, каждый описанный 80 характеристиками. Мы будем использовать его для прогнозирования логарифмической цены домов. В этом примере мы будем использовать только 20 наиболее интересных признаков, выбранных с помощью GradientBoostingRegressor(), и ограничим количество записей (здесь мы не будем подробно останавливаться на том, как выбрать наиболее интересные признаки).

Набор данных о ценах на жилье в Амесе не поставляется со scikit-learn, и поэтому мы получим его из OpenML.

import numpy as np

from sklearn.datasets import fetch_openml
from sklearn.utils import shuffle


def load_ames_housing():
    df = fetch_openml(name="house_prices", as_frame=True)
    X = df.data
    y = df.target

    features = [
        "YrSold",
        "HeatingQC",
        "Street",
        "YearRemodAdd",
        "Heating",
        "MasVnrType",
        "BsmtUnfSF",
        "Foundation",
        "MasVnrArea",
        "MSSubClass",
        "ExterQual",
        "Condition2",
        "GarageCars",
        "GarageType",
        "OverallQual",
        "TotalBsmtSF",
        "BsmtFinSF1",
        "HouseStyle",
        "MiscFeature",
        "MoSold",
    ]

    X = X.loc[:, features]
    X, y = shuffle(X, y, random_state=0)

    X = X.iloc[:600]
    y = y.iloc[:600]
    return X, np.log(y)


X, y = load_ames_housing()

Создание конвейера для предобработки данных

Прежде чем мы сможем использовать набор данных Ames, нам все еще нужно выполнить некоторую предобработку. Сначала мы выберем категориальные и числовые столбцы набора данных, чтобы построить первый этап конвейера.

from sklearn.compose import make_column_selector

cat_selector = make_column_selector(dtype_include=object)
num_selector = make_column_selector(dtype_include=np.number)
cat_selector(X)
['HeatingQC', 'Street', 'Heating', 'MasVnrType', 'Foundation', 'ExterQual', 'Condition2', 'GarageType', 'HouseStyle', 'MiscFeature']
num_selector(X)
['YrSold', 'YearRemodAdd', 'BsmtUnfSF', 'MasVnrArea', 'MSSubClass', 'GarageCars', 'OverallQual', 'TotalBsmtSF', 'BsmtFinSF1', 'MoSold']

Затем нам нужно разработать конвейеры предобработки, которые зависят от конечного регрессора. Если конечный регрессор — линейная модель, необходимо выполнить one-hot кодирование категорий. Если конечный регрессор — модель на основе деревьев, будет достаточно порядкового кодировщика. Кроме того, числовые значения необходимо стандартизировать для линейной модели, а исходные числовые данные можно обрабатывать так же, как и моделью на основе деревьев. Однако обе модели нуждаются в импьютере для обработки пропущенных значений.

Сначала мы разработаем конвейер, необходимый для моделей на основе деревьев.

from sklearn.compose import make_column_transformer
from sklearn.impute import SimpleImputer
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import OrdinalEncoder

cat_tree_processor = OrdinalEncoder(
    handle_unknown="use_encoded_value",
    unknown_value=-1,
    encoded_missing_value=-2,
)
num_tree_processor = SimpleImputer(strategy="mean", add_indicator=True)

tree_preprocessor = make_column_transformer(
    (num_tree_processor, num_selector), (cat_tree_processor, cat_selector)
)
tree_preprocessor
ColumnTransformer(transformers=[('simpleimputer',
                                 SimpleImputer(add_indicator=True),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                ('ordinalencoder',
                                 OrdinalEncoder(encoded_missing_value=-2,
                                                handle_unknown='use_encoded_value',
                                                unknown_value=-1),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])
В среде Jupyter, пожалуйста, перезапустите этот ячейку, чтобы отобразить HTML-представление, или доверьтесь блокноту.
На GitHub отображение HTML-представления невозможно, пожалуйста, попробуйте загрузить эту страницу с nbviewer.org.
ColumnTransformer(transformers=[('simpleimputer',
                                 SimpleImputer(add_indicator=True),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                ('ordinalencoder',
                                 OrdinalEncoder(encoded_missing_value=-2,
                                                handle_unknown='use_encoded_value',
                                                unknown_value=-1),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>
SimpleImputer(add_indicator=True)
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>
OrdinalEncoder(encoded_missing_value=-2, handle_unknown='use_encoded_value',
               unknown_value=-1)


Затем мы определим предобработчик, используемый, когда конечный регрессор — линейная модель.

from sklearn.preprocessing import OneHotEncoder, StandardScaler

cat_linear_processor = OneHotEncoder(handle_unknown="ignore")
num_linear_processor = make_pipeline(
    StandardScaler(), SimpleImputer(strategy="mean", add_indicator=True)
)

linear_preprocessor = make_column_transformer(
    (num_linear_processor, num_selector), (cat_linear_processor, cat_selector)
)
linear_preprocessor
ColumnTransformer(transformers=[('pipeline',
                                 Pipeline(steps=[('standardscaler',
                                                  StandardScaler()),
                                                 ('simpleimputer',
                                                  SimpleImputer(add_indicator=True))]),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                ('onehotencoder',
                                 OneHotEncoder(handle_unknown='ignore'),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])
В среде Jupyter, пожалуйста, перезапустите этот ячейку, чтобы отобразить HTML-представление, или доверьтесь блокноту.
На GitHub отображение HTML-представления невозможно, пожалуйста, попробуйте загрузить эту страницу с nbviewer.org.
ColumnTransformer(transformers=[('pipeline',
                                 Pipeline(steps=[('standardscaler',
                                                  StandardScaler()),
                                                 ('simpleimputer',
                                                  SimpleImputer(add_indicator=True))]),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                ('onehotencoder',
                                 OneHotEncoder(handle_unknown='ignore'),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>
StandardScaler()
SimpleImputer(add_indicator=True)
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>
OneHotEncoder(handle_unknown='ignore')


Стек предикторов на одном наборе данных

Иногда бывает сложно найти модель, которая будет лучше всего работать с заданным набором данных. Стек предоставляет альтернативу, объединяя выходы нескольких алгоритмов машинного обучения, без необходимости выбирать конкретную модель. Производительность стека обычно близка к производительности лучшей модели, и иногда она может превосходить производительность прогнозирования каждой отдельной модели.

Здесь мы объединяем 3 алгоритма машинного обучения (линейный и нелинейный) и используем RidgeRegressor для объединения их выходных данных.

Примечание

Хотя мы создадим новые конвейеры с процессорами, которые мы написали в предыдущем разделе для 3 алгоритмов машинного обучения, конечному оценщику RidgeCV() не требуется предварительная обработка данных, поскольку он будет получать уже обработанные выходные данные от 3 алгоритмов машинного обучения.

from sklearn.linear_model import LassoCV

lasso_pipeline = make_pipeline(linear_preprocessor, LassoCV())
lasso_pipeline
Pipeline(steps=[('columntransformer',
                 ColumnTransformer(transformers=[('pipeline',
                                                  Pipeline(steps=[('standardscaler',
                                                                   StandardScaler()),
                                                                  ('simpleimputer',
                                                                   SimpleImputer(add_indicator=True))]),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                                 ('onehotencoder',
                                                  OneHotEncoder(handle_unknown='ignore'),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])),
                ('lassocv', LassoCV())])
В среде Jupyter, пожалуйста, заново выполните эту ячейку, чтобы показать HTML-представление или доверьтесь блокноту.
На GitHub HTML-представление не может быть отображено, пожалуйста, попробуйте загрузить эту страницу с помощью nbviewer.org.
Pipeline(steps=[('columntransformer',
                 ColumnTransformer(transformers=[('pipeline',
                                                  Pipeline(steps=[('standardscaler',
                                                                   StandardScaler()),
                                                                  ('simpleimputer',
                                                                   SimpleImputer(add_indicator=True))]),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                                 ('onehotencoder',
                                                  OneHotEncoder(handle_unknown='ignore'),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])),
                ('lassocv', LassoCV())])
ColumnTransformer(transformers=[('pipeline',
                                 Pipeline(steps=[('standardscaler',
                                                  StandardScaler()),
                                                 ('simpleimputer',
                                                  SimpleImputer(add_indicator=True))]),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                ('onehotencoder',
                                 OneHotEncoder(handle_unknown='ignore'),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>
StandardScaler()
SimpleImputer(add_indicator=True)
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>
OneHotEncoder(handle_unknown='ignore')
LassoCV()


from sklearn.ensemble import RandomForestRegressor

rf_pipeline = make_pipeline(tree_preprocessor, RandomForestRegressor(random_state=42))
rf_pipeline
Pipeline(steps=[('columntransformer',
                 ColumnTransformer(transformers=[('simpleimputer',
                                                  SimpleImputer(add_indicator=True),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                                 ('ordinalencoder',
                                                  OrdinalEncoder(encoded_missing_value=-2,
                                                                 handle_unknown='use_encoded_value',
                                                                 unknown_value=-1),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])),
                ('randomforestregressor',
                 RandomForestRegressor(random_state=42))])
В среде Jupyter, пожалуйста, заново выполните эту ячейку, чтобы показать HTML-представление или доверьтесь блокноту.
На GitHub HTML-представление не может быть отображено, пожалуйста, попробуйте загрузить эту страницу с помощью nbviewer.org.
Pipeline(steps=[('columntransformer',
                 ColumnTransformer(transformers=[('simpleimputer',
                                                  SimpleImputer(add_indicator=True),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                                 ('ordinalencoder',
                                                  OrdinalEncoder(encoded_missing_value=-2,
                                                                 handle_unknown='use_encoded_value',
                                                                 unknown_value=-1),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])),
                ('randomforestregressor',
                 RandomForestRegressor(random_state=42))])
ColumnTransformer(transformers=[('simpleimputer',
                                 SimpleImputer(add_indicator=True),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                ('ordinalencoder',
                                 OrdinalEncoder(encoded_missing_value=-2,
                                                handle_unknown='use_encoded_value',
                                                unknown_value=-1),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>
SimpleImputer(add_indicator=True)
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>
OrdinalEncoder(encoded_missing_value=-2, handle_unknown='use_encoded_value',
               unknown_value=-1)
RandomForestRegressor(random_state=42)


from sklearn.ensemble import HistGradientBoostingRegressor

gbdt_pipeline = make_pipeline(
    tree_preprocessor, HistGradientBoostingRegressor(random_state=0)
)
gbdt_pipeline
Pipeline(steps=[('columntransformer',
                 ColumnTransformer(transformers=[('simpleimputer',
                                                  SimpleImputer(add_indicator=True),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                                 ('ordinalencoder',
                                                  OrdinalEncoder(encoded_missing_value=-2,
                                                                 handle_unknown='use_encoded_value',
                                                                 unknown_value=-1),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])),
                ('histgradientboostingregressor',
                 HistGradientBoostingRegressor(random_state=0))])
В среде Jupyter, пожалуйста, перезапустите этот ячейку, чтобы отобразить HTML-представление, или доверьтесь блокноту.
На GitHub HTML-представление невозможно отобразить, пожалуйста, попробуйте загрузить эту страницу с nbviewer.org.
Pipeline(steps=[('columntransformer',
                 ColumnTransformer(transformers=[('simpleimputer',
                                                  SimpleImputer(add_indicator=True),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                                 ('ordinalencoder',
                                                  OrdinalEncoder(encoded_missing_value=-2,
                                                                 handle_unknown='use_encoded_value',
                                                                 unknown_value=-1),
                                                  <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])),
                ('histgradientboostingregressor',
                 HistGradientBoostingRegressor(random_state=0))])
ColumnTransformer(transformers=[('simpleimputer',
                                 SimpleImputer(add_indicator=True),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                ('ordinalencoder',
                                 OrdinalEncoder(encoded_missing_value=-2,
                                                handle_unknown='use_encoded_value',
                                                unknown_value=-1),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>
SimpleImputer(add_indicator=True)
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>
OrdinalEncoder(encoded_missing_value=-2, handle_unknown='use_encoded_value',
               unknown_value=-1)
HistGradientBoostingRegressor(random_state=0)


from sklearn.ensemble import StackingRegressor
from sklearn.linear_model import RidgeCV

estimators = [
    ("Random Forest", rf_pipeline),
    ("Lasso", lasso_pipeline),
    ("Gradient Boosting", gbdt_pipeline),
]

stacking_regressor = StackingRegressor(estimators=estimators, final_estimator=RidgeCV())
stacking_regressor
StackingRegressor(estimators=[('Random Forest',
                               Pipeline(steps=[('columntransformer',
                                                ColumnTransformer(transformers=[('simpleimputer',
                                                                                 SimpleImputer(add_indicator=True),
                                                                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                                                                ('ordinalencoder',
                                                                                 OrdinalEncoder(encoded_missing_value=-2,
                                                                                                handle_unknown='use_encoded_value',
                                                                                                unknown_v...
                                                                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                                                                ('ordinalencoder',
                                                                                 OrdinalEncoder(encoded_missing_value=-2,
                                                                                                handle_unknown='use_encoded_value',
                                                                                                unknown_value=-1),
                                                                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])),
                                               ('histgradientboostingregressor',
                                                HistGradientBoostingRegressor(random_state=0))]))],
                  final_estimator=RidgeCV())
В среде Jupyter, пожалуйста, перезапустите этот ячейку, чтобы отобразить HTML-представление, или доверьтесь блокноту.
На GitHub HTML-представление невозможно отобразить, пожалуйста, попробуйте загрузить эту страницу с nbviewer.org.
StackingRegressor(estimators=[('Random Forest',
                               Pipeline(steps=[('columntransformer',
                                                ColumnTransformer(transformers=[('simpleimputer',
                                                                                 SimpleImputer(add_indicator=True),
                                                                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                                                                ('ordinalencoder',
                                                                                 OrdinalEncoder(encoded_missing_value=-2,
                                                                                                handle_unknown='use_encoded_value',
                                                                                                unknown_v...
                                                                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                                                                ('ordinalencoder',
                                                                                 OrdinalEncoder(encoded_missing_value=-2,
                                                                                                handle_unknown='use_encoded_value',
                                                                                                unknown_value=-1),
                                                                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])),
                                               ('histgradientboostingregressor',
                                                HistGradientBoostingRegressor(random_state=0))]))],
                  final_estimator=RidgeCV())
ColumnTransformer(transformers=[('simpleimputer',
                                 SimpleImputer(add_indicator=True),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                ('ordinalencoder',
                                 OrdinalEncoder(encoded_missing_value=-2,
                                                handle_unknown='use_encoded_value',
                                                unknown_value=-1),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>
SimpleImputer(add_indicator=True)
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>
OrdinalEncoder(encoded_missing_value=-2, handle_unknown='use_encoded_value',
               unknown_value=-1)
RandomForestRegressor(random_state=42)
ColumnTransformer(transformers=[('pipeline',
                                 Pipeline(steps=[('standardscaler',
                                                  StandardScaler()),
                                                 ('simpleimputer',
                                                  SimpleImputer(add_indicator=True))]),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                ('onehotencoder',
                                 OneHotEncoder(handle_unknown='ignore'),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>
StandardScaler()
SimpleImputer(add_indicator=True)
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>
OneHotEncoder(handle_unknown='ignore')
LassoCV()
ColumnTransformer(transformers=[('simpleimputer',
                                 SimpleImputer(add_indicator=True),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>),
                                ('ordinalencoder',
                                 OrdinalEncoder(encoded_missing_value=-2,
                                                handle_unknown='use_encoded_value',
                                                unknown_value=-1),
                                 <sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>)])
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b7032400>
SimpleImputer(add_indicator=True)
<sklearn.compose._column_transformer.make_column_selector object at 0x7656b70323a0>
OrdinalEncoder(encoded_missing_value=-2, handle_unknown='use_encoded_value',
               unknown_value=-1)
HistGradientBoostingRegressor(random_state=0)
RidgeCV()


Измерение и построение результатов

Теперь мы можем использовать набор данных Ames Housing для прогнозирования. Мы проверяем производительность каждого отдельного предиктора, а также стека регрессоров.

import time

import matplotlib.pyplot as plt

from sklearn.metrics import PredictionErrorDisplay
from sklearn.model_selection import cross_val_predict, cross_validate

fig, axs = plt.subplots(2, 2, figsize=(9, 7))
axs = np.ravel(axs)

for ax, (name, est) in zip(
    axs, estimators + [("Stacking Regressor", stacking_regressor)]
):
    scorers = {"R2": "r2", "MAE": "neg_mean_absolute_error"}

    start_time = time.time()
    scores = cross_validate(
        est, X, y, scoring=list(scorers.values()), n_jobs=-1, verbose=0
    )
    elapsed_time = time.time() - start_time

    y_pred = cross_val_predict(est, X, y, n_jobs=-1, verbose=0)
    scores = {
        key: (
            f"{np.abs(np.mean(scores[f'test_{value}'])):.2f} +- "
            f"{np.std(scores[f'test_{value}']):.2f}"
        )
        for key, value in scorers.items()
    }

    display = PredictionErrorDisplay.from_predictions(
        y_true=y,
        y_pred=y_pred,
        kind="actual_vs_predicted",
        ax=ax,
        scatter_kwargs={"alpha": 0.2, "color": "tab:blue"},
        line_kwargs={"color": "tab:red"},
    )
    ax.set_title(f"{name}\nEvaluation in {elapsed_time:.2f} seconds")

    for name, score in scores.items():
        ax.plot([], [], " ", label=f"{name}: {score}")
    ax.legend(loc="upper left")

plt.suptitle("Single predictors versus stacked predictors")
plt.tight_layout()
plt.subplots_adjust(top=0.9)
plt.show()
Single predictors versus stacked predictors, Random Forest Evaluation in 1.23 seconds, Lasso Evaluation in 0.36 seconds, Gradient Boosting Evaluation in 0.48 seconds, Stacking Regressor Evaluation in 9.95 seconds

Стек регрессоров объединит сильные стороны различных регрессоров. Однако мы также видим, что обучение стека регрессоров значительно более ресурсоемко.

Общее время выполнения скрипта: (0 минут 24,121 секунды)

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_stack_predictors.ipynb

Download Python source code: plot_stack_predictors.py

Download zipped: plot_stack_predictors.zip

Связанные примеры

График прогнозов индивидуальной и голосования регрессий

Поддержка категориальных признаков в Gradient Boosting

Отображение оценщиков и сложных конвейеров

Регрессия с использованием решающего дерева с AdaBoost

© 2007–2025 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.6/auto_examples/ensemble/plot_stack_predictors.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API