Spec-Zone.ru › scikit-learn

Примечание

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

Влияние преобразования целевых значений в регрессионной модели

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

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

print(__doc__)

Синтетический пример

Создаётся синтетический набор данных случайной регрессии. Целевые значения y модифицируются:

  1. все целевые значения переводятся так, чтобы все значения были неотрицательными (путем добавления абсолютного значения наименьшего y) и
  2. применяется экспоненциальная функция для получения нелинейных целевых значений, которые нельзя подобрать с помощью простой линейной модели.

Поэтому будет использоваться логарифмическая (np.log1p) и экспоненциальная функция (np.expm1) для преобразования целевых значений перед обучением линейной регрессионной модели и её использованием для прогнозирования.

import numpy as np

from sklearn.datasets import make_regression

X, y = make_regression(n_samples=10_000, noise=100, random_state=0)
y = np.expm1((y + abs(y.min())) / 200)
y_trans = np.log1p(y)

Ниже мы отображаем функции плотности вероятности целевого значения до и после применения логарифмических функций.

import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split

f, (ax0, ax1) = plt.subplots(1, 2)

ax0.hist(y, bins=100, density=True)
ax0.set_xlim([0, 2000])
ax0.set_ylabel("Probability")
ax0.set_xlabel("Target")
ax0.set_title("Target distribution")

ax1.hist(y_trans, bins=100, density=True)
ax1.set_ylabel("Probability")
ax1.set_xlabel("Target")
ax1.set_title("Transformed target distribution")

f.suptitle("Synthetic data", y=1.05)
plt.tight_layout()

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
Synthetic data, Target distribution, Transformed target distribution

Сначала будет применена линейная модель к исходным целевым значениям. Из-за нелинейности обученная модель не будет точной при прогнозировании. Впоследствии применяется логарифмическая функция для линеаризации целевых значений, что позволяет улучшить прогнозирование даже с помощью аналогичной линейной модели, как показано по медианной абсолютной ошибке (MedAE).

from sklearn.metrics import median_absolute_error, r2_score


def compute_score(y_true, y_pred):
    return {
        "R2": f"{r2_score(y_true, y_pred):.3f}",
        "MedAE": f"{median_absolute_error(y_true, y_pred):.3f}",
    }
from sklearn.compose import TransformedTargetRegressor
from sklearn.linear_model import RidgeCV
from sklearn.metrics import PredictionErrorDisplay

f, (ax0, ax1) = plt.subplots(1, 2, sharey=True)

ridge_cv = RidgeCV().fit(X_train, y_train)
y_pred_ridge = ridge_cv.predict(X_test)

ridge_cv_with_trans_target = TransformedTargetRegressor(
    regressor=RidgeCV(), func=np.log1p, inverse_func=np.expm1
).fit(X_train, y_train)
y_pred_ridge_with_trans_target = ridge_cv_with_trans_target.predict(X_test)

PredictionErrorDisplay.from_predictions(
    y_test,
    y_pred_ridge,
    kind="actual_vs_predicted",
    ax=ax0,
    scatter_kwargs={"alpha": 0.5},
)
PredictionErrorDisplay.from_predictions(
    y_test,
    y_pred_ridge_with_trans_target,
    kind="actual_vs_predicted",
    ax=ax1,
    scatter_kwargs={"alpha": 0.5},
)

# Add the score in the legend of each axis
for ax, y_pred in zip([ax0, ax1], [y_pred_ridge, y_pred_ridge_with_trans_target]):
    for name, score in compute_score(y_test, y_pred).items():
        ax.plot([], [], " ", label=f"{name}={score}")
    ax.legend(loc="upper left")

ax0.set_title("Ridge regression \n without target transformation")
ax1.set_title("Ridge regression \n with target transformation")
f.suptitle("Synthetic data", y=1.05)
plt.tight_layout()
Synthetic data, Ridge regression   without target transformation, Ridge regression   with target transformation

Данные из реального мира

Аналогичным образом, набор данных Ames по ценам на жильё используется для демонстрации влияния преобразования целевых значений перед обучением модели. В этом примере целевым значением, которое нужно предсказать, является цена продажи каждого дома.

from sklearn.datasets import fetch_openml
from sklearn.preprocessing import quantile_transform

