El método de Mínimos Cuadrados es una técnica estadística que permite encontrar la recta que mejor se ajusta a un conjunto de datos, minimizando la suma de los cuadrados de las diferencias entre los valores observados y los valores predichos por el modelo.
El modelo de Regresión Lineal Simple tiene la forma:
\[\hat{Y} = b_0 + b_1 \cdot X\]
Donde:
Se utiliza un ejemplo con 7 estudiantes, relacionando las horas de estudio (X) con la calificación obtenida (Y).
# Definición de los datos
horas <- c(1, 2, 3, 4, 5, 6, 7)
calif <- c(45, 55, 60, 65, 70, 78, 85)
n <- length(horas)
cat("Número de observaciones (n):", n, "\n")## Número de observaciones (n): 7
Para aplicar las fórmulas de Mínimos Cuadrados se necesitan las sumas: \(\sum X\), \(\sum Y\), \(\sum X^2\) y \(\sum XY\).
library(gt)
library(dplyr)
library(tibble)
tabla_mc <- tibble(
Estudiante = 1:n,
X = horas,
Y = calif,
X2 = horas^2,
XY = horas * calif
)
# Fila de totales
totales <- tibble(
Estudiante = NA,
X = sum(horas),
Y = sum(calif),
X2 = sum(horas^2),
XY = sum(horas * calif)
)
bind_rows(tabla_mc, totales) %>%
gt() %>%
tab_header(
title = md("**Tabla N°1 — Cálculos para Mínimos Cuadrados**"),
subtitle = "Horas de estudio vs Calificación"
) %>%
cols_label(
Estudiante = md("**Estudiante**"),
X = md("**X (horas)**"),
Y = md("**Y (calificación)**"),
X2 = md("**X²**"),
XY = md("**XY**")
) %>%
cols_align(align = "center", columns = everything()) %>%
sub_missing(columns = Estudiante, missing_text = "TOTAL") %>%
tab_style(
style = cell_fill(color = "#F5F5F5"),
locations = cells_body(rows = n + 1)
) %>%
tab_style(
style = cell_text(weight = "bold"),
locations = cells_body(rows = n + 1)
) %>%
tab_source_note("Autor: Grupo 5") %>%
tab_options(
heading.title.font.size = px(14),
heading.subtitle.font.size = px(12),
heading.align = "center",
heading.background.color = "#AAAAAA",
column_labels.font.weight = "bold",
column_labels.background.color = "#FFFFFF",
column_labels.border.top.color = "#AAAAAA",
column_labels.border.bottom.color = "#AAAAAA",
table.border.top.color = "#AAAAAA",
table.border.bottom.color = "#AAAAAA",
table.width = pct(70)
) %>%
tab_style(
style = cell_text(color = "white", weight = "bold"),
locations = cells_title(groups = c("title", "subtitle"))
)| Tabla N°1 — Cálculos para Mínimos Cuadrados | ||||
| Horas de estudio vs Calificación | ||||
| Estudiante | X (horas) | Y (calificación) | X² | XY |
|---|---|---|---|---|
| 1 | 1 | 45 | 1 | 45 |
| 2 | 2 | 55 | 4 | 110 |
| 3 | 3 | 60 | 9 | 180 |
| 4 | 4 | 65 | 16 | 260 |
| 5 | 5 | 70 | 25 | 350 |
| 6 | 6 | 78 | 36 | 468 |
| 7 | 7 | 85 | 49 | 595 |
| TOTAL | 28 | 458 | 140 | 2008 |
| Autor: Grupo 5 | ||||
Los coeficientes \(b_1\) (pendiente) y \(b_0\) (intercepto) se calculan con:
\[b_1 = \frac{n \cdot \sum XY - \sum X \cdot \sum Y}{n \cdot \sum X^2 - \left(\sum X\right)^2}\]
\[b_0 = \frac{\sum Y - b_1 \cdot \sum X}{n}\]
# Sumas necesarias
sum_x <- sum(horas)
sum_y <- sum(calif)
sum_x2 <- sum(horas^2)
sum_xy <- sum(horas * calif)
cat("Σ X =", sum_x, "\n")## Σ X = 28
## Σ Y = 458
## Σ X² = 140
## Σ XY = 2008
# Pendiente b1
b1 <- (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x^2)
# Intercepto b0
b0 <- (sum_y - b1 * sum_x) / n
cat("\n--- Resultados ---\n")##
## --- Resultados ---
## Pendiente b₁ = 6.2857
## Intercepto b₀ = 40.2857
##
## Modelo: Ŷ = 40.29 + 6.29 · X
lm()R permite obtener el mismo resultado automáticamente con la función
lm():
##
## Call:
## lm(formula = calif ~ horas)
##
## Residuals:
## 1 2 3 4 5 6 7
## -1.571e+00 2.143e+00 8.571e-01 -4.286e-01 -1.714e+00 -6.106e-16 7.143e-01
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 40.2857 1.2778 31.53 6.03e-07 ***
## horas 6.2857 0.2857 22.00 3.60e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.512 on 5 degrees of freedom
## Multiple R-squared: 0.9898, Adjusted R-squared: 0.9877
## F-statistic: 484 on 1 and 5 DF, p-value: 3.603e-06
Los coeficientes del summary() deben coincidir
exactamente con los calculados manualmente:
## Cálculo manual — b0: 40.2857 | b1: 6.2857
## Función lm() — b0: 40.2857 | b1: 6.2857
Los valores predichos (\(\hat{Y}\)) son los que entrega el modelo para cada \(X\). Los residuales (\(e_i = Y_i - \hat{Y}_i\)) representan el error del modelo para cada observación.
library(tibble)
predichos <- round(b0 + b1 * horas, 2)
residuales <- round(calif - predichos, 2)
res_cuad <- round(residuales^2, 2)
tabla_pred <- tibble(
Estudiante = 1:n,
X = horas,
Y_obs = calif,
Y_pred = predichos,
Residual = residuales,
Residual2 = res_cuad
)
totales_pred <- tibble(
Estudiante = NA,
X = NA,
Y_obs = NA,
Y_pred = NA,
Residual = round(sum(residuales), 4),
Residual2 = sum(res_cuad)
)
bind_rows(tabla_pred, totales_pred) %>%
gt() %>%
tab_header(
title = md("**Tabla N°2 — Valores Predichos y Residuales**"),
subtitle = md("El modelo minimiza la columna **Residual²**")
) %>%
cols_label(
Estudiante = md("**Est.**"),
X = md("**X**"),
Y_obs = md("**Y observado**"),
Y_pred = md("**Ŷ predicho**"),
Residual = md("**eᵢ = Y − Ŷ**"),
Residual2 = md("**eᵢ²**")
) %>%
cols_align(align = "center", columns = everything()) %>%
sub_missing(columns = c(Estudiante, X, Y_obs, Y_pred), missing_text = "—") %>%
tab_style(
style = cell_fill(color = "#F5F5F5"),
locations = cells_body(rows = n + 1)
) %>%
tab_style(
style = cell_text(weight = "bold"),
locations = cells_body(rows = n + 1)
) %>%
tab_style(
style = cell_fill(color = "#EAF4FB"),
locations = cells_body(columns = Residual2)
) %>%
tab_source_note(md("**SCE (Suma de Cuadrados del Error)** = suma de eᵢ² — Autor: Grupo 5")) %>%
tab_options(
heading.title.font.size = px(14),
heading.subtitle.font.size = px(12),
heading.align = "center",
heading.background.color = "#AAAAAA",
column_labels.font.weight = "bold",
column_labels.background.color = "#FFFFFF",
column_labels.border.top.color = "#AAAAAA",
column_labels.border.bottom.color = "#AAAAAA",
table.border.top.color = "#AAAAAA",
table.border.bottom.color = "#AAAAAA",
table.width = pct(80)
) %>%
tab_style(
style = cell_text(color = "white", weight = "bold"),
locations = cells_title(groups = c("title", "subtitle"))
)| Tabla N°2 — Valores Predichos y Residuales | |||||
| El modelo minimiza la columna Residual² | |||||
| Est. | X | Y observado | Ŷ predicho | eᵢ = Y − Ŷ | eᵢ² |
|---|---|---|---|---|---|
| 1 | 1 | 45 | 46.57 | -1.57 | 2.46 |
| 2 | 2 | 55 | 52.86 | 2.14 | 4.58 |
| 3 | 3 | 60 | 59.14 | 0.86 | 0.74 |
| 4 | 4 | 65 | 65.43 | -0.43 | 0.18 |
| 5 | 5 | 70 | 71.71 | -1.71 | 2.92 |
| 6 | 6 | 78 | 78.00 | 0.00 | 0.00 |
| 7 | 7 | 85 | 84.29 | 0.71 | 0.50 |
| — | — | — | — | 0.00 | 11.38 |
| SCE (Suma de Cuadrados del Error) = suma de eᵢ² — Autor: Grupo 5 | |||||
Nota: la suma de residuales (\(\sum e_i\)) siempre es igual a 0 (o muy cercana a 0 por redondeo), lo que confirma que la recta pasa por el centro de los datos.
library(ggplot2)
datos_graf <- data.frame(
horas = horas,
calif = calif,
predichos = predichos
)
ggplot(datos_graf, aes(x = horas, y = calif)) +
geom_segment(aes(xend = horas, yend = predichos),
color = "#E24B4A", linewidth = 0.8, linetype = "solid") +
geom_smooth(method = "lm", se = FALSE, color = "#185FA5",
linewidth = 1.2, formula = y ~ x) +
geom_point(color = "#378ADD", size = 4) +
scale_x_continuous(breaks = 1:7) +
scale_y_continuous(limits = c(35, 95)) +
labs(
title = "Gráfica N°1: Regresión Lineal — Horas de estudio vs Calificación",
x = "Horas de estudio (X)",
y = "Calificación (Y)",
caption = "Las líneas rojas representan los residuales | Autor: Grupo 5"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 13),
plot.caption = element_text(color = "#888888", size = 9),
axis.title = element_text(face = "bold"),
panel.grid.minor = element_blank(),
plot.background = element_rect(fill = "white", color = NA)
)datos_res <- data.frame(
horas = horas,
residuales = residuales
)
ggplot(datos_res, aes(x = horas, y = residuales)) +
geom_hline(yintercept = 0, color = "#185FA5", linewidth = 1, linetype = "dashed") +
geom_segment(aes(xend = horas, yend = 0), color = "#E24B4A", linewidth = 0.8) +
geom_point(color = "#E24B4A", size = 4) +
scale_x_continuous(breaks = 1:7) +
labs(
title = "Gráfica N°2: Residuales vs Horas de estudio",
x = "Horas de estudio (X)",
y = "Residual (eᵢ)",
caption = "Los residuales deben distribuirse aleatoriamente alrededor del cero | Autor: Grupo 5"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 13),
plot.caption = element_text(color = "#888888", size = 9),
axis.title = element_text(face = "bold"),
panel.grid.minor = element_blank(),
plot.background = element_rect(fill = "white", color = NA)
)# R² (coeficiente de determinación)
r2 <- summary(modelo)$r.squared
r <- sqrt(r2)
sce <- sum(residuales^2)
scr <- sum((predichos - mean(calif))^2)
sct <- sce + scr
cat("Correlación de Pearson (r):", round(r, 4), "\n")## Correlación de Pearson (r): 0.9949
## Coeficiente de determinación (R²): 0.9898
## R² en porcentaje: 98.98 %
##
## --- Descomposición de la varianza ---
## SCT (Total) = 1117.809
## SCR (Regresión) = 1106.411
## SCE (Error) = 11.3972
data.frame(
Indicador = c("Pendiente (b₁)", "Intercepto (b₀)", "Correlación (r)",
"Coef. Determinación (R²)", "SCE (error mínimo)"),
Valor = c(round(b1, 4), round(b0, 4), round(r, 4),
paste0(round(r2 * 100, 2), "%"), round(sce, 4))
) %>%
gt() %>%
tab_header(
title = md("**Tabla N°3 — Resumen de Indicadores del Modelo**")
) %>%
cols_label(
Indicador = md("**Indicador**"),
Valor = md("**Valor**")
) %>%
cols_align(align = "center", columns = everything()) %>%
tab_source_note("Autor: Grupo 5") %>%
tab_options(
heading.title.font.size = px(14),
heading.align = "center",
heading.background.color = "#AAAAAA",
column_labels.font.weight = "bold",
column_labels.background.color = "#FFFFFF",
column_labels.border.top.color = "#AAAAAA",
column_labels.border.bottom.color = "#AAAAAA",
table.border.top.color = "#AAAAAA",
table.border.bottom.color = "#AAAAAA",
table.width = pct(60)
) %>%
tab_style(
style = cell_text(color = "white", weight = "bold"),
locations = cells_title(groups = "title")
)| Tabla N°3 — Resumen de Indicadores del Modelo | |
| Indicador | Valor |
|---|---|
| Pendiente (b₁) | 6.2857 |
| Intercepto (b₀) | 40.2857 |
| Correlación (r) | 0.9949 |
| Coef. Determinación (R²) | 98.98% |
| SCE (error mínimo) | 11.3972 |
| Autor: Grupo 5 | |
El método de Mínimos Cuadrados permitió ajustar una recta de regresión lineal simple al conjunto de datos de horas de estudio y calificaciones, obteniendo el modelo:
\[\hat{Y} = 40.29 + 6.29 \cdot X\]
Los principales hallazgos son: