1 Introducción

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:

  • \(\hat{Y}\) = valor predicho de la variable dependiente
  • \(b_0\) = intercepto (valor de \(\hat{Y}\) cuando \(X = 0\))
  • \(b_1\) = pendiente (cambio en \(\hat{Y}\) por cada unidad de aumento en \(X\))
  • \(X\) = variable independiente (predictora)

2 Datos del Ejemplo

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

3 Tabla de Cálculos

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

4 Cálculo de los Coeficientes

4.1 Fórmulas

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}\]

4.2 Sustitución Numérica

# 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
cat("Σ Y  =", sum_y,  "\n")
## Σ Y  = 458
cat("Σ X² =", sum_x2, "\n")
## Σ X² = 140
cat("Σ XY =", sum_xy, "\n")
## Σ 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 ---
cat("Pendiente  b₁ =", round(b1, 4), "\n")
## Pendiente  b₁ = 6.2857
cat("Intercepto b₀ =", round(b0, 4), "\n")
## Intercepto b₀ = 40.2857
cat("\nModelo: Ŷ =", round(b0, 2), "+", round(b1, 2), "· X\n")
## 
## Modelo: Ŷ = 40.29 + 6.29 · X

4.3 Interpretación del Modelo

  • Intercepto (\(b_0\) = 40.29): cuando un estudiante no estudia ninguna hora, la calificación esperada sería de aproximadamente 40.29 puntos.
  • Pendiente (\(b_1\) = 6.29): por cada hora adicional de estudio, la calificación aumenta en promedio 6.29 puntos.
  • Modelo final: \(\hat{Y} = 40.29 + 6.29 \cdot X\)

5 Verificación con lm()

R permite obtener el mismo resultado automáticamente con la función lm():

modelo <- lm(calif ~ horas)
summary(modelo)
## 
## 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:

cat("Cálculo manual  — b0:", round(b0, 4), " | b1:", round(b1, 4), "\n")
## Cálculo manual  — b0: 40.2857  | b1: 6.2857
cat("Función lm()    — b0:", round(coef(modelo)[1], 4),
    " | b1:", round(coef(modelo)[2], 4), "\n")
## Función lm()    — b0: 40.2857  | b1: 6.2857

6 Predicciones y Residuales

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.


7 Gráficas

7.1 Diagrama de Dispersión con Línea de Regresión

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

7.2 Gráfica de Residuales

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


8 Indicadores del Modelo

# 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
cat("Coeficiente de determinación (R²):", round(r2, 4), "\n")
## Coeficiente de determinación (R²): 0.9898
cat("R² en porcentaje:", round(r2 * 100, 2), "%\n")
## R² en porcentaje: 98.98 %
cat("\n--- Descomposición de la varianza ---\n")
## 
## --- Descomposición de la varianza ---
cat("SCT (Total)     =", round(sct, 4), "\n")
## SCT (Total)     = 1117.809
cat("SCR (Regresión) =", round(scr, 4), "\n")
## SCR (Regresión) = 1106.411
cat("SCE (Error)     =", round(sce, 4), "\n")
## 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

9 Conclusiones

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:

  • La pendiente positiva (\(b_1 = 6.29\)) confirma que existe una relación directa entre las horas de estudio y la calificación: a mayor dedicación, mayor rendimiento académico.
  • El coeficiente de determinación (\(R^2 = 98.98\%\)) indica que aproximadamente el 98.98% de la variabilidad en las calificaciones es explicada por las horas de estudio, lo que refleja un ajuste muy bueno del modelo.
  • La suma de cuadrados del error (SCE = 11.4) es la mínima posible para cualquier recta que pase por estos datos, lo cual confirma que los coeficientes obtenidos son óptimos bajo el criterio de Mínimos Cuadrados.
  • Los residuales se distribuyen aleatoriamente alrededor de cero, sin un patrón sistemático evidente, lo que sugiere que el modelo lineal es apropiado para estos datos.