ames = fetch_openml(name="house_prices", as_frame=True)
# Keep only numeric columns
X = ames.data.select_dtypes(np.number)
# Remove columns with NaN or Inf values
X = X.drop(columns=["LotFrontage", "GarageYrBlt", "MasVnrArea"])
# Let the price be in k$
y = ames.target / 1000
y_trans = quantile_transform(
    y.to_frame(), n_quantiles=900, output_distribution="normal", copy=True
).squeeze()

Для нормализации распределения целевого значения перед применением модели RidgeCV используется QuantileTransformer.

f, (ax0, ax1) = plt.subplots(1, 2)

ax0.hist(y, bins=100, density=True)
ax0.set_ylabel("Probability")
ax0.set_xlabel("Target")
ax0.set_title("Target distribution")

ax1.hist(y_trans, bins=100, density=True)
ax1.set_ylabel("Probability")
ax1.set_xlabel("Target")
ax1.set_title("Transformed target distribution")

f.suptitle("Ames housing data: selling price", y=1.05)
plt.tight_layout()
Ames housing data: selling price, Target distribution, Transformed target distribution
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)

Влияние преобразователя слабее, чем на синтетических данных. Однако преобразование приводит к увеличению \(R^2\) и большому снижению MedAE. График остатков (предсказанное целевое значение - истинное целевое значение против предсказанного целевого значения) без преобразования целевого значения имеет криволинейную, «обратно-улыбчивую» форму из-за значений остатков, которые зависят от значения предсказанного целевого значения. С преобразованием целевого значения форма становится более линейной, что указывает на лучшую подгонку модели.

from sklearn.preprocessing import QuantileTransformer

f, (ax0, ax1) = plt.subplots(2, 2, sharey="row", figsize=(6.5, 8))

ridge_cv = RidgeCV().fit(X_train, y_train)
y_pred_ridge = ridge_cv.predict(X_test)

ridge_cv_with_trans_target = TransformedTargetRegressor(
    regressor=RidgeCV(),
    transformer=QuantileTransformer(n_quantiles=900, output_distribution="normal"),
).fit(X_train, y_train)
y_pred_ridge_with_trans_target = ridge_cv_with_trans_target.predict(X_test)

# plot the actual vs predicted values
PredictionErrorDisplay.from_predictions(
    y_test,
    y_pred_ridge,
    kind="actual_vs_predicted",
    ax=ax0[0],
    scatter_kwargs={"alpha": 0.5},
)
PredictionErrorDisplay.from_predictions(
    y_test,
    y_pred_ridge_with_trans_target,
    kind="actual_vs_predicted",
    ax=ax0[1],
    scatter_kwargs={"alpha": 0.5},
)

# Add the score in the legend of each axis
for ax, y_pred in zip([ax0[0], ax0[1]], [y_pred_ridge, y_pred_ridge_with_trans_target]):
    for name, score in compute_score(y_test, y_pred).items():
        ax.plot([], [], " ", label=f"{name}={score}")
    ax.legend(loc="upper left")

ax0[0].set_title("Ridge regression \n without target transformation")
ax0[1].set_title("Ridge regression \n with target transformation")

# plot the residuals vs the predicted values
PredictionErrorDisplay.from_predictions(
    y_test,
    y_pred_ridge,
    kind="residual_vs_predicted",
    ax=ax1[0],
    scatter_kwargs={"alpha": 0.5},
)
PredictionErrorDisplay.from_predictions(
    y_test,
    y_pred_ridge_with_trans_target,
    kind="residual_vs_predicted",
    ax=ax1[1],
    scatter_kwargs={"alpha": 0.5},
)
ax1[0].set_title("Ridge regression \n without target transformation")
ax1[1].set_title("Ridge regression \n with target transformation")

f.suptitle("Ames housing data: selling price", y=1.05)
plt.tight_layout()
plt.show()
Ames housing data: selling price, Ridge regression   without target transformation, Ridge regression   with target transformation, Ridge regression   without target transformation, Ridge regression   with target transformation

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

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_transformed_target.ipynb

Download Python source code: plot_transformed_target.py

Download zipped: plot_transformed_target.zip

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

Изотоническая регрессия

Пайплайнирование: объединение PCA и логистической регрессии

Объединение прогнозов с использованием стекинга

Графическое отображение кросс-валидированных прогнозов

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

Spec-Zone.ru

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