Transformando el objetivo para la regresión lineal

Machine LearningMachine LearningBeginner
Practicar Ahora

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

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este laboratorio, aprenderemos a usar el TransformedTargetRegressor de la biblioteca scikit-learn. Lo aplicaremos a dos conjuntos de datos diferentes para observar los beneficios de transformar los valores de destino antes de entrenar un modelo de regresión lineal. Usaremos datos sintéticos y el conjunto de datos de viviendas de Ames para ilustrar el impacto de transformar los valores de destino.

Consejos sobre la VM

Una vez finalizada la inicialización de la VM, haga clic en la esquina superior izquierda para cambiar a la pestaña Cuaderno y acceder a Jupyter Notebook para practicar.

A veces, es posible que tenga que esperar unos segundos a que Jupyter Notebook termine de cargarse. La validación de operaciones no se puede automatizar debido a las limitaciones de Jupyter Notebook.

Si tiene problemas durante el aprendizaje, no dude en preguntar a Labby. Deje su retroalimentación después de la sesión y resolveremos rápidamente el problema para usted.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL sklearn(("Sklearn")) -.-> sklearn/ModelSelectionandEvaluationGroup(["Model Selection and Evaluation"]) sklearn(("Sklearn")) -.-> sklearn/UtilitiesandDatasetsGroup(["Utilities and Datasets"]) ml(("Machine Learning")) -.-> ml/FrameworkandSoftwareGroup(["Framework and Software"]) sklearn(("Sklearn")) -.-> sklearn/CoreModelsandAlgorithmsGroup(["Core Models and Algorithms"]) sklearn(("Sklearn")) -.-> sklearn/DataPreprocessingandFeatureEngineeringGroup(["Data Preprocessing and Feature Engineering"]) sklearn/CoreModelsandAlgorithmsGroup -.-> sklearn/linear_model("Linear Models") sklearn/DataPreprocessingandFeatureEngineeringGroup -.-> sklearn/preprocessing("Preprocessing and Normalization") sklearn/ModelSelectionandEvaluationGroup -.-> sklearn/model_selection("Model Selection") sklearn/ModelSelectionandEvaluationGroup -.-> sklearn/metrics("Metrics") sklearn/ModelSelectionandEvaluationGroup -.-> sklearn/compose("Composite Estimators") sklearn/UtilitiesandDatasetsGroup -.-> sklearn/datasets("Datasets") ml/FrameworkandSoftwareGroup -.-> ml/sklearn("scikit-learn") subgraph Lab Skills sklearn/linear_model -.-> lab-49321{{"Transformando el objetivo para la regresión lineal"}} sklearn/preprocessing -.-> lab-49321{{"Transformando el objetivo para la regresión lineal"}} sklearn/model_selection -.-> lab-49321{{"Transformando el objetivo para la regresión lineal"}} sklearn/metrics -.-> lab-49321{{"Transformando el objetivo para la regresión lineal"}} sklearn/compose -.-> lab-49321{{"Transformando el objetivo para la regresión lineal"}} sklearn/datasets -.-> lab-49321{{"Transformando el objetivo para la regresión lineal"}} ml/sklearn -.-> lab-49321{{"Transformando el objetivo para la regresión lineal"}} end

Importar las bibliotecas necesarias y cargar datos sintéticos

Comenzamos importando las bibliotecas necesarias y cargando datos sintéticos. Generamos un conjunto de datos de regresión aleatorio sintético y modificamos los objetivos trasladando todos los objetivos de modo que todas las entradas sean no negativas y aplicando una función exponencial para obtener objetivos no lineales que no se pueden ajustar con un modelo lineal simple. Luego usamos una función logarítmica (np.log1p) y una función exponencial (np.expm1) para transformar los objetivos antes de entrenar un modelo de regresión lineal y usarlo para la predicción.

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.compose import TransformedTargetRegressor
from sklearn.linear_model import RidgeCV
from sklearn.metrics import median_absolute_error, r2_score, PredictionErrorDisplay

## Generate synthetic data
X, y = make_regression(n_samples=10_000, noise=100, random_state=0)

## Modify the targets
y = np.expm1((y + abs(y.min())) / 200)
y_trans = np.log1p(y)

Graficar las distribuciones de los objetivos

Graficamos las funciones de densidad de probabilidad del objetivo antes y después de aplicar las funciones logarítmicas.

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

ax0.hist(y, bins=100, density=True)
ax0.set_xlim([0, 2000])
ax0.set_ylabel("Probabilidad")
ax0.set_xlabel("Objetivo")
ax0.set_title("Distribución del objetivo")

ax1.hist(y_trans, bins=100, density=True)
ax1.set_ylabel("Probabilidad")
ax1.set_xlabel("Objetivo")
ax1.set_title("Distribución del objetivo transformado")

f.suptitle("Datos sintéticos", y=1.05)
plt.tight_layout()

Entrenar y evaluar un modelo de regresión lineal en los objetivos originales

Entrenamos y evaluamos un modelo de regresión lineal en los objetivos originales. Debido a la no linealidad, el modelo entrenado no será preciso durante la predicción.

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

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

score = {
    "R2": f"{r2_score(y_test, y_pred_ridge):.3f}",
    "MedAE": f"{median_absolute_error(y_test, y_pred_ridge):.3f}",
}

