Al finalizar esta unidad, el estudiante podrá formular, estimar, evaluar e interpretar un modelo de regresión lineal simple, comunicar su incertidumbre y justificar decisiones empresariales sin confundir asociación estadística con causalidad.
Preguntas orientadoras: ¿Cómo cambian las ventas cuando aumenta la inversión publicitaria? ¿Qué parte de la variación de las ventas explica el modelo? ¿Qué tan precisa es una predicción? ¿Qué condiciones deben cumplirse para confiar en las conclusiones?
Ruta de aprendizaje: pregunta de negocio → diagrama de dispersión → modelo → mínimos cuadrados → bondad de ajuste → inferencia → predicción → diagnóstico → recomendación.
Una empresa registra durante 24 períodos su inversión publicitaria y sus ventas. Ambas variables se expresan en millones de pesos por período. La dirección desea anticipar ventas y evaluar si la inversión está asociada con mejores resultados.
Para garantizar que todos puedan reproducir los cálculos, utilizaremos datos simulados con fines pedagógicos. No representan observaciones reales de una compañía ni permiten atribuir efectos causales a la publicidad.
periodo <- 1:24
inversion <- c(4,7,5,9,6,11,8,12,10,14,7,13,
15,9,16,12,18,14,17,20,16,19,21,23)
ruido <- c(3,-4,1,5,-2,-3,4,-5,2,1,-1,3,
-4,2,5,-2,1,-3,4,-4,0,3,-2,2)
ventas <- 35 + 4.2*inversion + ruido
datos <- data.frame(periodo, inversion, ventas)
kable(head(datos, 10), digits=2,
col.names=c('Período','Inversión (millones)','Ventas (millones)'))| Período | Inversión (millones) | Ventas (millones) |
|---|---|---|
| 1 | 4 | 54.8 |
| 2 | 7 | 60.4 |
| 3 | 5 | 57.0 |
| 4 | 9 | 77.8 |
| 5 | 6 | 58.2 |
| 6 | 11 | 78.2 |
| 7 | 8 | 72.6 |
| 8 | 12 | 80.4 |
| 9 | 10 | 79.0 |
| 10 | 14 | 94.8 |
Antes de modelar: ¿esperamos una relación positiva, negativa o nula? ¿Una asociación positiva implica necesariamente que la publicidad causa el aumento de las ventas? ¿Qué otras variables podrían explicar las ventas (temporada, precios, promociones, competencia)?
ggplot(datos, aes(inversion, ventas)) +
geom_point(size=3, color='#176aa0') +
labs(title='Inversión publicitaria y ventas',
subtitle='Datos simulados: 24 períodos',
x='Inversión publicitaria (millones de pesos)',
y='Ventas (millones de pesos)') +
theme_minimal(base_size=13)El modelo poblacional describe la relación entre una variable respuesta \(Y\) y una variable explicativa \(X\):
\[Y_i=\beta_0+\beta_1X_i+\varepsilon_i.\]
Bajo el supuesto \(E(\varepsilon_i\mid X_i)=0\), la media condicional es:
\[E(Y_i\mid X_i)=\beta_0+\beta_1X_i.\]
La recta estimada utiliza los datos de la muestra:
\[\widehat{Y}_i=b_0+b_1X_i.\]
Es fundamental distinguir \(Y_i\) (valor observado), \(\widehat{Y}_i\) (valor ajustado) y \(e_i=Y_i-\widehat{Y}_i\) (residuo). El residuo es observable después de ajustar el modelo; el error poblacional \(\varepsilon_i\) no lo es.
El método de mínimos cuadrados ordinarios (MCO) elige \(b_0\) y \(b_1\) para minimizar la suma de cuadrados de los residuos:
\[SCE=\sum_{i=1}^{n}(Y_i-b_0-b_1X_i)^2.\]
Al derivar respecto a ambos coeficientes e igualar a cero, obtenemos las ecuaciones normales. Su solución, si los valores de \(X\) no son todos iguales, es:
\[b_1=\frac{\sum_{i=1}^{n}(X_i-\overline X)(Y_i-\overline Y)}{\sum_{i=1}^{n}(X_i-\overline X)^2},\qquad b_0=\overline Y-b_1\overline X.\]
Interpretación: la pendiente compara cómo se mueven conjuntamente \(X\) e \(Y\) con la dispersión propia de \(X\). La recta estimada pasa por \((\overline X,\overline Y)\) cuando el modelo incluye intercepto.
x <- datos$inversion
y <- datos$ventas
x_barra <- mean(x); y_barra <- mean(y)
Sxx <- sum((x-x_barra)^2)
Sxy <- sum((x-x_barra)*(y-y_barra))
b1 <- Sxy/Sxx
b0 <- y_barra-b1*x_barra
modelo <- lm(ventas ~ inversion, data=datos)
kable(data.frame(Parametro=c('Intercepto','Pendiente'),
Calculo_manual=c(b0,b1),
Funcion_lm=unname(coef(modelo))), digits=4)| Parametro | Calculo_manual | Funcion_lm |
|---|---|---|
| Intercepto | 35.4558 | 35.4558 |
| Pendiente | 4.1839 | 4.1839 |
La función lm() ajusta la misma recta mediante MCO.
Explique con sus palabras qué significa la pendiente
estimada en millones de pesos de ventas por cada millón adicional
invertido. El intercepto no debe interpretarse como pronóstico confiable
de ventas sin publicidad si \(X=0\)
queda fuera del rango observado.
ggplot(datos, aes(inversion, ventas)) +
geom_point(color='#176aa0', size=2.8) +
geom_smooth(method='lm', se=FALSE, color='#c0392b', linewidth=1.1) +
labs(title='Recta de mínimos cuadrados',
x='Inversión publicitaria (millones)',
y='Ventas (millones)') +
theme_minimal(base_size=13)datos$ajustado <- fitted(modelo)
datos$residuo <- resid(modelo)
ggplot(datos, aes(inversion, ventas)) +
geom_segment(aes(xend=inversion, yend=ajustado),
color='#d35400', linewidth=.8) +
geom_point(color='#176aa0', size=2.7) +
geom_line(aes(y=ajustado), color='#b52c36', linewidth=1) +
labs(title='Distancias verticales entre observaciones y recta',
subtitle='MCO minimiza la suma de estas distancias elevadas al cuadrado',
x='Inversión (millones)', y='Ventas (millones)') +
theme_minimal(base_size=13)kable(head(transform(datos, residuo_cuadrado=residuo^2)[,
c('periodo','ventas','ajustado','residuo','residuo_cuadrado')],8),
digits=3)| periodo | ventas | ajustado | residuo | residuo_cuadrado |
|---|---|---|---|---|
| 1 | 54.8 | 52.191 | 2.609 | 6.806 |
| 2 | 60.4 | 64.743 | -4.343 | 18.860 |
| 3 | 57.0 | 56.375 | 0.625 | 0.391 |
| 4 | 77.8 | 73.111 | 4.689 | 21.991 |
| 5 | 58.2 | 60.559 | -2.359 | 5.565 |
| 6 | 78.2 | 81.478 | -3.278 | 10.747 |
| 7 | 72.6 | 68.927 | 3.673 | 13.493 |
| 8 | 80.4 | 85.662 | -5.262 | 27.690 |
## Suma de cuadrados residual: 226.331
Compruebe lo siguiente: en una regresión con intercepto, la suma de los residuos es aproximadamente cero (salvo error numérico). Esto no significa que el modelo sea correcto ni que sus predicciones sean exactas.
La correlación de Pearson mide dirección e intensidad de la asociación lineal:
\[r=\frac{\sum(X_i-\overline X)(Y_i-\overline Y)}{\sqrt{\sum(X_i-\overline X)^2\sum(Y_i-\overline Y)^2}},\quad -1\le r\le1.\]
Un valor cercano a \(1\) indica asociación lineal positiva fuerte; cercano a \(-1\), negativa fuerte; cercano a cero, poca asociación lineal (aunque podría existir una relación no lineal).
La variabilidad total de \(Y\) puede descomponerse, en MCO con intercepto, en:
\[SCT=\sum(Y_i-\overline Y)^2,\quad SCR=\sum(\widehat Y_i-\overline Y)^2,\quad SCE=\sum(Y_i-\widehat Y_i)^2.\]
\[SCT=SCR+SCE,\qquad R^2=\frac{SCR}{SCT}=1-\frac{SCE}{SCT}.\]
En regresión lineal simple con intercepto, \(R^2=r^2\). Esta igualdad no debe generalizarse sin cuidado a modelos sin intercepto o a otras especificaciones.
SCT <- sum((y-mean(y))^2)
SCE <- sum(resid(modelo)^2)
SCR <- SCT-SCE
r <- cor(x,y)
R2 <- summary(modelo)$r.squared
kable(data.frame(Indicador=c('Correlación r','R cuadrado','SCT','SCR','SCE'),
Valor=c(r,R2,SCT,SCR,SCE)),digits=4)| Indicador | Valor |
|---|---|
| Correlación r | 0.9902 |
| R cuadrado | 0.9805 |
| SCT | 11613.1200 |
| SCR | 11386.7895 |
| SCE | 226.3305 |
Interpretación correcta: \(R^2\) es la proporción de variabilidad observada de las ventas explicada por la recta ajustada en esta muestra. No es la probabilidad de que el modelo sea verdadero, ni el porcentaje de ventas causado por la publicidad, ni una garantía de precisión futura.
Para interpretar los coeficientes y realizar inferencia clásica debemos examinar:
Advertencia: una nube de puntos muy alineada no demuestra que estos supuestos se cumplan. En nuestro caso, los datos están ordenados por períodos y por eso conviene revisar dependencia temporal.
Con dos parámetros estimados (intercepto y pendiente), los grados de libertad residuales son \(n-2\):
\[s^2=\frac{SCE}{n-2},\qquad s=\sqrt{\frac{SCE}{n-2}}.\]
El error estándar residual expresa la magnitud típica de los residuos en las unidades de \(Y\), aunque no es un límite máximo de error.
## Error estándar residual: 3.207 millones de pesos
## Grados de libertad: 22
La pregunta inferencial es si la pendiente poblacional es distinta de cero:
\[H_0:\beta_1=0,\qquad H_1:\beta_1\ne0.\]
Para el modelo clásico:
\[EE(b_1)=\frac{s}{\sqrt{S_{xx}}},\qquad t=\frac{b_1-0}{EE(b_1)},\quad gl=n-2.\]
Bajo \(H_0\) y los supuestos correspondientes, el estadístico sigue una distribución t con \(n-2\) grados de libertad. El valor-p mide qué tan extremos serían los resultados observados, o más, si \(H_0\) fuera verdadera; no es la probabilidad de que \(H_0\) sea cierta.
resumen <- summary(modelo)
tabla_coef <- coef(resumen)
kable(tabla_coef,digits=5,caption='Estimaciones, errores estándar, t y valores-p')| Estimate | Std. Error | t value | Pr(>|t|) | |
|---|---|---|---|---|
| (Intercept) | 35.45580 | 1.73194 | 20.47176 | 0 |
| inversion | 4.18386 | 0.12576 | 33.26905 | 0 |
alpha <- .05
p_pendiente <- tabla_coef['inversion','Pr(>|t|)']
cat('Decisión al 5%:',ifelse(p_pendiente<alpha,
'Rechazar H0: evidencia de pendiente no nula.',
'No rechazar H0: evidencia insuficiente.'),'\n')## Decisión al 5%: Rechazar H0: evidencia de pendiente no nula.
Importante: una pendiente estadísticamente significativa puede ser pequeña o poco relevante económicamente. Tampoco demuestra causalidad.
\[b_1\pm t_{1-\alpha/2,n-2}\,EE(b_1).\]
## 2.5 % 97.5 %
## (Intercept) 31.863986 39.047621
## inversion 3.923052 4.444665
Interprete el intervalo de la pendiente en millones de pesos de ventas por cada millón de inversión, aclarando que el 95% corresponde a la cobertura del procedimiento en muestreos repetidos bajo sus supuestos.
La prueba F contrasta si el modelo con predictor mejora, en términos de suma de cuadrados, respecto al modelo con solo intercepto. En regresión simple con intercepto, contrasta \(H_0:\beta_1=0\) y cumple \(F=t^2\) para la pendiente.
\[CMR=\frac{SCR}{1},\quad CME=\frac{SCE}{n-2},\quad F=\frac{CMR}{CME}.\]
| Df | Sum Sq | Mean Sq | F value | Pr(>F) | |
|---|---|---|---|---|---|
| inversion | 1 | 11386.7895 | 11386.7895 | 1106.83 | 0 |
| Residuals | 22 | 226.3305 | 10.2878 | NA | NA |
## F calculada: 1106.83
## t de pendiente al cuadrado: 1106.83
La prueba F y la prueba t proporcionan la misma decisión para la pendiente en este caso. Esto deja de ser una equivalencia general cuando se prueban varios coeficientes simultáneamente.
La empresa considera una inversión de 15 millones de pesos. Debemos distinguir dos preguntas:
La predicción puntual es \(\widehat y_0=b_0+b_1x_0\). Para \(x_0=15\):
\[EE(\widehat{E[Y\mid x_0]})=s\sqrt{\frac1n+\frac{(x_0-\overline X)^2}{S_{xx}}}.\]
\[EE(\text{predicción individual})=s\sqrt{1+\frac1n+\frac{(x_0-\overline X)^2}{S_{xx}}}.\]
Ambos intervalos usan el valor crítico \(t_{1-\alpha/2,n-2}\), pero el intervalo de predicción es más ancho porque incorpora la variabilidad de una nueva observación.
nuevo <- data.frame(inversion=15)
IC_media <- predict(modelo,newdata=nuevo,interval='confidence',level=.95)
IP_individual <- predict(modelo,newdata=nuevo,interval='prediction',level=.95)
kable(rbind('IC para media'=IC_media,'IP para observación'=IP_individual),digits=3)| fit | lwr | upr | |
|---|---|---|---|
| 1 | 98.214 | 96.734 | 99.693 |
| 1 | 98.214 | 91.399 | 105.028 |
rejilla <- data.frame(inversion=seq(min(x),max(x),length.out=150))
ic <- as.data.frame(predict(modelo,rejilla,interval='confidence'))
ip <- as.data.frame(predict(modelo,rejilla,interval='prediction'))
bandas <- cbind(rejilla, media=ic$fit, ic_inf=ic$lwr, ic_sup=ic$upr,
ip_inf=ip$lwr, ip_sup=ip$upr)
ggplot() +
geom_ribbon(data=bandas,aes(inversion,ymin=ip_inf,ymax=ip_sup),
fill='#bdd7e7',alpha=.5) +
geom_ribbon(data=bandas,aes(inversion,ymin=ic_inf,ymax=ic_sup),
fill='#4292c6',alpha=.4) +
geom_line(data=bandas,aes(inversion,media),color='#b2182b',linewidth=1) +
geom_point(data=datos,aes(inversion,ventas),color='#184b70',size=2) +
labs(title='Incertidumbre: media condicional frente a observación futura',
subtitle='Banda estrecha: IC 95% de la media; banda amplia: IP 95% individual',
x='Inversión (millones)',y='Ventas (millones)') +
theme_minimal(base_size=12)Discusión: ¿por qué las bandas se amplían cuando nos alejamos del promedio de inversión? ¿Sería razonable predecir para 80 millones si los datos observados solo cubren de 4 a 23 millones? Esto último sería extrapolación y requiere cautela especial.
El diagnóstico evalúa si el modelo describe razonablemente los datos y si algunas observaciones influyen desproporcionadamente en el ajuste.
Buscamos ausencia de patrones sistemáticos. Una curva sugiere no linealidad; un embudo, varianza no constante.
ggplot(data.frame(ajustado=fitted(modelo),residuo=resid(modelo)),
aes(ajustado,residuo)) +
geom_hline(yintercept=0,linetype='dashed',color='#b2182b') +
geom_point(color='#176aa0',size=2.7) +
geom_smooth(se=FALSE,method='loess',color='#d35400') +
labs(title='Residuos frente a valores ajustados',
x='Ventas ajustadas',y='Residuo') +
theme_minimal(base_size=13)ggplot(data.frame(residuo=rstandard(modelo)),aes(sample=residuo)) +
stat_qq(color='#176aa0') + stat_qq_line(color='#b2182b') +
labs(title='Gráfico Q-Q de residuos estandarizados',
x='Cuantiles teóricos normales',y='Cuantiles observados') +
theme_minimal(base_size=13)Las desviaciones de la línea pueden sugerir colas pesadas o asimetría. Un gráfico Q-Q no prueba por sí solo que los errores sean normales; además, los residuos no son idénticos a los errores poblacionales.
ggplot(datos,aes(periodo,residuo)) +
geom_hline(yintercept=0,linetype='dashed',color='#b2182b') +
geom_line(color='#176aa0') + geom_point(color='#176aa0') +
labs(title='Residuos ordenados por período',x='Período',y='Residuo') +
theme_minimal(base_size=13)En datos secuenciales es importante revisar ciclos, tendencias y
autocorrelación. No basta con asumir independencia porque se haya usado
lm().
diagnostico <- data.frame(
periodo=datos$periodo,
residuo_estandarizado=rstandard(modelo),
leverage=hatvalues(modelo),
cook=cooks.distance(modelo))
kable(diagnostico[order(-diagnostico$cook),][1:6,],digits=4,
caption='Seis observaciones con mayor distancia de Cook')| periodo | residuo_estandarizado | leverage | cook | |
|---|---|---|---|---|
| 20 | 20 | -1.3755 | 0.1225 | 0.1320 |
| 2 | 2 | -1.4213 | 0.0925 | 0.1029 |
| 4 | 4 | 1.5106 | 0.0633 | 0.0771 |
| 1 | 1 | 0.8871 | 0.1594 | 0.0746 |
| 15 | 15 | 1.5426 | 0.0579 | 0.0731 |
| 8 | 8 | -1.6766 | 0.0425 | 0.0624 |
ggplot(diagnostico,aes(periodo,cook)) +
geom_col(fill='#2677a8') +
geom_hline(yintercept=4/nrow(datos),linetype='dashed',color='#b2182b') +
labs(title='Distancia de Cook por período',
subtitle='Línea punteada: regla exploratoria 4/n (no criterio definitivo)',
x='Período',y='Distancia de Cook') +
theme_minimal(base_size=13)Precaución: no se deben eliminar observaciones solo porque contradigan el modelo. Primero hay que verificar captura, contexto, representatividad y sensibilidad de las conclusiones.
Creamos una copia de los datos e introducimos una venta extraordinariamente alta en un periodo de inversión elevada. Este escenario es artificial y permite observar la influencia de un punto.
datos_alt <- datos
indice <- which.max(datos_alt$inversion)
datos_alt$ventas[indice] <- datos_alt$ventas[indice] + 65
modelo_alt <- lm(ventas~inversion,data=datos_alt)
comparacion <- data.frame(
Modelo=c('Original','Con observación extrema'),
Intercepto=c(coef(modelo)[1],coef(modelo_alt)[1]),
Pendiente=c(coef(modelo)[2],coef(modelo_alt)[2]),
R2=c(summary(modelo)$r.squared,summary(modelo_alt)$r.squared))
kable(comparacion,digits=3)| Modelo | Intercepto | Pendiente | R2 |
|---|---|---|---|
| Original | 35.456 | 4.184 | 0.981 |
| Con observación extrema | 25.105 | 5.208 | 0.821 |
ggplot() +
geom_point(data=datos,aes(inversion,ventas),color='#176aa0',size=2.4) +
geom_point(data=datos_alt[indice,,drop=FALSE],
aes(inversion,ventas),color='#c0392b',size=4) +
geom_abline(intercept=coef(modelo)[1],slope=coef(modelo)[2],
color='#176aa0',linewidth=1) +
geom_abline(intercept=coef(modelo_alt)[1],slope=coef(modelo_alt)[2],
color='#c0392b',linetype='dashed',linewidth=1) +
labs(title='Sensibilidad del ajuste a una observación extrema',
subtitle='Azul: modelo original; rojo punteado: modelo modificado',
x='Inversión (millones)',y='Ventas (millones)') +
theme_minimal(base_size=13)Reflexión: ¿cuánto cambia la pendiente? ¿Qué decisión empresarial podría cambiar si no se revisara este dato? ¿Sería justificable eliminarlo sin investigar su origen?
Supongamos que la dirección propone aumentar la inversión de 12 a 15 millones. Según la recta, la diferencia en ventas medias estimadas es:
\[\widehat{\Delta Y}=b_1(15-12).\]
ventas_12 <- predict(modelo,newdata=data.frame(inversion=12))
ventas_15 <- predict(modelo,newdata=data.frame(inversion=15))
cat('Ventas medias estimadas con inversión 12:',round(ventas_12,2),'millones\n')## Ventas medias estimadas con inversión 12: 85.66 millones
## Ventas medias estimadas con inversión 15: 98.21 millones
## Diferencia estimada: 12.55 millones
No confundir: una diferencia de ventas no equivale a utilidad. Para recomendar la inversión se requieren, al menos, margen de contribución, costos, capacidad operativa, horizonte temporal y evidencia que permita atribuir el cambio a la inversión. La regresión observacional presentada es una herramienta descriptiva y predictiva, no una evaluación causal.
Estos cuatro ejercicios cortos permiten comprobar lo
aprendido sin convertir la práctica en otro proyecto. Se utiliza la base
mtcars, incluida en R. Los datos son históricos y se usan
exclusivamente con fines pedagógicos.
Contexto: una empresa de transporte desea comprender
cómo se relaciona el peso de un vehículo con su rendimiento de
combustible. En mtcars, wt mide el peso en
miles de libras y mpg mide el rendimiento
en millas por galón. No se requiere buscar datos,
calcular costos ni redactar un informe ejecutivo.
flota <- data.frame(peso = mtcars$wt, rendimiento = mtcars$mpg)
modelo_flota <- lm(rendimiento ~ peso, data = flota)La gerencia quiere saber si los vehículos más pesados tienden a rendir más o menos combustible.
peso frente a
rendimiento.El equipo de análisis ajustó una regresión lineal para explicar el rendimiento a partir del peso.
Antes de utilizar el modelo, la gerencia pregunta si existe evidencia estadística de una relación lineal.
La empresa estudia un vehículo cuyo peso es de 3.000
libras (peso = 3 en esta base).
predict().Resuelva los cuatro ejercicios con ayuda del material de clase. No se solicita informe, presentación, búsqueda de bases de datos ni trabajo adicional de investigación. Para cada ejercicio basta con ejecutar el código indicado y responder brevemente las preguntas de interpretación. Esta actividad sirve para reforzar los conceptos mientras se desarrolla el proyecto principal del curso.
Un modelo de regresión lineal simple no es solo una ecuación: es una cadena de decisiones analíticas. Primero formulamos una pregunta, después examinamos la relación entre variables, estimamos una recta, cuantificamos incertidumbre, revisamos los supuestos y finalmente comunicamos conclusiones con límites explícitos.
Idea central: el valor de la regresión no está en dibujar la mejor línea, sino en saber qué podemos afirmar con ella y qué todavía no.
Anderson, D. R., Sweeney, D. J., & Williams, T. A. (2008). Estadística para administración y economía (10.ª ed.). Cengage Learning. Capítulo 14: Regresión lineal simple.