# install.packages(c("nortest", "boot", "ggplot2", "knitr"))
library(nortest)
library(boot)
library(ggplot2)
library(knitr)

1. Errores Tipo I y Tipo II

Al realizar una prueba de hipótesis siempre existe la posibilidad de cometer un error. Los dos tipos de error son:

H₀ verdadera H₀ falsa
No rechazamos H₀ ✅ Decisión correcta ❌ Error Tipo II (β)
Rechazamos H₀ ❌ Error Tipo I (α) ✅ Decisión correcta (Potencia)
  • Error Tipo I (α): Rechazar H₀ cuando es verdadera → falso positivo. Por convención α = 0.05.
  • Error Tipo II (β): No rechazar H₀ cuando es falsa → falso negativo.
  • Potencia = 1 − β: Probabilidad de detectar un efecto real. Meta: ≥ 0.80 (80%)

2. El P-valor

El p-valor es la probabilidad de obtener un resultado tan extremo como el observado, suponiendo que H₀ es verdadera.

  • Si p-valor < α → Rechazamos H₀
  • Si p-valor ≥ α → No rechazamos H₀
set.seed(123)
muestra_normal   <- rnorm(50, mean = 0, sd = 1)
muestra_uniforme <- runif(50, min = -3, max = 3)

cat("Shapiro-Wilk – muestra NORMAL:\n")
## Shapiro-Wilk – muestra NORMAL:
shapiro.test(muestra_normal)
## 
##  Shapiro-Wilk normality test
## 
## data:  muestra_normal
## W = 0.98928, p-value = 0.9279
cat("\nShapiro-Wilk – muestra UNIFORME:\n")
## 
## Shapiro-Wilk – muestra UNIFORME:
shapiro.test(muestra_uniforme)
## 
##  Shapiro-Wilk normality test
## 
## data:  muestra_uniforme
## W = 0.94659, p-value = 0.02474

La muestra normal arroja un p-valor alto (no rechazamos normalidad), mientras que la uniforme tiene un p-valor bajo (rechazamos normalidad).


3. Pruebas de Normalidad

Todas estas pruebas tienen la misma hipótesis:

  • H₀: Los datos siguen una distribución Normal
  • H₁: Los datos NO siguen una distribución Normal
Prueba Función en R Paquete
Shapiro-Wilk shapiro.test() base R
Lilliefors lillie.test() nortest
Cramér-von Mises cvm.test() nortest
Anderson-Darling ad.test() nortest
aplicar_pruebas <- function(x, nombre = "muestra") {
  sw  <- shapiro.test(x)
  lf  <- lillie.test(x)
  cvm <- cvm.test(x)
  ad  <- ad.test(x)

  resultados <- data.frame(
    Prueba     = c("Shapiro-Wilk", "Lilliefors", "Cramér-von Mises", "Anderson-Darling"),
    Estadistico = round(c(sw$statistic, lf$statistic, cvm$statistic, ad$statistic), 4),
    P_valor    = round(c(sw$p.value,   lf$p.value,   cvm$p.value,   ad$p.value),   4),
    Decision   = ifelse(
      c(sw$p.value, lf$p.value, cvm$p.value, ad$p.value) < 0.05,
      "Rechaza normalidad ✗",
      "No rechaza normalidad ✓"
    )
  )
  kable(resultados, caption = paste("Pruebas de normalidad –", nombre))
}

3.1 Muestra Normal

aplicar_pruebas(muestra_normal, "Normal(0,1) n=50")
Pruebas de normalidad – Normal(0,1) n=50
Prueba Estadistico P_valor Decision
Shapiro-Wilk 0.9893 0.9279 No rechaza normalidad ✓
Lilliefors 0.0832 0.5233 No rechaza normalidad ✓
Cramér-von Mises 0.0364 0.7407 No rechaza normalidad ✓
Anderson-Darling 0.2100 0.8529 No rechaza normalidad ✓

3.2 Muestra Uniforme