print("Linear Regression on original targets:")
for key, val in score.items():
    print(f"{key}: {val}")

Entrenar y evaluar un modelo de regresión lineal en los objetivos transformados

Entrenamos y evaluamos un modelo de regresión lineal en los objetivos transformados usando TransformedTargetRegressor. La función logarítmica lineariza los objetivos, lo que permite una mejor predicción incluso con un modelo lineal similar, como lo indica el error absoluto mediano (MedAE).

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)

score = {
    "R2": f"{r2_score(y_test, y_pred_ridge_with_trans_target):.3f}",
    "MedAE": f"{median_absolute_error(y_test, y_pred_ridge_with_trans_target):.3f}",
}

print("\nLinear Regression on transformed targets:")
for key, val in score.items():
    print(f"{key}: {val}")

Graficar valores reales vs valores predichos para ambos modelos

Graficamos los valores reales vs los valores predichos para ambos modelos y agregamos la puntuación en la leyenda de cada eje.

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

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},
)

for ax, y_pred in zip([ax0, ax1], [y_pred_ridge, y_pred_ridge_with_trans_target]):
    for name, score in score.items():
        ax.plot([], [], " ", label=f"{name}={score}")
    ax.legend(loc="upper left")

ax0.set_title("Regresión Ridge \n sin transformación de objetivo")
ax1.set_title("Regresión Ridge \n con transformación de objetivo")
f.suptitle("Datos sintéticos", y=1.05)
plt.tight_layout()

Cargar y preprocesar los datos de la vivienda de Ames

Cargamos el conjunto de datos de la vivienda de Ames y lo preprocesamos manteniendo solo las columnas numéricas y eliminando las columnas con valores de NaN o Inf. El objetivo a predecir es el precio de venta de cada casa.

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

ames = fetch_openml(name="house_prices", as_frame=True, parser="pandas")

## 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()

Graficar las distribuciones del objetivo para los datos de la vivienda de Ames

Graficamos las funciones de densidad de probabilidad del objetivo antes y después de aplicar el QuantileTransformer.

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

ax0.hist(y, bins=100, density=True)
ax0.set_ylabel("Probabilidad")
ax0.set_xlabel("Objetivo")
ax0.set_title("Distribución del objetivo")

ax1.hist(y_trans, bins=100, density=True)
ax1.set_ylabel("Probabilidad")
ax1.set_xlabel("Objetivo")
ax1.set_title("Distribución del objetivo transformado")

f.suptitle("Datos de la vivienda de Ames: precio de venta", y=1.05)
plt.tight_layout()

Entrenar y evaluar un modelo de regresión lineal en los objetivos originales para los datos de la vivienda de Ames

Entrenamos y evaluamos un modelo de regresión lineal en los objetivos originales para los datos de la vivienda de Ames.

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)

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

score = {
    "R2": f"{r2_score(y_test, y_pred_ridge):.3f}",
    "MedAE": f"{median_absolute_error(y_test, y_pred_ridge):.3f}",
}

print("\nLinear Regression on original targets:")
for key, val in score.items():
    print(f"{key}: {val}")

Entrenar y evaluar un modelo de regresión lineal en los objetivos transformados para los datos de la vivienda de Ames

Entrenamos y evaluamos un modelo de regresión lineal en los objetivos transformados utilizando TransformedTargetRegressor para los datos de la vivienda de Ames.

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)

score = {
    "R2": f"{r2_score(y_test, y_pred_ridge_with_trans_target):.3f}",
    "MedAE": f"{median_absolute_error(y_test, y_pred_ridge_with_trans_target):.3f}",
}

print("\nLinear Regression on transformed targets:")
for key, val in score.items():
    print(f"{key}: {val}")

Graficar valores reales vs valores predichos y residuos vs valores predichos para ambos modelos

Graficamos valores reales vs valores predichos y residuos vs valores predichos para ambos modelos y agregamos la puntuación en la leyenda de cada eje.

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

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},
)

for ax, y_pred in zip([ax0[0], ax0[1]], [y_pred_ridge, y_pred_ridge_with_trans_target]):
    for name, score in score.items():
        ax.plot([], [], " ", label=f"{name}={score}")
    ax.legend(loc="upper left")

ax0[0].set_title("Regresión Ridge \n sin transformación del objetivo")
ax0[1].set_title("Regresión Ridge \n con transformación del objetivo")

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("Regresión Ridge \n sin transformación del objetivo")
ax1[1].set_title("Regresión Ridge \n con transformación del objetivo")

f.suptitle("Datos de la vivienda de Ames: precio de venta", y=1.05)
plt.tight_layout()
plt.show()

Resumen

En este laboratorio, aprendimos cómo usar el TransformedTargetRegressor de la biblioteca scikit - learn. Lo aplicamos a dos conjuntos de datos diferentes para observar los beneficios de transformar los valores del objetivo antes de entrenar un modelo de regresión lineal. Utilizamos datos sintéticos y el conjunto de datos de la vivienda de Ames para ilustrar el impacto de la transformación de los valores del objetivo. Observamos que la función logarítmica linealizó los objetivos, lo que permitió una mejor predicción incluso con un modelo lineal similar, como lo reporta el error absoluto mediano (MedAE). También observamos que el efecto del transformador fue más débil para el conjunto de datos de la vivienda de Ames, pero aún así resultó en un aumento del R2 y una gran disminución del MedAE.