# install.packages(c("nortest", "boot", "ggplot2", "knitr"))
library(nortest)
library(boot)
library(ggplot2)
library(knitr)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) |
El p-valor es la probabilidad de obtener un resultado tan extremo como el observado, suponiendo que H₀ es verdadera.
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-Wilk normality test
##
## data: muestra_normal
## W = 0.98928, p-value = 0.9279
##
## Shapiro-Wilk – 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).
Todas estas pruebas tienen la misma hipótesis:
| 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))
}| 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 ✓ |
| 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 ✓ |
El bootstrap permite estimar la distribución de un estadístico cuando no conocemos la distribución poblacional.
Pasos:
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
##
## Media bootstrap : 44.6749
##
## Error estándar boot: 7.6402
##
## 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)Comparamos la potencia de Shapiro-Wilk, Lilliefors y Cramér-von Mises bajo distintos tamaños de muestra.
Estrategia:
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)
)
}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)")| 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 |
resultados_exp <- do.call(rbind, lapply(tamanos, simular_potencia,
B = 500, distribucion = "exp"))
kable(resultados_exp, caption = "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 |
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")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)"
)| 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.
| 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 |