La búsqueda del punto óptimo en una regresión lineal con características numéricas
De acuerdo con el principio de la navaja de Occam, comenzar de manera simple a menudo conduce a conocimientos más profundos, especialmente cuando se construye un modelo predictivo. En esta publicación, utilizando el conjunto de datos de vivienda de Ames, primero identificaremos las características clave que brillan por sí solas. Luego, paso a paso, superpondremos estos conocimientos y observaremos cómo su efecto combinado mejora nuestra capacidad de pronosticar con precisión. A medida que profundicemos, aprovecharemos el poder del Selector de funciones secuenciales (SFS) para examinar las complejidades y resaltar la combinación óptima de funciones. Este enfoque metódico nos guiará hacia el "punto ideal": una combinación armoniosa donde las características seleccionadas maximizan la precisión predictiva de nuestro modelo sin sobrecargarlo con datos innecesarios.
Empecemos.
Descripción general
Esta publicación se divide en tres partes; ellos son:
- De características individuales al impacto colectivo
- Profundizando más con SFS: el poder de la combinación
- Encontrar el “punto ideal” predictivo
De las fortalezas individuales al impacto colectivo
Nuestro primer paso es identificar qué características, entre las innumerables disponibles en el conjunto de datos de Ames, se destacan como predictores poderosos por sí solos. Pasamos a modelos de regresión lineal simples, cada uno dedicado a una de las principales características independientes identificadas en función de su poder predictivo de los precios de la vivienda.
# Load the essential libraries and Ames dataset
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LinearRegression
import pandas as pd
Ames = pd.read_csv("Ames.csv").select_dtypes(include=["int64", "float64"])
Ames.dropna(axis=1, inplace=True)
X = Ames.drop("SalePrice", axis=1)
y = Ames["SalePrice"]
# Initialize the Linear Regression model
model = LinearRegression()
# Prepare to collect feature scores
feature_scores = {}
# Evaluate each feature with cross-validation
for feature in X.columns:
X_single = X[[feature]]
cv_scores = cross_val_score(model, X_single, y)
feature_scores[feature] = cv_scores.mean()
# Identify the top 5 features based on mean CV R² scores
sorted_features = sorted(feature_scores.items(), key=lambda item: item[1], reverse=True)
top_5 = sorted_features[0:5]
# Display the top 5 features and their individual performance
for feature, score in top_5:
print(f"Feature: {feature}, Mean CV R²: {score:.4f}")
Esto generará las 5 características principales que se pueden usar individualmente en una regresión lineal simple:
Feature: OverallQual, Mean CV R²: 0.6183
Feature: GrLivArea, Mean CV R²: 0.5127
Feature: 1stFlrSF, Mean CV R²: 0.3957
Feature: YearBuilt, Mean CV R²: 0.2852
Feature: FullBath, Mean CV R²: 0.2790
La curiosidad nos lleva más lejos: ¿qué pasa si combinamos estas características principales en un único modelo de regresión lineal múltiple? ¿Su poder colectivo superará sus contribuciones individuales?
# Extracting the top 5 features for our multiple linear regression
top_features = [feature for feature, score in top_5]
# Building the model with the top 5 features
X_top = Ames[top_features]
# Evaluating the model with cross-validation
cv_scores_mlr = cross_val_score(model, X_top, y, cv=5, scoring="r2")
mean_mlr_score = cv_scores_mlr.mean()
print(f"Mean CV R² Score for Multiple Linear Regression Model: {mean_mlr_score:.4f}")
Los hallazgos iniciales son prometedores; De hecho, cada característica tiene sus puntos fuertes. Sin embargo, cuando se combinan en un modelo de regresión múltiple, observamos una mejora “decente”, un testimonio de la complejidad de las predicciones de los precios de la vivienda.
Mean CV R² Score for Multiple Linear Regression Model: 0.8003
Este resultado sugiere un potencial sin explotar: ¿podría haber una forma más estratégica de seleccionar y combinar características para lograr una precisión predictiva aún mayor?
Profundizando más con SFS: el poder de la combinación
A medida que ampliamos nuestro uso del Selector de funciones secuenciales (SFS) de $n=1$a $n=5$, entra en juego un concepto importante: el poder de la combinación. Ilustremos a medida que desarrollamos el código anterior:
# Perform Sequential Feature Selector with n=5 and build on above code
from sklearn.feature_selection import SequentialFeatureSelector
sfs = SequentialFeatureSelector(model, n_features_to_select=5)
sfs.fit(X, y)
selected_features = X.columns[sfs.get_support()].to_list()
print(f"Features selected by SFS: {selected_features}")
scores = cross_val_score(model, Ames[selected_features], y)
print(f"Mean CV R² Score using SFS with n=5: {scores.mean():.4f}")
Elegir $n=5$no significa simplemente seleccionar las cinco mejores funciones independientes. Más bien, se trata de identificar el conjunto de cinco características que, cuando se usan juntas, optimizan la capacidad predictiva del modelo:
Features selected by SFS: ['GrLivArea', 'OverallQual', 'YearBuilt', '1stFlrSF', 'KitchenAbvGr']
Mean CV R² Score using SFS with n=5: 0.8056
Este resultado es particularmente esclarecedor cuando lo comparamos con las cinco características principales seleccionadas en función de su poder predictivo independiente. El atributo “FullBath” (no seleccionado por SFS) fue reemplazado por “KitchenAbvGr” en la selección de SFS. Esta divergencia resalta un principio fundamental de la selección de características: es la combinación lo que cuenta. SFS no sólo busca fuertes predictores individuales; busca características que funcionen mejor en conjunto. Esto podría significar seleccionar una característica que, por sí sola, no encabezaría la lista pero que, cuando se combina con otras, mejora la precisión del modelo.
Si se pregunta por qué es así, las características seleccionadas en la combinación deben ser complementarias entre sí en lugar de estar correlacionadas. De esta manera, cada nueva característica proporciona nueva información al predictor en lugar de coincidir con lo que ya se sabe.
Encontrar el “punto ideal” predictivo
El viaje hacia la selección óptima de funciones comienza llevando nuestro modelo al límite. Al considerar inicialmente el máximo de características posibles, obtenemos una visión integral de cómo evoluciona el rendimiento del modelo al agregar cada característica. Esta visualización nos sirve como punto de partida, destacando los rendimientos decrecientes de la previsibilidad del modelo y guiándonos hacia la búsqueda del "punto óptimo". Comencemos ejecutando un Selector de funciones secuenciales (SFS) en todo el conjunto de funciones, trazando el rendimiento para visualizar el impacto de cada adición:
# Performance of SFS from 1 feature to maximum, building on code above:
import matplotlib.pyplot as plt
# Prepare to store the mean CV R² scores for each number of features
mean_scores = []
# Iterate over a range from 1 feature to the maximum number of features available
for n_features_to_select in range(1, len(X.columns)):
sfs = SequentialFeatureSelector(model, n_features_to_select=n_features_to_select)
sfs.fit(X, y)
selected_features = X.columns[sfs.get_support()]
score = cross_val_score(model, X[selected_features], y, cv=5, scoring="r2").mean()
mean_scores.append(score)
# Plot the mean CV R² scores against the number of features selected
plt.figure(figsize=(10, 6))
plt.plot(range(1, len(X.columns)), mean_scores, marker="o")
plt.title("Performance vs. Number of Features Selected")
plt.xlabel("Number of Features")
plt.ylabel("Mean CV R² Score")
plt.grid(True)
plt.show()
El siguiente gráfico demuestra cómo el rendimiento del modelo mejora a medida que se agregan más funciones, pero finalmente se estabiliza, lo que indica un punto de rendimiento decreciente:
En este gráfico se puede ver que utilizar más de diez funciones tiene pocos beneficios. Sin embargo, utilizar tres o menos funciones no es óptimo. Puede utilizar el "método del codo" para encontrar dónde se dobla esta curva y determinar la cantidad óptima de características. Esta es una decisión subjetiva. Esta gráfica sugiere que entre 5 y 9 se ve bien.
Armados con los conocimientos de nuestra exploración inicial, aplicamos una tolerancia (tol=0.005
) a nuestro proceso de selección de funciones. Esto puede ayudarnos a determinar la cantidad óptima de funciones de manera objetiva y sólida:
# Apply Sequential Feature Selector with tolerance = 0.005, building on code above
sfs_tol = SequentialFeatureSelector(model, n_features_to_select="auto", tol=0.005)
sfs_tol.fit(X, y)
# Get the number of features selected with tolerance
n_features_selected = sum(sfs_tol.get_support())
# Prepare to store the mean CV R² scores for each number of features
mean_scores_tol = []
# Iterate over a range from 1 feature to the Sweet Spot
for n_features_to_select in range(1, n_features_selected + 1):
sfs = SequentialFeatureSelector(model, n_features_to_select=n_features_to_select)
sfs.fit(X, y)
selected_features = X.columns[sfs.get_support()]
score = cross_val_score(model, X[selected_features], y, cv=5, scoring="r2").mean()
mean_scores_tol.append(score)
# Plot the mean CV R² scores against the number of features selected
plt.figure(figsize=(10, 6))
plt.plot(range(1, n_features_selected + 1), mean_scores_tol, marker="o")
plt.title("The Sweet Spot: Performance vs. Number of Features Selected")
plt.xlabel("Number of Features")
plt.ylabel("Mean CV R² Score")
plt.grid(True)
plt.show()
Este movimiento estratégico nos permite concentrarnos en aquellas características que brindan la mayor previsibilidad, culminando en la selección de 8 características óptimas:
Ahora podemos concluir nuestros hallazgos mostrando las características seleccionadas por SFS:
# Print the selected features and their performance, building on the above:
selected_features = X.columns[sfs_tol.get_support()]
print(f"Number of features selected: {n_features_selected}")
print(f"Selected features: {selected_features.tolist()}")
print(f"Mean CV R² Score using SFS with tol=0.005: {mean_scores_tol[-1]:.4f}")
Number of features selected: 8
Selected features: ['GrLivArea', 'LotArea', 'OverallQual', 'OverallCond', 'YearBuilt', '1stFlrSF', 'BedroomAbvGr', 'KitchenAbvGr']
Mean CV R² Score using SFS with tol=0.005: 0.8239
Al centrarnos en estas 8 características, logramos un modelo que equilibra la complejidad con una alta previsibilidad, mostrando la efectividad de un enfoque medido para la selección de características.
Lecturas adicionales
API
- API sklearn.feature_selection.SequentialFeatureSelector
Tutoriales
- Selección de largometrajes secuenciales de Sebastian Raschka
Conjunto de datos y diccionario de datos sobre vivienda de Ames
- Conjunto de datos de Ames
- Diccionario de datos Ames
Resumen
A través de esta publicación de tres partes, se ha embarcado en un viaje desde la evaluación del poder predictivo de características individuales hasta el aprovechamiento de sus fortalezas combinadas en un modelo refinado. Nuestra exploración ha demostrado que, si bien más funciones pueden mejorar la capacidad de un modelo para capturar patrones complejos, llega un punto en el que funciones adicionales ya no contribuyen a mejorar las predicciones. Al aplicar un nivel de tolerancia al Selector de funciones secuenciales, se ha perfeccionado un conjunto óptimo de funciones que impulsan el rendimiento de nuestro modelo al máximo sin complicar demasiado el panorama predictivo. Este punto óptimo, identificado como ocho características clave, personifica la combinación estratégica de simplicidad y sofisticación en el modelado predictivo.
Específicamente, aprendiste:
- El arte de empezar de forma sencilla: empezar con modelos de regresión lineal simples para comprender el valor predictivo independiente de cada característica sienta las bases para análisis más complejos.
- Sinergia en la selección: la transición al selector de funciones secuenciales subraya la importancia no solo de las fortalezas de las funciones individuales, sino también de su impacto sinérgico cuando se combinan de manera efectiva.
- Maximizar la eficacia del modelo: la búsqueda del punto óptimo predictivo a través de SFS con una tolerancia establecida nos enseña el valor de la precisión en la selección de funciones, logrando lo máximo con lo mínimo.
¿Tiene alguna pregunta? Haga sus preguntas en los comentarios a continuación y haré todo lo posible para responder.