El capítulo de regresión lineal del nivel Básico cerró con una recta de un solo predictor y con su límite: en los 442 pacientes, el índice de masa corporal explicaba por sí solo apenas un tercio de la variación de la respuesta. Con esa base (mínimos cuadrados, ecuaciones normales, residuos, y el error estándar, el intervalo y el p-value de una pendiente), en este primer capítulo del nivel Avanzado das el paso natural: la regresión lineal múltiple, que explica una respuesta con varios predictores a la vez. Recorres el modelo y sus supuestos, exploras los datos antes de ajustar, mides la multicolinealidad con el VIF, evalúas el desempeño predictivo y diagnosticas los residuos.
El ejemplo que guía el capítulo es el consumo energético residencial.
Tiempo estimado de lectura: 65 minutos (unas 2 horas y media si ejecutas el código y respondes las preguntas)
Nivel: Avanzado
Conocimientos previos recomendados: la regresión lineal simple (mínimos cuadrados, residuos e inferencia sobre la pendiente) y la relación entre variables (covarianza y correlación) del nivel Básico.
Los dos conjuntos de datos son simulados con fórmulas que el capítulo muestra en su código: 500 hogares de energía residencial, generados con la semilla SEMILLA = 24, y 450 hogares para la exploración, generados con SEMILLA_DEMO = 2026 y con colinealidad, segmentos, curvatura y atípicos puestos a propósito. No proceden de clientes. Todo corre en CPU, y las versiones se imprimen en la primera celda de código.
Objetivos
Al terminar este capítulo vas a ser capaz de:
escribir el modelo de regresión múltiple e interpretar sus coeficientes como efectos parciales, manteniendo fijos los demás predictores;
explorar un conjunto de datos multivariado buscando redundancia, curvatura, segmentos y atípicos antes de ajustar;
medir la colinealidad con el VIF y explicar en qué se diferencia de una correlación por pares;
distinguir los diagnósticos calculados sobre la muestra de ajuste de la evaluación predictiva en datos no vistos;
detectar los límites de una forma funcional lineal con los residuos y proponer una validación apropiada para corregirla.
Ejecuta las celdas en orden: las secciones comparten variables.
16.1 Qué es el análisis multivariado
En un análisis univariado observas una variable a la vez, y en uno bivariado, la relación entre dos. En un análisis multivariado estudias varias variables simultáneamente, con cuatro propósitos:
Explicar una respuesta con varios predictores. En lugar de suponer que un solo factor determina el resultado, modelas la contribución conjunta de varias variables, lo que representa mejor fenómenos que casi siempre son multifactoriales.
Controlar factores de confusión. Una variable puede distorsionar la relación aparente entre un predictor y la respuesta; incluirla en el modelo ayuda a separar las relaciones y evita conclusiones engañosas.
Estimar efectos parciales. Cada coeficiente se lee como el cambio esperado en la respuesta cuando su variable aumenta una unidad y las demás permanecen fijas. Es una asociación condicional, y atribuirle una causa requiere otros supuestos.
Predecir mejor. Combinar información de varias fuentes suele reducir el error de predicción y producir recomendaciones más útiles para priorizar variables, diseñar intervenciones o asignar recursos.
Una precisión de vocabulario: en sentido estricto, el análisis multivariado estudia varias variables respuesta a la vez, o varias variables sin una respuesta fija, como el PCA. Un modelo con una sola respuesta y varios predictores se llama con más precisión regresión múltiple, y es el caso de este capítulo.
donde \(y\) es la variable objetivo, \(x_1, \ldots, x_D\) son los predictores, \(\beta_j\) es el cambio esperado en \(y\) por una unidad adicional de \(x_j\) con las demás variables constantes, y \(\varepsilon\) es el error, la variación que los predictores no explican, que se supone de media cero. En forma matricial, con \(X\) de \(N\times(D+1)\) (una columna de unos y una por predictor), la solución de mínimos cuadrados es la misma del nivel Básico, \(\hat{\boldsymbol\beta}=(X^\top X)^{-1}X^\top\mathbf y\), con más columnas.
16.3 Por qué importa en IA y machine learning
La regresión múltiple es la forma más simple de un modelo que combina features, y sus problemas reaparecen en modelos más complejos:
Línea base. Antes de un modelo de gradient boosting o una red neuronal, un modelo lineal con las mismas variables fija el error a vencer; en este capítulo, OLS deja un RMSE de 27.66 kWh en prueba frente a un ruido simulado de 25 kWh, así que un modelo más complejo tendría poco margen para mejorar.
Variables redundantes. Dos features que cuentan la misma historia, como ingreso y gasto_electrico_base (correlación 0.87 en la exploración), inflan la varianza de los coeficientes y vuelven inestables las importancias de variables que se reportan en producto.
Ingeniería de variables. La relación en V de la temperatura muestra que la forma funcional se decide antes de ajustar: una feature mal especificada deja estructura en los residuos, sea cual sea el algoritmo.
Evaluación honesta. Separar entrenamiento y prueba, y elegir con validación cruzada solo dentro del entrenamiento, es el mismo protocolo que vas a usar para cualquier modelo de aprendizaje automático (capítulos de evaluación y bootstrap y de validación cruzada).
Lo que distingue a la regresión es que, si se cumplen sus supuestos, sus coeficientes tienen errores estándar e intervalos interpretables, algo que los modelos más flexibles no ofrecen directamente.
16.4 El ejemplo: energía residencial
Quieres explicar el consumo mensual de energía (kWh) de un hogar a partir de cinco variables: la temperatura promedio exterior, el número de ocupantes, el área de la vivienda (m²), un índice de aislamiento térmico y la cantidad de electrodomésticos intensivos. Es un problema naturalmente multivariado, porque una sola variable rara vez explica el consumo por completo.
La primera celda carga las bibliotecas, fija las dos semillas y muestra las versiones del entorno.
# Librerías base para regresión múltipleimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom sklearn.model_selection import train_test_split, cross_val_scorefrom sklearn.linear_model import LinearRegression, Ridge, Lassofrom sklearn.pipeline import Pipelinefrom sklearn.preprocessing import StandardScalerfrom sklearn.metrics import mean_squared_error, mean_absolute_error, r2_scoreimport statsmodels.api as smfrom statsmodels.stats.outliers_influence import variance_inflation_factor# Estilo visual base para mantener uniformidad en todas las graficassns.set_theme(style="whitegrid", context="notebook")plt.rcParams["axes.titlesize"] =12plt.rcParams["axes.labelsize"] =10# Semillas globales para reproducibilidadSEMILLA =24# dataset de energía y partición entrenamiento/pruebaSEMILLA_DEMO =2026# dataset sintético de la exploración (Etapas 1-8)# Versiones del entorno usado para ejecutar este capítulo.import sysimport importlib.metadata as metadatosprint('Python:', sys.version.split()[0])for paquete in ['numpy', 'pandas', 'matplotlib', 'scipy', 'scikit-learn', 'statsmodels']:print(paquete +':', metadatos.version(paquete))import matplotlib.pyplot as pltfrom cycler import cyclerplt.rcParams['axes.prop_cycle'] = cycler(color=['#1786B3', '#EE5400', '#487A35', '#7851A9']) + cycler(linestyle=['-', '--', '-.', ':'])plt.rcParams['font.size'] =10
El entorno queda con Python 3.13.14, NumPy 2.5.1, pandas 3.0.5, SciPy 1.18.0, scikit-learn 1.9.0 y statsmodels 0.14.6.
Ahora generas los 500 hogares de energía. Los predictores salen de distribuciones normales, uniformes y enteras, y el consumo se construye con la regla \(120 + 1.8\,\text{área} + 18\,\text{ocupantes} + 9\,\text{electrodomésticos} - 55\,\text{aislamiento} + 2.7\,|T-22| + \varepsilon\), con un ruido normal de desviación 25 kWh. El término de la temperatura tiene forma de V, con el mínimo en 22 °C.
Las cinco primeras filas muestran la escala de cada variable: temperaturas entre 15.3 y 25.4 °C, de 2 a 6 ocupantes, de 2 a 10 electrodomésticos y consumos entre 270 y 485 kWh. Antes de ajustar nada, conviene fijar el orden de trabajo.
16.5 Flujo recomendado de trabajo
Define la pregunta y la variable objetivo. Fija qué quieres entender o predecir, la unidad de análisis (hogar, persona, empresa) y el horizonte temporal (día, mes, año). Si la pregunta es difusa, el modelo también lo será.
Revisa la calidad de los datos. Busca valores faltantes, atípicos, diferencias de escala (por ejemplo, 0–1 frente a 0–10 000) y problemas de codificación de categorías. Un modelo no corrige datos mal preparados; arrastra sus problemas a las conclusiones.
Explora las relaciones entre predictores y objetivo, y entre los predictores: relaciones fuertes o débiles, efectos no lineales, interacciones (el efecto de una variable depende del nivel de otra) y predictores redundantes. La sección de exploración desarrolla estos diagnósticos.
Separa entrenamiento y prueba. Ajustas con el entrenamiento y reservas la prueba, que el modelo no ve, para medir la generalización.
Ajusta un modelo base por OLS (ordinary least squares, mínimos cuadrados ordinarios). Es la referencia para saber si la complejidad adicional aporta.
Diagnostica los supuestos y la multicolinealidad. Revisa los residuos (valor real menos valor predicho): si muestran un patrón, el modelo deja estructura sin explicar, y si su dispersión cambia a lo largo de las predicciones, falla la homocedasticidad. Mide la multicolinealidad con el VIF. Si esta etapa falla, no leas los coeficientes como firmes aunque el error global parezca bueno.
Evalúa con varias métricas y con validación cruzada. MAE, RMSE y \(R^2\) dicen cómo le fue al modelo en una partición, y la validación cruzada dentro del entrenamiento dice si el resultado se sostiene en otras particiones. Un buen \(R^2\) puede convivir con errores absolutos demasiado altos para la decisión.
Itera con transformaciones, regularización o selección de variables, validando cada cambio dentro del entrenamiento.
Comunica qué encontraste, con qué confianza y bajo qué condiciones. La significancia estadística no equivale a relevancia práctica, y toda conclusión declara sus limitaciones:
«En [población], con \(n=\)[valor] ([entrenamiento / prueba]), se ajustó una regresión múltiple de [respuesta] sobre [predictores]. VIF máximo: [valor]. En prueba, MAE = [valor] y RMSE = [valor][unidades], \(R^2\) = [valor]; en validación cruzada, \(R^2\) medio = [valor]. Los coeficientes [principales, con IC 95%] se leen como asociaciones manteniendo fijos los demás predictores. Residuos: [patrones encontrados]. Limitación: [forma funcional, datos simulados u otra].»
En análisis multivariado, la claridad de la pregunta y la calidad de los datos suelen influir más en el resultado que elegir un algoritmo más sofisticado.
16.6 Exploración multivariada
Antes de ajustar, la exploración te ayuda a detectar colinealidad, segmentos y formas no lineales, y a responder cuatro preguntas prácticas: qué variables parecen informativas, cuáles duplican información, si hay patrones no lineales que un modelo lineal no capturaría y si existen grupos atípicos que puedan sesgar las conclusiones.
Qué miras en la exploración
Distribuciones marginales. El centro, la dispersión, la asimetría y los valores extremos de cada variable por separado; una cola muy larga puede pedir una transformación.
Relación de cada predictor con el objetivo. La forma general (creciente, decreciente, curva o casi nula), para priorizar variables y no suponer linealidad donde no la hay.
Relación entre predictores. Si dos variables se mueven casi juntas, aportan información redundante que infla la incertidumbre de sus coeficientes.
Matriz de correlaciones. Un mapa rápido de asociaciones lineales por pares, que no reemplaza la inspección visual ni implica causalidad: una correlación alta no prueba utilidad causal, una baja no descarta una relación no lineal, y una alta entre predictores alerta de colinealidad.
Patrones no lineales. Umbrales, saturaciones o efectos en U; si fuerzas linealidad donde la relación es curva, quedan residuos sistemáticos.
Segmentos. El mismo fenómeno puede comportarse distinto en subgrupos (zona, tipo de hogar), y un modelo global puede ocultarlo.
Atípicos con contexto. No todo atípico es un error: distingue el atípico técnico (un dato incorrecto) del atípico sustantivo (un caso extremo real) y justifica la decisión de tratarlo o conservarlo.
Una buena exploración deja tres resultados: hipótesis sobre qué variables deberían entrar al modelo base, una lista de riesgos (colinealidad, no linealidad, atípicos, segmentos) y un plan de modelado (transformaciones, interacciones y diagnósticos).
Un conjunto de datos para ver cada fenómeno
Para que estos patrones se vean con nitidez, la exploración usa un conjunto distinto del de energía: 450 hogares simulados con variables propias (ingreso, tamano_hogar, edad_vivienda, aislamiento, gasto_electrico_base, temperatura y segmento urbano o rural). La celda los genera con colinealidad (gasto_electrico_base es \(0.28\,\text{ingreso}\) más ruido), un efecto de temperatura en V (\(3.5\,|T-24|\)), un desplazamiento de nivel por segmento (+55 kWh urbano, −20 rural) y seis atípicos técnicos, consumos multiplicados por un factor entre 2.2 y 3.0.
La celda anterior es la etapa 1, y en las siete siguientes revisas df_demo en este orden:
Etapa 2: distribuciones marginales.
Etapa 3: correlación de cada predictor con el objetivo.
Etapa 4: correlación entre predictores, el foco principal.
Etapa 5: redundancia medida con el VIF.
Etapa 6: no linealidad.
Etapa 7: heterogeneidad por segmento.
Etapa 8: atípicos con el criterio del rango intercuartílico (IQR, \(Q_3 - Q_1\)), que marca todo valor por debajo de \(Q_1 - 1.5\,\text{IQR}\) o por encima de \(Q_3 + 1.5\,\text{IQR}\).
La etapa 1 no prueba hipótesis: construye 450 hogares y 8 columnas con estructura conocida para que cada patrón sea observable. La lección vale para cualquier conjunto de datos: antes de interpretar resultados, entiende cómo se generó o recolectó el dato. Cuando llegues a los supuestos de la regresión vuelves al conjunto de energía.
La asimetría de consumo_kwh es 2.88, frente a valores entre −0.13 y 0.26 en todos los predictores: la respuesta tiene una cola derecha marcada, visible en el histograma como unos pocos valores aislados por encima de 800 kWh. Los predictores tienen formas razonables, y la cola de la respuesta es una primera evidencia de observaciones extremas que vas a revisar en la etapa 8.
# Etapa 3: correlación de cada predictor con la variable objetivocorr_target = df_demo[preds + ["consumo_kwh"]].corr()["consumo_kwh"].drop("consumo_kwh")corr_target = corr_target.sort_values(key=np.abs, ascending=False)print("Correlación predictor -> consumo (ordenada por magnitud absoluta):")display(corr_target.to_frame("corr_con_consumo"))plt.figure(figsize=(7, 4))corr_target.sort_values().plot(kind="barh")plt.title("Correlación de predictores con consumo_kwh")plt.xlabel("Coeficiente de correlación")plt.tight_layout()plt.show()print("Interpretación: magnitud más alta = asociación lineal más fuerte (no implica causalidad).")
corr_con_consumo
gasto_electrico_base
0.437479
ingreso
0.434257
tamano_hogar
0.375648
aislamiento
-0.135343
temperatura
-0.117516
edad_vivienda
0.099901
Correlación predictor -> consumo (ordenada por magnitud absoluta):
Interpretación: magnitud más alta = asociación lineal más fuerte (no implica causalidad).
Los predictores con mayor correlación absoluta con consumo_kwh son gasto_electrico_base (0.437) e ingreso (0.434), candidatos fuertes para el modelo base aunque, como verás en la etapa 4, cuentan casi la misma historia. tamano_hogar (0.376) aporta señal algo menor, y aislamiento (−0.135), temperatura (−0.118) y edad_vivienda (0.100) quedan muy por debajo.
Una correlación baja no descarta una variable, porque puede actuar de forma no lineal o en interacción con otras. temperatura es el ejemplo: su efecto se construyó en forma de V (\(3.5\,|T-24|\)), y una correlación lineal no puede capturarlo. Una correlación alta prioriza, pero no prueba causalidad.
# Etapa 4: correlación entre predictores (foco principal)corr_preds = df_demo[preds].corr()print("Matriz de correlación entre predictores:")display(corr_preds)plt.figure(figsize=(8, 5))sns.heatmap(corr_preds, annot=True, cmap="coolwarm", fmt=".2f")plt.title("Correlación entre predictores")plt.show()# Ranking de pares con mayor correlación absolutapairs = ( corr_preds.where(np.triu(np.ones(corr_preds.shape), k=1).astype(bool)) .stack() .reset_index() .rename(columns={"level_0": "var_1", "level_1": "var_2", 0: "corr"}))pairs["abs_corr"] = pairs["corr"].abs()pairs = pairs.sort_values("abs_corr", ascending=False)print("Top 8 pares más correlacionados (en valor absoluto):")display(pairs.head(8))print("Lectura clave: una correlación alta entre predictores sugiere posible redundancia de información.")
ingreso
tamano_hogar
edad_vivienda
aislamiento
gasto_electrico_base
temperatura
ingreso
1.000000
0.058265
0.015557
0.022029
0.869356
-0.015021
tamano_hogar
0.058265
1.000000
0.010388
0.023812
0.026014
-0.034876
edad_vivienda
0.015557
0.010388
1.000000
0.005575
0.003494
-0.008368
aislamiento
0.022029
0.023812
0.005575
1.000000
-0.008215
0.022293
gasto_electrico_base
0.869356
0.026014
0.003494
-0.008215
1.000000
-0.017753
temperatura
-0.015021
-0.034876
-0.008368
0.022293
-0.017753
1.000000
var_1
var_2
corr
abs_corr
4
ingreso
gasto_electrico_base
0.869356
0.869356
1
ingreso
tamano_hogar
0.058265
0.058265
11
tamano_hogar
temperatura
-0.034876
0.034876
10
tamano_hogar
gasto_electrico_base
0.026014
0.026014
9
tamano_hogar
aislamiento
0.023812
0.023812
23
aislamiento
temperatura
0.022293
0.022293
3
ingreso
aislamiento
0.022029
0.022029
29
gasto_electrico_base
temperatura
-0.017753
0.017753
Matriz de correlación entre predictores:
Top 8 pares más correlacionados (en valor absoluto):
Lectura clave: una correlación alta entre predictores sugiere posible redundancia de información.
La matriz y el ranking de pares muestran una correlación de 0.869 entre ingreso y gasto_electrico_base, mientras que el siguiente par más correlacionado no llega a 0.06. Las dos variables capturan en buena parte el mismo fenómeno, y si entran juntas al modelo sus coeficientes pueden volverse menos estables y más difíciles de interpretar.
Una correlación alta entre dos predictores obliga a revisar la colinealidad, pero una correlación baja por pares no la descarta, porque un predictor puede ser casi combinación lineal de varios otros. Por eso el paso siguiente es el VIF.
# Etapa 5: cuantificar redundancia entre predictores con VIFX_vif_demo = sm.add_constant(df_demo[preds])vif_demo = pd.DataFrame({"variable": X_vif_demo.columns,"VIF": [variance_inflation_factor(X_vif_demo.values, i) for i inrange(X_vif_demo.shape[1])]})display(vif_demo.sort_values("VIF", ascending=False))print("Guía rápida: VIF < 5 usualmente aceptable; 5-10 zona de alerta; >= 10 problema serio.")
variable
VIF
0
const
46.990296
1
ingreso
4.132227
5
gasto_electrico_base
4.119082
2
tamano_hogar
1.007616
4
aislamiento
1.004502
6
temperatura
1.002103
3
edad_vivienda
1.000809
Guía rápida: VIF < 5 usualmente aceptable; 5-10 zona de alerta; >= 10 problema serio.
ingreso (4.13) y gasto_electrico_base (4.12) tienen un VIF unas cuatro veces mayor que el resto de predictores, todos entre 1.00 y 1.01: la varianza de sus coeficientes se multiplica por cuatro y su error estándar, por \(\sqrt{4.1} \approx 2\). Con un solo par correlacionado, el VIF se deduce de la correlación, \(1/(1-0.869^2) \approx 4.1\). Aunque 0.87 es una correlación muy alta, el VIF queda por debajo del umbral orientativo de 5; los umbrales son convenciones, y la interpretación simultánea de ambos coeficientes igual pide cuidado. El VIF de la constante (46.99) no se interpreta, porque la columna de unos no es un predictor.
La comparación de curvatura que sigue se calcula sobre la misma muestra del ajuste y sirve para explorar la especificación. Retiras solo los seis errores que conoces por haberlos inyectado en la simulación; con datos reales, esa decisión exigiría evidencia externa.
# Etapa 6: validar no linealidad (lineal vs polinomial en temperatura)X_lin = df_demo[["temperatura"]]y_lin = df_demo["consumo_kwh"]m_lin = LinearRegression().fit(X_lin, y_lin)r2_lin = m_lin.score(X_lin, y_lin)poly = PolynomialFeatures(degree=2, include_bias=False)X_poly = poly.fit_transform(X_lin)m_poly = LinearRegression().fit(X_poly, y_lin)r2_poly = m_poly.score(X_poly, y_lin)print(f"R2 lineal (temperatura -> consumo): {r2_lin:.3f}")print(f"R2 polinomial grado 2: {r2_poly:.3f}")print("La mejora de ajuste es descriptiva e in-sample; debe contrastarse fuera de muestra.")# Misma comparación, controlando por los demás predictores y sin los 6 atípicos inyectados en la Etapa 1datos_ctrl = df_demo.drop(index=idx_out).copy()datos_ctrl["urbano"] = (datos_ctrl["segmento"] =="urbano").astype(int)datos_ctrl["temperatura2"] = datos_ctrl["temperatura"] **2base_ctrl = ["ingreso", "tamano_hogar", "edad_vivienda", "aislamiento", "gasto_electrico_base", "urbano", "temperatura"]m_base = sm.OLS(datos_ctrl["consumo_kwh"], sm.add_constant(datos_ctrl[base_ctrl])).fit()m_curva = sm.OLS(datos_ctrl["consumo_kwh"], sm.add_constant(datos_ctrl[base_ctrl + ["temperatura2"]])).fit()print(f"R2 controlado, lineal en temperatura: {m_base.rsquared:.3f}")print(f"R2 controlado, con temperatura^2: {m_curva.rsquared:.3f}")print(f"p-valor del término cuadrático: {m_curva.pvalues['temperatura2']:.3f}")
R2 lineal (temperatura -> consumo): 0.014
R2 polinomial grado 2: 0.014
La mejora de ajuste es descriptiva e in-sample; debe contrastarse fuera de muestra.
R2 controlado, lineal en temperatura: 0.771
R2 controlado, con temperatura^2: 0.775
p-valor del término cuadrático: 0.008
Con la temperatura sola, el \(R^2\) lineal es 0.014 y el polinomial de grado 2 también, sin mejora apreciable. Sin embargo, la curvatura existe por construcción, porque el consumo se generó con \(3.5\,|T - 24|\). La comparación marginal no la detecta porque el efecto de la temperatura es pequeño frente al resto de la variación (los demás predictores, el segmento y los 6 atípicos), que un modelo con una sola variable deja en el error.
Al controlar por los demás predictores y excluir los atípicos inyectados, el término cuadrático sí aparece: el \(R^2\) pasa de 0.771 a 0.775 y su p-value es 0.008. No supongas no linealidad por intuición, pero tampoco la descartes con una comparación marginal; la evidencia la buscas con el resto de variables en el modelo.
# Etapa 7: validar heterogeneidad por segmentoresumen_segmento = df_demo.groupby("segmento")["consumo_kwh"].agg(["mean", "median", "std", "count"])print("Resumen por segmento:")display(resumen_segmento)plt.figure(figsize=(7, 4))sns.boxplot(data=df_demo, x="segmento", y="consumo_kwh")plt.title("Consumo por segmento")plt.show()print("Si las medias/medianas difieren de forma consistente, hay heterogeneidad estructural.")
mean
median
std
count
segmento
rural
390.330223
382.678209
124.188189
153
urbano
462.614223
455.502952
117.755586
297
Resumen por segmento:
Si las medias/medianas difieren de forma consistente, hay heterogeneidad estructural.
El consumo medio urbano (462.6 kWh) supera al rural (390.3 kWh) en 72.3 kWh, y las medianas cuentan lo mismo (455.5 frente a 382.7). Con desviaciones estándar cercanas a 120 kWh en los dos grupos, la diferencia es clara, pero el diagrama de caja muestra que las distribuciones se superponen mucho.
Lo que muestra la tabla es una diferencia de nivel, y por eso el segmento debe entrar al modelo como variable indicadora. No prueba que los predictores actúen distinto en cada grupo: para afirmar pendientes distintas tendrías que probar interacciones. En estos datos el segmento solo desplaza el nivel, porque se generó con +55 kWh para urbano y −20 kWh para rural.
# Etapa 8: detectar outliers con IQR y revisar casosq1 = df_demo["consumo_kwh"].quantile(0.25)q3 = df_demo["consumo_kwh"].quantile(0.75)iqr = q3 - q1lim_inf = q1 -1.5* iqrlim_sup = q3 +1.5* iqrmask_out = (df_demo["consumo_kwh"] < lim_inf) | (df_demo["consumo_kwh"] > lim_sup)n_out =int(mask_out.sum())pct_out =100* n_out /len(df_demo)print(f"Límites IQR: [{lim_inf:.1f}, {lim_sup:.1f}] kWh")print("Índices de los atípicos inyectados en la Etapa 1:", sorted(idx_out.tolist()))print(f"Atípicos detectados por IQR: {n_out} ({pct_out:.2f}%)")print("Primeros casos para inspección contextual:")display(df_demo.loc[mask_out, ["segmento", "ingreso", "temperatura", "consumo_kwh"]].head(10))plt.figure(figsize=(8, 4))sns.scatterplot( data=df_demo, x=df_demo.index, y="consumo_kwh", hue=mask_out, style=mask_out, markers={False: "o", True: "X"}, palette={False: "steelblue", True: "crimson"}, alpha=0.7)plt.title("Outliers IQR resaltados")plt.xlabel("Índice de observación")plt.legend(title="Outlier")plt.show()
segmento
ingreso
temperatura
consumo_kwh
18
urbano
2538.787656
21.959488
909.347068
36
urbano
2634.936971
18.557640
847.581914
37
urbano
878.806315
17.065044
948.831839
43
rural
3251.097441
24.611346
1445.817729
96
urbano
1553.545359
16.699184
863.513000
134
urbano
4299.768079
30.301488
726.822478
180
rural
1570.405241
22.073216
135.410652
263
rural
1816.872298
18.462113
158.588262
323
rural
1752.390752
25.020978
140.435608
444
urbano
2564.273788
15.801986
1499.488896
Límites IQR: [173.1, 682.0] kWh
Índices de los atípicos inyectados en la Etapa 1: [18, 36, 37, 43, 96, 444]
Atípicos detectados por IQR: 10 (2.22%)
Primeros casos para inspección contextual:
El criterio IQR marca 10 observaciones (2.22%) fuera del intervalo [173.1, 682.0] kWh. Seis son justo los atípicos técnicos inyectados en la etapa 1 (índices 18, 36, 37, 43, 96 y 444, con consumos entre 848 y 1 499 kWh). Las otras cuatro son casos reales: un consumo alto (índice 134, 727 kWh) y tres consumos bajos de hogares rurales (índices 180, 263 y 323, entre 135 y 159 kWh).
La regla IQR detecta valores extremos, no errores. Aquí encontró todos los errores inyectados y también cuatro hogares legítimos, así que eliminar las 10 filas a ciegas borraría información válida. Documenta el criterio de tratamiento y compara las métricas con y sin esos casos para medir su impacto.
Cierre de la exploración
La exploración dejó cuatro hallazgos para el modelado: un par de predictores redundantes (ingreso y gasto_electrico_base, VIF ≈ 4.1), una curvatura en la temperatura que solo aparece al controlar por el resto, una diferencia de nivel entre segmentos y unos pocos atípicos, de los que no todos son errores. Si tienes poco tiempo, las etapas 3, 4 y 5 (correlación con la respuesta, correlación entre predictores y VIF) son las que más informan sobre la redundancia.
16.7 Supuestos de la regresión múltiple
La regresión múltiple no se evalúa solo por el \(R^2\). Para interpretar coeficientes, p-values e intervalos de confianza tienes que revisar seis supuestos:
Supuesto
Qué pide
Si falla
Linealidad
La relación esperada entre cada predictor y la respuesta, controlando los demás, es aproximadamente lineal
Patrones sistemáticos en los residuos y coeficientes sesgados
Independencia de los errores
Los residuos no se influyen entre observaciones
Errores estándar mal estimados y pruebas \(t\) y \(F\) menos confiables
Homocedasticidad
La varianza de los residuos es parecida en todo el rango de predicción
Afecta poco a la predicción media y compromete la inferencia (p-values e intervalos)
Normalidad aproximada de los residuos
Importa para la inferencia clásica, sobre todo con muestras pequeñas
Intervalos y contrastes inestables
Baja multicolinealidad
Los predictores no son casi copias entre sí
Coeficientes inestables, signos que cambian entre muestras y más incertidumbre en cada \(\beta\)
Especificación
El modelo incluye las variables relevantes con una forma funcional razonable
Sesgo por variable omitida o por mala forma
En rigor, OLS solo exige que no haya colinealidad perfecta (ningún predictor es combinación lineal exacta de otros); la colinealidad alta no sesga los coeficientes, pero infla su varianza. Un modelo puede tener un buen \(R^2\) y aun así problemas de interpretación si no cumple estos supuestos.
Desde aquí vuelves al conjunto de energía residencial (df, con temperatura, ocupantes, area_m2, aislamiento y electrodomesticos); el de la exploración ya cumplió su función. Separas 400 hogares de entrenamiento y 100 de prueba, y ajustas el modelo completo con inferencia formal en statsmodels.
# Separación train/test y ajuste con statsmodels para inferenciaX = df.drop(columns=["consumo_kwh"])y = df["consumo_kwh"]X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=SEMILLA)X_train_sm = sm.add_constant(X_train)modelo_ols = sm.OLS(y_train, X_train_sm).fit()print(modelo_ols.summary())
Con 400 hogares de entrenamiento y cinco predictores, el modelo tiene \(R^2 = 0.823\) y \(R^2\) ajustado de 0.821, casi iguales, así que no hay señal de sobreparametrización; el estadístico \(F = 367.6\), con p-value de \(6.4\times10^{-146}\), dice que en conjunto los predictores explican el consumo. Los 394 grados de libertad residuales son \(400 - 5 - 1\).
Los coeficientes se leen manteniendo fijos los demás predictores. Cada ocupante adicional se asocia con 18.96 kWh más; cada m², con 1.84 kWh; cada electrodoméstico, con 8.98 kWh; y pasar del índice de aislamiento 0 al 1 (en los datos va de 0.2 a 1.0), con 58.7 kWh menos. Como los datos son simulados, puedes compararlos con los valores verdaderos: 18, 1.8, 9 y −55, y los cuatro intervalos de confianza al 95% los contienen. La temperatura tiene coeficiente \(-1.84\) kWh por °C, la pendiente de una recta ajustada a una relación que no es lineal: los datos se generaron con \(2.7\,|T - 22|\) y temperaturas de media 20 °C, así que la mayoría cae en el tramo descendente de la V. Un coeficiente puede ser muy significativo y describir mal la forma del efecto. El intercepto (162 frente a 120) se aleja más porque absorbe la parte del efecto de la temperatura que la recta no captura.
Todos los p-values son menores que 0.001 y ningún intervalo cruza el 0. Las pruebas Ómnibus (\(p = 0.513\)) y de Jarque–Bera (\(p = 0.535\)), que contrastan la normalidad de los residuos a partir de su asimetría (\(-0.137\)) y curtosis (3.015), no dan evidencia para rechazarla. El estadístico de Durbin–Watson (1.889) mide la correlación entre residuos consecutivos, y solo informa cuando las filas tienen un orden natural, como el tiempo; aquí los hogares están en orden arbitrario. AIC (3 762) y BIC (3 786) sirven para comparar con modelos alternativos.
El número de condición, 686, refleja sobre todo las escalas distintas de los predictores (el área ronda 85 m² y el aislamiento va de 0.2 a 1.0), no colinealidad, como confirma el VIF de la sección siguiente. Covariance Type: nonrobust indica que los errores estándar suponen errores homocedásticos y no correlacionados; si sospechas heterocedasticidad, contrasta con errores robustos (fit(cov_type="HC3")). El ajuste global es alto y los signos son los esperados, pero la lectura no termina en el \(R^2\): falta el diagnóstico de colinealidad, de la evaluación fuera de muestra y de los residuos.
16.8 Multicolinealidad y VIF
La multicolinealidad es el solapamiento de información entre predictores: varias variables explicativas aportan casi la misma señal dentro del modelo. El VIF (variance inflation factor, factor de inflación de la varianza) la cuantifica midiendo cuánto se infla la varianza de cada coeficiente por depender linealmente de los demás predictores.
La correlación describe la asociación lineal entre dos variables a la vez, mientras que el VIF evalúa, para cada predictor, cuánta redundancia tiene respecto del conjunto de todos los demás. Por eso puede haber correlaciones por pares moderadas y un VIF elevado, si la combinación de varias variables explica casi la misma información. La fórmula es
\[VIF_j = \frac{1}{1-R_j^2},\]
donde \(R_j^2\) es el \(R^2\) de la regresión auxiliar del predictor \(j\) sobre los demás: un VIF de 5 equivale a \(R_j^2 = 0.8\), y uno de 10, a \(R_j^2 = 0.9\). Una regla orientativa, no absoluta, considera aceptable un VIF menor que 5, zona de alerta entre 5 y 10 y riesgo alto de inestabilidad a partir de 10.
La multicolinealidad aparece con variables que miden casi el mismo fenómeno (como ingreso y gasto_electrico_base en la etapa 4), con variables derivadas entre sí y con procesos en los que varias variables crecen juntas por diseño. Produce coeficientes que cambian mucho entre muestras parecidas, errores estándar inflados, p-values poco informativos para decidir qué variable importa y signos contraintuitivos. No significa que el modelo prediga mal, ni que haya un error en los datos, ni invalida el ajuste global.
Si la encuentras, quita o combina variables redundantes, usa regularización (el capítulo siguiente) o prioriza la interpretabilidad según el objetivo. En un análisis explicativo, la multicolinealidad es sobre todo un problema de interpretación de coeficientes.
La celda calcula el VIF de cada predictor del conjunto de energía sobre X_train, con la constante añadida para las regresiones auxiliares.
# Cálculo e interpretación práctica de VIFX_vif = sm.add_constant(X_train).copy()vif_df = pd.DataFrame({"variable": X_vif.columns,"VIF": [variance_inflation_factor(X_vif.values, i) for i inrange(X_vif.shape[1])]})# El intercepto no se interpreta para colinealidad, se excluye en el semaforo.vif_eval = vif_df[vif_df["variable"] !="const"].copy()def clasificar_vif(v):if v <5:return"OK (<5)"if v <10:return"Alerta (5-10)"return"Alto (>=10)"vif_eval["lectura"] = vif_eval["VIF"].apply(clasificar_vif)vif_eval = vif_eval.sort_values("VIF", ascending=False).reset_index(drop=True)display(vif_eval)n_alerta = (vif_eval["VIF"] >=5).sum()n_alto = (vif_eval["VIF"] >=10).sum()vif_max =float(vif_eval["VIF"].max())var_max =str(vif_eval.loc[vif_eval["VIF"].idxmax(), "variable"])print(f"VIF máximo: {vif_max:.3f} ({var_max})")print(f"Variables en alerta (VIF >= 5): {n_alerta}")print(f"Variables en riesgo alto (VIF >= 10): {n_alto}")
variable
VIF
lectura
0
ocupantes
1.014488
OK (<5)
1
temperatura
1.010758
OK (<5)
2
aislamiento
1.007479
OK (<5)
3
electrodomesticos
1.005178
OK (<5)
4
area_m2
1.003686
OK (<5)
VIF máximo: 1.014 (ocupantes)
Variables en alerta (VIF >= 5): 0
Variables en riesgo alto (VIF >= 10): 0
El VIF máximo es 1.014 (ocupantes), y ningún predictor llega a la zona de alerta ni a la de riesgo alto. Contrasta con la etapa 5, donde ingreso y gasto_electrico_base llegaban a 4.13: en el conjunto de energía los predictores se simularon de forma independiente. No hay evidencia de multicolinealidad, así que la interpretación de los coeficientes es estable desde ese punto de vista; si agregas variables o interacciones, vuelve a calcular el VIF.
16.9 Evaluación predictiva
La evaluación predictiva responde dos preguntas: qué tan grande es el error en unidades reales y qué tan estable es el desempeño cuando cambia la muestra. Con el residuo de predicción \(e_i = y_i - \hat{y}_i\), las métricas principales son
El MAE es el error promedio en unidades originales, fácil de comunicar; el MSE amplifica los errores grandes y es la pérdida que minimiza OLS; el RMSE conserva esa sensibilidad y vuelve a la escala de la respuesta; y el \(R^2\) es la proporción de variabilidad explicada, útil para comparar ajustes. La validación cruzada complementa la evaluación en una sola prueba, porque mide el desempeño en varios pliegues del entrenamiento.
Antes de abrir la prueba fijas OLS como modelo del reporte, porque este ejemplo tiene cinco predictores y VIF cercanos a 1; la comparación posterior con Ridge y Lasso es descriptiva y no cambia ese modelo.
Guía de lectura de las métricas
Métrica
Qué penaliza
Cuándo priorizarla
Qué revisar
MAE
Todos los errores de forma lineal
Cuando quieres una medida robusta y fácil de comunicar en unidades reales
Compararlo con una tolerancia de la operación y con un modelo que predice la media
MSE
Los errores grandes, de forma cuadrática
Cuando lo usas como función de costo para optimizar
Las observaciones con error grande y el efecto de limpiar o transformar
RMSE
Los errores grandes, en la escala original
Cuando los errores extremos son costosos y necesitas leerlos en unidades reales
Si el RMSE es mucho mayor que el MAE, hay una cola de errores grandes: revisa no linealidad, segmentos o variables omitidas
\(R^2\)
No mide error absoluto, sino varianza explicada
Cuando comparas ajustes sobre el mismo problema
Compararlo entre entrenamiento, prueba y validación cruzada; en datos nuevos puede ser negativo, peor que predecir la media
Lee siempre el MAE y el RMSE en la unidad real de la respuesta, y confirma la estabilidad con validación cruzada, no solo con una partición de prueba.
# Modelo base con sklearn + lectura de estabilidadlr = LinearRegression()lr.fit(X_train, y_train)pred_test = lr.predict(X_test)mae = mean_absolute_error(y_test, pred_test)rmse = np.sqrt(mean_squared_error(y_test, pred_test))r2 = r2_score(y_test, pred_test)# CV solo sobre el entrenamiento: el conjunto de prueba queda reservado para el reporte finalcv_r2 = cross_val_score(lr, X_train, y_train, cv=5, scoring="r2")cv_r2_mean =float(cv_r2.mean())cv_r2_std =float(cv_r2.std())print(f"MAE : {mae:.2f}")print(f"RMSE: {rmse:.2f}")print(f"R2 test: {r2:.3f}")print(f"R2 CV (media): {cv_r2_mean:.3f}")print(f"R2 CV (desv): {cv_r2_std:.3f}")# Brecha test vs CV como chequeo rapido de estabilidadgap_test_cv = r2 - cv_r2_meanprint(f"Brecha R2 test - R2 CV media: {gap_test_cv:+.3f}")
En los 100 hogares de prueba, MAE = 22.40 kWh, RMSE = 27.66 kWh y \(R^2\) = 0.820. El cociente RMSE/MAE es 1.23; describe la diferencia entre dos resúmenes del error, pero por sí solo no descarta colas pesadas ni demuestra normalidad.
La validación cruzada sobre el entrenamiento da un \(R^2\) medio de 0.817, con una desviación entre folds de 0.032, y la diferencia entre prueba y validación cruzada es de +0.003. Los resultados son cercanos en esta partición; para estudiar su sensibilidad conviene repetir el diseño de validación. La desviación entre folds describe esos bloques y no es un error estándar del promedio (capítulo de validación cruzada).
16.10 Cuándo usar regularización
Regularizar es entrenar el modelo minimizando el error de ajuste más una penalización sobre el tamaño de los coeficientes. OLS solo minimiza el error de predicción, y si hay ruido o variables muy parecidas puede asignar coeficientes grandes e inestables para seguir detalles de la muestra; la penalización obliga a preferir soluciones más sobrias.
Ridge (penalización \(L_2\)) encoge todos los coeficientes sin llevarlos exactamente a cero, reparte el peso entre variables correlacionadas y estabiliza los coeficientes entre muestras.
Lasso (penalización \(L_1\)) encoge y además puede dejar coeficientes exactamente en cero, lo que equivale a seleccionar variables; con variables muy correlacionadas puede ser menos estable, porque elige algunas y descarta otras.
El hiperparámetro \(\alpha\) fija la fuerza de la penalización: con \(\alpha\) pequeño el resultado se parece a OLS, y con \(\alpha\) grande el recorte es mayor. Se elige por validación cruzada.
Las dos penalizaciones exigen estandarizar los predictores, porque suman magnitudes de coeficientes que dependen de las unidades; por eso el código usa StandardScaler dentro de un Pipeline. Aquí solo las comparas con valores fijos de \(\alpha\); el capítulo siguiente desarrolla Ridge y Lasso con sus fórmulas y la elección de \(\alpha\).
# Comparación: OLS vs Ridge vs Lasso con validación cruzadamodelos = {"OLS": LinearRegression(),"Ridge(alpha=1.0)": Pipeline([("scaler", StandardScaler()), ("m", Ridge(alpha=1.0))]),"Lasso(alpha=0.05)": Pipeline([("scaler", StandardScaler()), ("m", Lasso(alpha=0.05, max_iter=10000))]),}res_reg = []for nombre, modelo in modelos.items(): scores = cross_val_score(modelo, X_train, y_train, cv=5, scoring="r2") # CV solo sobre entrenamiento res_reg.append({"modelo": nombre,"r2_cv_mean": float(scores.mean()),"r2_cv_std": float(scores.std()) })res_reg_df = pd.DataFrame(res_reg).sort_values("r2_cv_mean", ascending=False).reset_index(drop=True)display(res_reg_df)mejor_modelo =str(res_reg_df.loc[0, "modelo"])mejor_r2 =float(res_reg_df.loc[0, "r2_cv_mean"])print(f"Mejor modelo por R2 CV medio: {mejor_modelo} ({mejor_r2:.3f})")
modelo
r2_cv_mean
r2_cv_std
0
Ridge(alpha=1.0)
0.817280
0.032450
1
Lasso(alpha=0.05)
0.817274
0.032368
2
OLS
0.817271
0.032268
Mejor modelo por R2 CV medio: Ridge(alpha=1.0) (0.817)
Ridge con alpha=1.0, Lasso con alpha=0.05 y OLS obtienen \(R^2\) de validación cruzada cercanos a 0.81727, con una diferencia entre el mayor y el menor de unas 0.000009. Con esos valores fijos de penalización no aparece una ventaja predictiva en este experimento; no exploraste todas las penalizaciones ni demostraste equivalencia estadística.
El VIF máximo de 1.014 indica poco solapamiento lineal entre estos cinco predictores, y OLS es una referencia razonable para este conjunto simulado. En el capítulo de regularización elegirás alpha dentro del entrenamiento antes de evaluar en prueba.
16.11 Diagnóstico de residuos
El residuo \(e_i = y_i - \hat{y}_i\) es la parte que el modelo no explica, y mirarlo detecta problemas que una métrica no muestra. Revisa cinco cosas:
Que los residuos estén alrededor de 0. Un promedio cercano a 0 indica que no hay un sesgo sistemático fuerte.
Que no haya patrón frente a la predicción. Debe verse una nube desordenada; una curva, una pendiente o una forma clara indican estructura sin explicar. Mira también el residuo frente a cada predictor, porque una curvatura en un solo predictor puede diluirse frente a la predicción.
Que la dispersión sea parecida en todo el rango. Si los residuos se abren como un embudo al aumentar la predicción, la varianza no es constante.
Que no haya demasiados casos extremos. Muchos residuos muy grandes pueden distorsionar resultados y conclusiones.
Que la forma general sea razonable. Con un histograma y un gráfico Q–Q (cuantiles de los residuos frente a los de una normal) revisas si se parecen de forma aproximada a una normal.
Dos de los chequeos numéricos más comunes, la media de los residuos y la correlación entre predicción y residuo, dan exactamente 0 por construcción cuando los calculas sobre los mismos datos con que ajustaste un OLS con intercepto: las ecuaciones normales obligan a que los residuos sean ortogonales a las columnas de \(X\), incluida la de unos. Esos dos chequeos solo informan si los calculas sobre la prueba.
Si aparece una alerta, prueba transformaciones (por ejemplo, logaritmo), agrega términos no lineales o interacciones, revisa atípicos y calidad de datos, o considera segmentar el análisis o usar errores robustos.
# Diagnóstico de residuos: gráfico + resumen numéricofrom statsmodels.stats.stattools import durbin_watsonpred_train = modelo_ols.predict(X_train_sm)resid = y_train - pred_train# Prediccion y residuos sobre el conjunto de PRUEBA: el modelo no los vio al ajustarse,# por eso son los unicos que permiten un chequeo no tautologico de media y correlacion (ver nota arriba).X_test_sm = sm.add_constant(X_test)pred_test = modelo_ols.predict(X_test_sm)resid_test = y_test - pred_testfig, axes = plt.subplots(1, 3, figsize=(15, 4))# 1) Residuo vs predicciónaxes[0].scatter(pred_train, resid, alpha=0.6)axes[0].axhline(0, color="red", linestyle="--")axes[0].set_xlabel("Predicción")axes[0].set_ylabel("Residuo")axes[0].set_title("Residuo vs predicción")# 2) Histograma de residuossns.histplot(resid, kde=True, ax=axes[1])axes[1].set_title("Distribución de residuos")axes[1].set_xlabel("Residuo")# 3) Q-Q plotsm.qqplot(resid, line="45", ax=axes[2], fit=True)axes[2].set_title("Q-Q plot de residuos")plt.tight_layout()plt.show()# Resumen numerico rapido (sobre train, para escala/forma) mas el chequeo no tautologico (sobre test)resid_mean =float(resid.mean())resid_std =float(resid.std())corr_pred_resid =float(np.corrcoef(pred_train, resid)[0, 1])pct_extremos =float((np.abs(resid) >2* resid_std).mean() *100)dw =float(durbin_watson(resid))resid_test_mean =float(resid_test.mean())corr_pred_resid_test =float(np.corrcoef(pred_test, resid_test)[0, 1])print(f"Media de residuos (entrenamiento, ~0 por construcción, no es diagnóstico): {resid_mean:.3f}")print(f"Media de residuos (prueba, chequeo real): {resid_test_mean:.3f}")print(f"Desv. estándar de residuos (entrenamiento): {resid_std:.3f}")print(f"Correlación predicción-residuo (entrenamiento, ~0 por construcción, no es diagnóstico): {corr_pred_resid:.3f}")print(f"Correlación predicción-residuo (prueba, chequeo real): {corr_pred_resid_test:.3f}")print(f"% residuos extremos (|resid| > 2*std): {pct_extremos:.2f}%")print(f"Durbin-Watson: {dw:.3f}")# Lectura automatica orientativa (usa el chequeo de test, el unico no tautologico)ifabs(corr_pred_resid_test) >0.2:print("Alerta: hay dependencia notable entre predicción y residuo en prueba; revisar especificación.")else:print("OK: no hay dependencia lineal fuerte entre predicción y residuo en prueba.")if pct_extremos >8:print("Alerta: porcentaje alto de residuos extremos; revisar atípicos y no linealidad.")else:print("OK: porcentaje de residuos extremos en rango razonable.")
Media de residuos (entrenamiento, ~0 por construcción, no es diagnóstico): 0.000
Media de residuos (prueba, chequeo real): 2.371
Desv. estándar de residuos (entrenamiento): 26.319
Correlación predicción-residuo (entrenamiento, ~0 por construcción, no es diagnóstico): -0.000
Correlación predicción-residuo (prueba, chequeo real): 0.088
% residuos extremos (|resid| > 2*std): 5.25%
Durbin-Watson: 1.889
OK: no hay dependencia lineal fuerte entre predicción y residuo en prueba.
OK: porcentaje de residuos extremos en rango razonable.
Los residuos de entrenamiento tienen media 0.000 y una correlación con la predicción de −0.000 por las ecuaciones de OLS con intercepto; esas dos identidades no verifican los supuestos. En prueba, la media residual es 2.371 kWh y la correlación predicción-residuo, 0.088, resúmenes descriptivos de 100 hogares que no descartan otros patrones. La desviación residual de entrenamiento es 26.319 kWh, cerca del ruido simulado de 25 kWh, y el 5.25% de los residuos supera dos desviaciones en valor absoluto.
El estadístico de Durbin–Watson vale 1.889, pero como las filas son hogares en orden arbitrario carece de una lectura temporal, y un valor cercano a 2 tampoco demuestra independencia entre hogares. Los gráficos resumen la forma residual en el entrenamiento, y queda pendiente la relación en V de temperatura, que el modelo aproxima con una recta. Si decides cambiar esa forma después de mirar la prueba, necesitarás otra evaluación independiente para el modelo revisado.
16.12 Decisiones a partir del diagnóstico
Para estos hogares, empieza por MAE = 22.40 kWh y RMSE = 27.66 kWh: su utilidad depende de cuánto error tolere la decisión energética, y el \(R^2\) de 0.820 no sustituye ese criterio. El VIF máximo de 1.014 te permite interpretar los coeficientes sin una alerta de colinealidad, aunque el coeficiente de temperatura resume una V con una recta, y esa forma funcional merece más atención que cualquier clasificación automática del modelo; los splines son una forma de corregirla.
Usa los residuos de entrenamiento para proponer cambios y valídalos dentro del entrenamiento. Cuando hayas fijado variables y transformaciones, informa el resultado de prueba; si la prueba motiva una nueva especificación, deja de tratarla como evaluación final de esa nueva versión. Con datos temporales o agrupados, cambia el diseño de partición, porque separar filas al azar no reproduce el pronóstico de períodos nuevos ni la generalización a grupos nuevos.
16.13 Preguntas de comprensión
¿Por qué una correlación cercana a cero entre los residuos de entrenamiento y la predicción no verifica la especificación del modelo?
Con un VIF máximo de 1.014, ¿la temperatura necesita regularización o una forma distinta?
En la exploración, ingreso y gasto_electrico_base tienen correlación 0.869 y VIF de 4.1. ¿Qué pasaría con los errores estándar de sus coeficientes si las dos entraran al modelo, y qué podrías hacer?
El coeficiente de aislamiento es \(-58.7\) kWh. Un colega concluye que mejorar el aislamiento de un hogar de 0.2 a 1.0 le ahorrará 47 kWh al mes. ¿Qué parte de esa lectura sostienen los datos y qué parte no?
El criterio IQR marcó 10 atípicos en la exploración. ¿Por qué no conviene eliminarlos todos antes de ajustar?
TipOrientaciones
Porque OLS con intercepto impone la ortogonalidad entre residuos y columnas de \(X\) en los datos de ajuste, de modo que esa correlación vale 0 por construcción. En este caso persiste la relación en V con la temperatura, que tendrías que explorar y validar sin reutilizar la prueba.
Una forma distinta. El VIF mide colinealidad, y aquí no la hay; la V simulada pide revisar la forma funcional (por ejemplo, \(|T-22|\) o un spline), y Ridge no convierte por sí solo una recta en una V.
Con VIF de 4.1, la varianza de cada coeficiente se multiplica por unas cuatro veces y su error estándar por unas dos, respecto de predictores independientes. Podrías quitar una de las dos, combinarlas en un índice o usar Ridge, según si te interesa interpretar cada una o solo predecir.
Los datos sostienen una asociación: con los demás predictores fijos, pasar de 0.2 a 1.0 de aislamiento se asocia con \(0.8\times58.7\approx47\) kWh menos de consumo medio. No sostienen que intervenir un hogar produzca ese ahorro, porque es un modelo observacional (aquí, además, simulado) y la intervención podría cambiar otras variables.
Porque la regla detecta valores extremos, no errores: de los 10, seis eran atípicos técnicos inyectados y cuatro eran hogares legítimos. Eliminarlos a ciegas borra información válida; documenta el criterio y compara el ajuste con y sin ellos.
16.14 Referencias para profundizar
James, G., Witten, D., Hastie, T. y Tibshirani, R. (2021). An Introduction to Statistical Learning (2.ª ed.). Springer. El capítulo 3 trata la regresión múltiple, la colinealidad y el diagnóstico de residuos.
Fox, J. (2016). Applied Regression Analysis and Generalized Linear Models (3.ª ed.). Sage. Supuestos, diagnóstico y colinealidad con detalle.
Belsley, D. A., Kuh, E. y Welsch, R. E. (1980). Regression Diagnostics: Identifying Influential Data and Sources of Collinearity. Wiley. El origen del número de condición como diagnóstico.
O’Brien, R. M. (2007). A caution regarding rules of thumb for variance inflation factors. Quality & Quantity, 41(5), 673–690. Por qué los umbrales de 5 y 10 son convenciones.
Un coeficiente de regresión múltiple se lee con los demás predictores fijos, y su interpretación depende de la colinealidad, de la forma funcional y de una evaluación hecha fuera de los datos de ajuste.
La exploración encontró un par redundante (correlación 0.869, VIF de 4.1), una curvatura que solo apareció al controlar por el resto (\(R^2\) de 0.771 a 0.775, \(p=0.008\)), una diferencia de nivel de 72.3 kWh entre segmentos y 10 atípicos, de los que solo 6 eran errores.
En el conjunto de energía, los cuatro coeficientes lineales recuperaron los valores de diseño dentro de sus intervalos, y el de temperatura (\(-1.84\)) resumió una V con una recta.
El VIF máximo de 1.014 descartó la colinealidad; un número de condición de 686 reflejaba escalas distintas, no redundancia.
En prueba, el modelo dejó MAE = 22.40 kWh, RMSE = 27.66 kWh y \(R^2\) = 0.820, cerca del 0.817 de la validación cruzada y del piso que impone un ruido de 25 kWh.
Ridge y Lasso empataron con OLS (diferencias de 0.000009 en \(R^2\)) porque no había colinealidad que corregir.
La media y la correlación de los residuos valen 0 en entrenamiento por construcción, y solo informan en prueba (2.371 kWh y 0.088).
16.16 Puente hacia los siguientes capítulos
Aquí Ridge y Lasso empataron con OLS porque los predictores eran independientes. El capítulo de regularización estudia el caso contrario, con muchas variables o variables redundantes, y elige \(\alpha\) por validación cruzada antes de evaluar en prueba. Los capítulos de evaluación y bootstrap y de validación cruzada k-fold desarrollan el protocolo que usaste aquí para separar entrenamiento y prueba, y el de splines da una forma de corregir la V de la temperatura sin abandonar la regresión lineal.