aplicar_pruebas(muestra_uniforme, "Uniforme(-3,3) n=50")
Pruebas de normalidad – Uniforme(-3,3) n=50
Prueba Estadistico P_valor Decision
Shapiro-Wilk 0.9466 0.0247 Rechaza normalidad ✗
Lilliefors 0.0927 0.3503 No rechaza normalidad ✓
Cramér-von Mises 0.0955 0.1258 No rechaza normalidad ✓
Anderson-Darling 0.6994 0.0637 No rechaza normalidad ✓

4. Bootstrap – Remuestreo

El bootstrap permite estimar la distribución de un estadístico cuando no conocemos la distribución poblacional.

Pasos:

  1. Tenemos una muestra de tamaño n
  2. Remuestreamos con reemplazo B veces
  3. Calculamos el estadístico en cada remuestra
  4. La distribución de esos B valores estima la distribución del estadístico
set.seed(42)
datos <- c(23, 45, 12, 67, 34, 89, 15, 52, 38, 71)

B            <- 1000
medias_boot  <- numeric(B)

for (i in 1:B) {
  remuestra      <- sample(datos, size = length(datos), replace = TRUE)
  medias_boot[i] <- mean(remuestra)
}

ic_boot <- quantile(medias_boot, probs = c(0.025, 0.975))

cat("Media original     :", mean(datos))
## Media original     : 44.6
cat("\nMedia bootstrap    :", round(mean(medias_boot), 4))
## 
## Media bootstrap    : 44.6749
cat("\nError estándar boot:", round(sd(medias_boot), 4))
## 
## Error estándar boot: 7.6402
cat("\nIC 95% Bootstrap   : [", round(ic_boot[1], 4), ",", round(ic_boot[2], 4), "]\n")
## 
## IC 95% Bootstrap   : [ 29.5 , 58.6075 ]
df_boot <- data.frame(media = medias_boot)

ggplot(df_boot, aes(x = media)) +
  geom_histogram(bins = 35, fill = "steelblue", color = "white", alpha = 0.85) +
  geom_vline(xintercept = mean(datos),  color = "red",    linewidth = 1.2, linetype = "dashed") +
  geom_vline(xintercept = ic_boot,      color = "orange", linewidth = 1,   linetype = "dotted") +
  annotate("text", x = mean(datos) + 1, y = 80,
           label = "Media original", color = "red", hjust = 0) +
  labs(
    title    = "Distribución Bootstrap de la Media (B = 1000)",
    subtitle = "Línea roja = media original | Líneas naranja = IC 95%",
    x = "Media", y = "Frecuencia"
  ) +
  theme_minimal(base_size = 13)


5. Simulación de Potencia

Comparamos la potencia de Shapiro-Wilk, Lilliefors y Cramér-von Mises bajo distintos tamaños de muestra.

Estrategia:

  • Para cada n, generamos B = 500 muestras de una distribución no normal
  • Aplicamos cada prueba y contamos cuántas veces rechaza H₀
  • Potencia estimada = proporción de rechazos
simular_potencia <- function(n, B = 500, distribucion = "t3", alpha = 0.05) {
  rechazo_sw  <- numeric(B)
  rechazo_lf  <- numeric(B)
  rechazo_cvm <- numeric(B)

  for (i in 1:B) {
    x <- switch(distribucion,
      "t3"       = rt(n, df = 3),
      "exp"      = rexp(n, rate = 1),
      "uniforme" = runif(n, -3, 3),
      "normal"   = rnorm(n)
    )

    rechazo_sw[i] <- shapiro.test(x)$p.value < alpha
    rechazo_lf[i] <- lillie.test(x)$p.value  < alpha

    # Solo si n > 7
    if (n > 7) {
      rechazo_cvm[i] <- cvm.test(x)$p.value < alpha
    } else {
      rechazo_cvm[i] <- NA
    }
  }

  data.frame(
    n            = n,
    distribucion = distribucion,
    Shapiro_Wilk = round(mean(rechazo_sw, na.rm = TRUE), 3),
    Lilliefors   = round(mean(rechazo_lf, na.rm = TRUE), 3),
    CVM          = round(mean(rechazo_cvm, na.rm = TRUE), 3)
  )
}

5.1 Distribución alternativa: t con 3 grados de libertad

set.seed(2024)
tamanos      <- c(5, 10, 20, 50, 100)
resultados_t3 <- do.call(rbind, lapply(tamanos, simular_potencia,
                                        B = 500, distribucion = "t3"))
kable(resultados_t3, caption = "Potencia estimada – alternativa: t(3)")
Potencia estimada – alternativa: t(3)
n distribucion Shapiro_Wilk Lilliefors CVM
5 t3 0.088 0.096 NaN
10 t3 0.178 0.152 0.176
20 t3 0.350 0.270 0.344
50 t3 0.634 0.502 0.574
100 t3 0.866 0.748 0.820

5.2 Distribución alternativa: Exponencial

resultados_exp <- do.call(rbind, lapply(tamanos, simular_potencia,
                                         B = 500, distribucion = "exp"))
kable(resultados_exp, caption = "Potencia estimada – alternativa: Exponencial")
Potencia estimada – alternativa: Exponencial
n distribucion Shapiro_Wilk Lilliefors CVM
5 exp 0.170 0.130 NaN
10 exp 0.460 0.302 0.384
20 exp 0.832 0.584 0.712
50 exp 1.000 0.958 0.994
100 exp 1.000 1.000 1.000

5.3 Gráfico de Potencia vs n

pot_largo <- reshape(resultados_t3,
                     varying   = c("Shapiro_Wilk", "Lilliefors", "CVM"),
                     v.names   = "Potencia",
                     timevar   = "Prueba",
                     times     = c("Shapiro-Wilk", "Lilliefors", "CVM"),
                     direction = "long")

ggplot(pot_largo, aes(x = n, y = Potencia, color = Prueba, group = Prueba)) +
  geom_line(linewidth = 1.3) +
  geom_point(size = 3.5) +
  geom_hline(yintercept = 0.80, linetype = "dashed",
             color = "red", linewidth = 0.9) +
  annotate("text", x = 95, y = 0.83,
           label = "Meta: 80% de potencia", color = "red", size = 4) +
  scale_y_continuous(labels = scales::percent_format(), limits = c(0, 1)) +
  scale_x_continuous(breaks = tamanos) +
  labs(
    title    = "Potencia de Pruebas de Normalidad vs Tamaño de Muestra",
    subtitle = "Alternativa: t con 3 grados de libertad (B = 500 simulaciones)",
    x = "Tamaño de muestra (n)", y = "Potencia estimada", color = "Prueba"
  ) +
  theme_minimal(base_size = 13) +
  theme(legend.position = "bottom")


6. Verificación del Error Tipo I

Cuando los datos sí son normales, cada prueba debe rechazar aproximadamente el α = 5% de las veces. Si rechaza mucho más, hay inflación del error Tipo I.

set.seed(99)
error_tipo1 <- do.call(rbind, lapply(tamanos, simular_potencia,
                                      B = 500, distribucion = "normal"))
kable(
  error_tipo1[, c("n", "Shapiro_Wilk", "Lilliefors", "CVM")],
  caption = "Tasa de rechazo con datos normales (esperado ≈ 0.05)"
)
Tasa de rechazo con datos normales (esperado ≈ 0.05)
n Shapiro_Wilk Lilliefors CVM
5 0.042 0.036 NaN
10 0.034 0.056 0.036
20 0.058 0.038 0.054
50 0.058 0.048 0.062
100 0.040 0.038 0.042

Valores cercanos a 0.05 indican que las pruebas controlan bien el error Tipo I.


7. Resumen

Concepto Descripción
Error Tipo I (α) Rechazar H₀ siendo verdadera (falso positivo). Meta: α = 0.05
Error Tipo II (β) No rechazar H₀ siendo falsa (falso negativo)
Potencia 1 − β. Probabilidad de detectar efecto real. Meta: ≥ 80%
P-valor p < α → rechazar H₀
Shapiro-Wilk shapiro.test() | Más potente para n < 5000
Lilliefors lillie.test() del paquete nortest
Cramér-von Mises cvm.test() del paquete nortest
Bootstrap sample(x, replace=TRUE) repetido B veces → distribución del estadístico