Cómo usar este notebook

Este documento es un material de estudio guiado. Cada prueba sigue siempre el mismo recorrido, para que aprendas a razonar y no solo a ejecutar una función:

  1. Idea intuitiva: qué pregunta responde la prueba.
  2. Supuestos e hipótesis: cuándo es válida y qué se contrasta.
  3. Estadístico y fórmulas: con la demostración de los resultados principales.
  4. Cálculo paso a paso “a mano” en R: cada fórmula se traduce en una línea de código.
  5. Función automática de R: confirma que el cálculo manual es correcto.
  6. Interpretación y reporte: cómo se escribe la conclusión en un informe.
  7. Ejercicio para practicar.

Instrucciones prácticas

  • Abre este archivo en RStudio. Puedes ejecutar cada bloque de código (las zonas grises) con el botón verde de ejecución (triángulo) o con Ctrl + Shift + Enter, o generar el informe completo con Knit.
  • Solo se usa R base: no necesitas instalar paquetes, salvo rmarkdown para el botón Knit.
  • La base del taller ya viene incluida en este archivo. Al compilar se guarda una copia llamada encuesta_salud.csv en tu carpeta.
  • En todo el documento usaremos un nivel de significancia \(\alpha = 0.05\).
Sesión Tema Funciones de R
9.1 Prueba de los signos y prueba de Wilcoxon binom.test(), wilcox.test(paired = TRUE)
9.2 Prueba U de Mann-Whitney wilcox.test()
10.1 Chi-cuadrado de independencia y prueba exacta de Fisher chisq.test(), fisher.test()
10.2 Taller con una encuesta de salud pública todas las anteriores
11.1 Limitaciones en muestras pequeñas simulación de potencia
12.1–12.2 Evaluación parcial y solucionario todas las anteriores

1 Ideas previas que necesitamos

1.1 ¿Qué significa “no paramétrico”?

Una prueba paramétrica (por ejemplo, la prueba \(t\)) supone que los datos provienen de una familia de distribuciones conocida, normalmente la normal, y contrasta sus parámetros (\(\mu\), \(\sigma\)). Una prueba no paramétrica hace supuestos mucho más débiles: por lo general solo que las observaciones son independientes y provienen de una distribución continua.

¿Cómo lo logra? Trabajando con los signos o con los rangos (el orden) de los datos en lugar de sus valores. La distribución de los rangos bajo \(H_0\) no depende de la forma de la distribución original. Por eso estas pruebas se llaman también de distribución libre.

Cuándo conviene usarlas:

  • Variables asimétricas con valores extremos: ingresos, salarios, gasto, tiempos de espera.
  • Datos ordinales: escalas de satisfacción o Likert.
  • Muestras pequeñas, en las que no se puede verificar la normalidad.
  • Variables categóricas, organizadas en tablas de contingencia.

1.2 Los rangos y el tratamiento de los empates

El rango de una observación es su posición cuando los datos se ordenan de menor a mayor. Si dos o más valores son iguales (un empate), cada uno recibe el promedio de las posiciones que ocupan. Veámoslo en R:

x <- c(40, 60, 20, 60, 90, 60)
data.frame(valor = x, rango = rank(x))
valor rango
40 2
60 4
20 1
60 4
90 6
60 4

Los tres valores 60 ocupan las posiciones 3, 4 y 5. Por eso cada uno recibe el rango \((3+4+5)/3 = 4\). Observa una propiedad útil: la suma de los rangos de \(n\) datos siempre es

\[1 + 2 + \cdots + n = \frac{n(n+1)}{2}.\]

cat("Suma de los rangos   :", sum(rank(x)), "\n")
Suma de los rangos   : 21 
cat("Fórmula n(n + 1) / 2 :", length(x) * (length(x) + 1) / 2, "\n")
Fórmula n(n + 1) / 2 : 21 

1.3 El p-valor y el tamaño del efecto

  • El p-valor es la probabilidad, suponiendo que \(H_0\) es cierta, de obtener un resultado tan extremo o más que el observado. Si \(p < \alpha\), rechazamos \(H_0\).
  • El p-valor no mide la magnitud del efecto. Con muestras grandes, una diferencia mínima puede ser “significativa”; con muestras pequeñas, una diferencia importante puede no serlo.
  • Por eso siempre reportaremos también un tamaño del efecto y un estimador de la diferencia (el estimador de Hodges-Lehmann).

1.4 Funciones auxiliares

Para que las salidas sean ordenadas y fáciles de leer, usaremos tres funciones de presentación:

  • ver(): muestra varios resultados con nombre, uno por línea y alineados.
  • mostrar(): imprime una tabla redondeada y sin la numeración de filas.
  • informe(): resume en español cualquier prueba de R (nombre de la prueba, hipótesis alternativa, estadístico, p-valor y decisión).

R no tiene una función directa para la prueba de los signos ni para el estimador de Hodges-Lehmann. Las definimos una sola vez aquí y las usaremos en todo el documento.

# ---------------------------------------------------------------
# 1) Funciones para mostrar resultados de forma ordenada
# ---------------------------------------------------------------

# fmt(): da formato a un número. Los p-valores muy pequeños se muestran en
# notación científica; los enteros, sin decimales.
fmt <- function(v, dec = 4) {
  if (is.null(v) || length(v) == 0 || is.na(v)) return("--")
  if (!is.numeric(v)) return(as.character(v))
  if (v != 0 && abs(v) < 0.001) return(formatC(v, format = "e", digits = 2))
  if (abs(v - round(v)) < 1e-9) return(format(round(v), big.mark = ""))
  as.character(round(v, dec))
}

# ver(): muestra varios valores con nombre, uno por línea y alineados.
#   Ejemplo: ver("Media" = 10.5, "Mediana" = 9)
ver <- function(..., dec = 4) {
  x <- list(...)
  etiquetas <- format(names(x))
  valores   <- vapply(x, fmt, character(1), dec = dec)
  cat(paste0("  ", etiquetas, " : ", valores), sep = "\n")
}

# mostrar(): imprime un data.frame redondeado y sin numeración de filas.
mostrar <- function(df, dec = 3) {
  df <- as.data.frame(df)
  num <- vapply(df, is.numeric, logical(1))
  df[num] <- lapply(df[num], round, dec)
  print(df, row.names = FALSE)
}

# informe(): resume en español el resultado de cualquier prueba de R
# (binom.test, wilcox.test, chisq.test, fisher.test, shapiro.test).
informe <- function(prueba, alpha = 0.05, extra = list()) {
  m <- prueba$method
  nombre <- if (grepl("binomial", m)) "Prueba de los signos (binomial exacta)"
    else if (grepl("signed rank", m)) paste("Wilcoxon de rangos con signo",
            ifelse(grepl("exact", m), "(exacta)", "(aprox. normal)"))
    else if (grepl("rank sum", m)) paste("U de Mann-Whitney",
            ifelse(grepl("exact", m), "(exacta)", "(aprox. normal)"))
    else if (grepl("Yates", m)) "Chi-cuadrado (corrección de Yates)"
    else if (grepl("Chi", m)) "Chi-cuadrado de independencia"
    else if (grepl("Fisher", m)) "Prueba exacta de Fisher"
    else if (grepl("Shapiro", m)) "Shapiro-Wilk (normalidad)"
    else m
  alternativa <- switch(ifelse(is.null(prueba$alternative), "ninguna", prueba$alternative),
    greater = "unilateral, mayor (cola derecha)",
    less = "unilateral, menor (cola izquierda)",
    two.sided = "bilateral", "no aplica (cola derecha)")
  est <- prueba$statistic
  nom_est <- if (is.null(est)) "" else switch(names(est),
    "number of successes" = "B (signos +)", "X-squared" = "Chi2", names(est))
  filas <- list("Prueba" = nombre, "Hipótesis alternativa" = alternativa)
  if (!is.null(est)) filas[["Estadístico"]] <- paste(nom_est, "=", fmt(unname(est)))
  if (!is.null(prueba$parameter) && !grepl("binomial", m))
    filas[["Grados de libertad"]] <- fmt(unname(prueba$parameter))
  filas[["p-valor"]] <- fmt(prueba$p.value)
  filas[["Decisión (alfa = 0.05)"]] <- ifelse(prueba$p.value < alpha,
    "Se rechaza H0", "No se rechaza H0")
  for (k in names(extra)) filas[[k]] <- fmt(extra[[k]])
  linea <- strrep("-", 62)
  cat(linea, "\n")
  cat(paste0("  ", format(names(filas)), " : ", unlist(filas)), sep = "\n")
  cat(linea, "\n")
}

# ---------------------------------------------------------------
# 2) Funciones estadísticas que R no trae directamente
# ---------------------------------------------------------------

# Estimador de Hodges-Lehmann para una muestra (o para diferencias pareadas):
# mediana de todos los promedios de Walsh (d_i + d_j)/2 con i <= j.
hl_1m <- function(d) {
  w <- outer(d, d, "+") / 2
  median(w[upper.tri(w, diag = TRUE)])
}

# Estimador de Hodges-Lehmann del desplazamiento entre dos muestras:
# mediana de todas las diferencias x_i - y_j.
hl_2m <- function(x, y) median(outer(x, y, "-"))

# Prueba de los signos para la mediana: cuenta los signos + y -, descarta los
# empates con m0 y aplica una prueba binomial con p = 1/2.
prueba_signos <- function(x, m0 = 0, alternative = "two.sided") {
  d <- x - m0
  pos <- sum(d > 0); neg <- sum(d < 0)
  binom.test(pos, pos + neg, p = 0.5, alternative = alternative)
}

2 Sesión 9.1 — Prueba de los signos y prueba de Wilcoxon

2.1 El caso: ingresos antes y después de una intervención

Un programa municipal de capacitación productiva se aplicó a 12 hogares. Se registró el ingreso mensual (S/) de cada hogar antes y después de la intervención. La pregunta es: ¿aumentó el ingreso típico de los hogares?

Los datos son pareados: cada hogar se mide dos veces. Por eso no comparamos dos grupos, sino que analizamos la diferencia de cada hogar:

\[D_i = \text{post}_i - \text{pre}_i, \qquad i = 1, \dots, 12.\]

pre  <- c(820, 950, 1100, 780, 1250, 900, 1010, 870, 1500, 990, 1120, 760)
post <- c(900, 1010, 1080, 850, 1400, 960, 1150, 870, 1620, 1050, 1180, 800)
d <- post - pre                              # diferencia de cada hogar
mostrar(data.frame(hogar = 1:12, pre, post, d, signo = sign(d)))
 hogar  pre post   d signo
     1  820  900  80     1
     2  950 1010  60     1
     3 1100 1080 -20    -1
     4  780  850  70     1
     5 1250 1400 150     1
     6  900  960  60     1
     7 1010 1150 140     1
     8  870  870   0     0
     9 1500 1620 120     1
    10  990 1050  60     1
    11 1120 1180  60     1
    12  760  800  40     1
ver("Mediana antes"        = median(pre),
    "Mediana después"      = median(post),
    "Mediana de las dif."  = median(d))
  Mediana antes       : 970
  Mediana después     : 1030
  Mediana de las dif. : 60

Primera lectura: casi todas las diferencias son positivas, una es negativa (hogar 3) y una es cero (hogar 8). Además hay empates en las diferencias: cuatro hogares aumentaron exactamente S/ 60. Ambas situaciones son frecuentes en datos reales y veremos cómo se tratan.

2.2 Prueba de los signos

2.2.1 Idea intuitiva

Si el programa no tuviera efecto, cada hogar tendría la misma probabilidad de aumentar o de disminuir su ingreso, como al lanzar una moneda. Si observamos “demasiados” aumentos para que sean obra del azar, concluimos que el ingreso mediano aumentó.

2.2.2 Supuestos e hipótesis

  • Las diferencias \(D_1, \dots, D_n\) son independientes (hogares distintos).
  • Provienen de una distribución continua con mediana \(M\).
  • No se requiere normalidad ni simetría.

\[H_0: M = 0 \qquad \text{frente a} \qquad H_1: M > 0 \quad (\text{el ingreso aumentó}).\]

2.2.3 El estadístico y su distribución (demostración)

Sea \(B\) el número de diferencias positivas entre las \(n^*\) diferencias no nulas.

Resultado. Bajo \(H_0\), \(B \sim \text{Binomial}\left(n^*, \tfrac12\right)\).

Demostración. Si la mediana de \(D\) es 0, entonces por definición de mediana (y porque \(D\) es continua): \[P(D_i > 0) = P(D_i < 0) = \tfrac12 .\] Definamos \(I_i = 1\) si \(D_i > 0\) e \(I_i = 0\) si \(D_i < 0\). Cada \(I_i\) es una variable de Bernoulli con \(p = \tfrac12\), y las \(I_i\) son independientes porque las \(D_i\) lo son. Entonces \(B = \sum_{i=1}^{n^*} I_i\) es una suma de \(n^*\) Bernoulli independientes con la misma \(p\), es decir, una binomial: \(B \sim \text{Binomial}(n^*, \tfrac12)\). \(\blacksquare\)

¿Y los ceros? Una diferencia igual a cero no aporta información sobre la dirección del cambio. Por eso se descartan y se trabaja con las \(n^*\) diferencias restantes.

P-valor (alternativa “mayor”). Es la probabilidad de observar \(b_{\text{obs}}\) o más signos positivos: \[p = P(B \ge b_{\text{obs}}) = \sum_{k = b_{\text{obs}}}^{n^*} \binom{n^*}{k}\left(\frac12\right)^{n^*}.\]

Muestras grandes (\(n^* > 25\)). Como \(E(B) = n^*/2\) y \(\mathrm{Var}(B) = n^*/4\): \[Z = \frac{B - n^*/2}{\sqrt{n^*}/2} \approx N(0,1).\]

2.2.4 Cálculo paso a paso

# Paso 1: contar signos (los ceros se descartan)
b     <- sum(d > 0)        # signos +
neg   <- sum(d < 0)        # signos -
n_est <- b + neg           # n* = diferencias no nulas
ver("Signos positivos (B)"    = b,
    "Signos negativos"        = neg,
    "Ceros (se descartan)"    = sum(d == 0),
    "n* (diferencias útiles)" = n_est)
  Signos positivos (B)    : 10
  Signos negativos        : 1
  Ceros (se descartan)    : 1
  n* (diferencias útiles) : 11
# Paso 2: p-valor exacto con la fórmula binomial: P(B >= 10) con n* = 11
p_manual  <- sum(choose(n_est, b:n_est) * 0.5^n_est)
p_dbinom  <- sum(dbinom(b:n_est, size = n_est, prob = 0.5))   # lo mismo con dbinom()
ver("p-valor (fórmula)"  = p_manual,
    "p-valor (dbinom)"   = p_dbinom)
  p-valor (fórmula) : 0.0059
  p-valor (dbinom)  : 0.0059

Es decir: \[p = \frac{\binom{11}{10} + \binom{11}{11}}{2^{11}} = \frac{11 + 1}{2048} = \frac{12}{2048} \approx 0.00586.\]

# Distribución de B bajo H0 y región del p-valor
k <- 0:n_est
barplot(dbinom(k, n_est, 0.5), names.arg = k,
        col = ifelse(k >= b, "#80162a", "grey75"), border = NA,
        main = "Distribución de B bajo H0: Binomial(11; 0.5)",
        xlab = "Número de signos positivos (B)", ylab = "Probabilidad")
legend("topleft", fill = "#80162a", legend = "Región del p-valor: B >= 10", bty = "n")

2.2.5 Confirmación con la función de R

res_signos <- prueba_signos(d, alternative = "greater")
informe(res_signos, extra = list("Proporción de signos +" = unname(res_signos$estimate)))
-------------------------------------------------------------- 
  Prueba                 : Prueba de los signos (binomial exacta)
  Hipótesis alternativa  : unilateral, mayor (cola derecha)
  Estadístico            : B (signos +) = 10
  p-valor                : 0.0059
  Decisión (alfa = 0.05) : Se rechaza H0
  Proporción de signos + : 0.9091
-------------------------------------------------------------- 

Decisión: \(p = 0.0059 < 0.05\), así que rechazamos \(H_0\). Hay evidencia de que la mediana del ingreso aumentó.

Limitación: la prueba de los signos solo usa la dirección del cambio. Un hogar que ganó S/ 150 más cuenta igual que uno que ganó S/ 40 más. La prueba de Wilcoxon aprovecha también la magnitud.

2.3 Prueba de Wilcoxon de rangos con signo

2.3.1 Idea intuitiva

Ordenamos las diferencias por su tamaño (valor absoluto). Si el programa no tuviera efecto, las diferencias grandes serían positivas o negativas con igual probabilidad. Si las diferencias grandes son casi todas positivas, eso es evidencia de que el ingreso aumentó.

2.3.2 Supuestos e hipótesis

  • Diferencias independientes, de una distribución continua y simétrica alrededor de su mediana \(M\).
  • La simetría es el supuesto adicional respecto de la prueba de los signos.

\[H_0: M = 0 \qquad H_1: M > 0.\]

2.3.3 Procedimiento

  1. Calcular \(D_i\) y descartar los \(D_i = 0\); quedan \(n\) diferencias.
  2. Ordenar los \(|D_i|\) y asignar rangos \(1, \dots, n\) (rangos promedio si hay empates).
  3. Calcular \(W^+ =\) suma de los rangos de las diferencias positivas y \(W^- =\) suma de los rangos de las negativas. Siempre se cumple \(W^+ + W^- = \frac{n(n+1)}{2}\).

2.3.4 Media y varianza de \(W^+\) bajo \(H_0\) (demostración)

Sin empates, los rangos son \(1, 2, \dots, n\). Definamos \(I_i = 1\) si la diferencia con rango \(i\) es positiva y \(I_i = 0\) si es negativa. Entonces \[W^+ = \sum_{i=1}^{n} i \cdot I_i .\] Bajo \(H_0\) y por la simetría, cada signo es positivo con probabilidad \(\tfrac12\), de forma independiente de su rango. Por tanto \(E(I_i) = \tfrac12\) y \(\mathrm{Var}(I_i) = \tfrac14\), y:

\[E(W^+) = \sum_{i=1}^{n} i \cdot \frac12 = \frac12 \cdot \frac{n(n+1)}{2} = \frac{n(n+1)}{4},\]

\[\mathrm{Var}(W^+) = \sum_{i=1}^{n} i^2 \cdot \frac14 = \frac14 \cdot \frac{n(n+1)(2n+1)}{6} = \frac{n(n+1)(2n+1)}{24}. \qquad \blacksquare\]

Aquí usamos las sumas conocidas \(\sum i = \frac{n(n+1)}{2}\) y \(\sum i^2 = \frac{n(n+1)(2n+1)}{6}\).

Corrección por empates. Si hay grupos de valores empatados de tamaños \(t_1, t_2, \dots\), la varianza disminuye: \[\mathrm{Var}(W^+) = \frac{n(n+1)(2n+1)}{24} - \frac{\sum_j (t_j^3 - t_j)}{48}.\]

Estadístico estandarizado (con corrección por continuidad de \(0.5\)): \[Z = \frac{W^+ - E(W^+) - 0.5}{\sqrt{\mathrm{Var}(W^+)}} \approx N(0,1).\]

2.3.5 Cálculo paso a paso

# Paso 1: descartar las diferencias nulas
dz <- d[d != 0]
n  <- length(dz)

# Paso 2: rangos de los valores absolutos (rango promedio en los empates)
rangos <- rank(abs(dz))
tabla_w <- data.frame(d = dz, abs_d = abs(dz), rango = rangos,
                      signo = ifelse(dz > 0, "+", "-"))
mostrar(tabla_w[order(tabla_w$abs_d), ])
   d abs_d rango signo
 -20    20   1.0     -
  40    40   2.0     +
  60    60   4.5     +
  60    60   4.5     +
  60    60   4.5     +
  60    60   4.5     +
  70    70   7.0     +
  80    80   8.0     +
 120   120   9.0     +
 140   140  10.0     +
 150   150  11.0     +
# Paso 3: sumas de rangos
W_mas   <- sum(rangos[dz > 0])
W_menos <- sum(rangos[dz < 0])
ver("n (sin ceros)"            = n,
    "W+ (rangos positivos)"    = W_mas,
    "W- (rangos negativos)"    = W_menos,
    "Comprobación n(n+1)/2"    = n * (n + 1) / 2)
  n (sin ceros)         : 11
  W+ (rangos positivos) : 65
  W- (rangos negativos) : 1
  Comprobación n(n+1)/2 : 66

Los cuatro valores \(|D| = 60\) ocupan las posiciones 3 a 6, así que cada uno recibe el rango \((3+4+5+6)/4 = 4.5\). La única diferencia negativa (\(-20\)) tiene el rango más pequeño: el único hogar que perdió ingreso fue el que menos cambió.

# Paso 4: media y varianza bajo H0, con corrección por empates
E_W <- n * (n + 1) / 4
t_j <- table(abs(dz))                  # tamaños de los grupos de empates
V_W <- n * (n + 1) * (2 * n + 1) / 24 - sum(t_j^3 - t_j) / 48

# Paso 5: estadístico Z y p-valor unilateral (cola derecha)
Z <- (W_mas - E_W - 0.5) / sqrt(V_W)
ver("E(W+)"                 = E_W,
    "Var(W+) sin empates"   = n * (n + 1) * (2 * n + 1) / 24,
    "Var(W+) con empates"   = V_W,
    "Z"                     = Z,
    "p-valor = P(Z >= z)"   = pnorm(Z, lower.tail = FALSE))
  E(W+)               : 33
  Var(W+) sin empates : 126.5
  Var(W+) con empates : 125.25
  Z                   : 2.8146
  p-valor = P(Z >= z) : 0.0024

Sustituyendo los valores: \[E(W^+) = \frac{11 \cdot 12}{4} = 33, \qquad \mathrm{Var}(W^+) = \frac{11 \cdot 12 \cdot 23}{24} - \frac{4^3 - 4}{48} = 126.5 - 1.25 = 125.25,\] \[Z = \frac{65 - 33 - 0.5}{\sqrt{125.25}} = 2.815, \qquad p = P(Z \ge 2.815) = 0.00244.\]

2.3.6 Confirmación con la función de R

Como hay ceros y empates, R no puede usar la distribución exacta y aplica la aproximación normal que acabamos de calcular:

res_w <- wilcox.test(post, pre, paired = TRUE, alternative = "greater",
                     exact = FALSE, correct = TRUE)
informe(res_w)
-------------------------------------------------------------- 
  Prueba                 : Wilcoxon de rangos con signo (aprox. normal)
  Hipótesis alternativa  : unilateral, mayor (cola derecha)
  Estadístico            : V = 65
  p-valor                : 0.0024
  Decisión (alfa = 0.05) : Se rechaza H0
-------------------------------------------------------------- 

R llama \(V\) al estadístico \(W^+\). Obtuvimos el mismo valor: \(V = 65\) y \(p = 0.00244\). La función informe() resume en español lo que imprime wilcox.test(); si quieres ver la salida original de R, escribe print(res_w).

Nota sobre la distribución exacta. Sin empates, para \(n\) pequeño se usa la distribución exacta de \(W^+\), que se obtiene contando los \(2^n\) patrones de signos igualmente probables. Por ejemplo, con \(n = 11\) y sin empates, solo 2 de los 2048 patrones dan \(W^+ \geq 65\):

ver("P(W+ >= 65), n = 11" = psignrank(64, n = 11, lower.tail = FALSE),
    "2 / 2048"             = 2 / 2048)
  P(W+ >= 65), n = 11 : 9.77e-04
  2 / 2048            : 9.77e-04

2.3.7 Estimación y tamaño del efecto

Estimador de Hodges-Lehmann. Se calcula la mediana de los promedios de Walsh \(\frac{D_i + D_j}{2}\) para todos los pares \(i \le j\). Estima el cambio típico y es robusto frente a valores extremos:

HL <- hl_1m(dz)
r  <- Z / sqrt(n)            # tamaño del efecto
ver("Hodges-Lehmann (S/)"  = HL,
    "Tamaño del efecto r"  = r)
  Hodges-Lehmann (S/) : 70
  Tamaño del efecto r : 0.8486

Tamaño del efecto \(r = Z/\sqrt{n}\). Como referencia (Cohen): \(0.1\) es pequeño, \(0.3\) mediano y \(0.5\) grande. Aquí \(r = 0.85\): el efecto es grande.

2.3.8 Visualización

par(mfrow = c(1, 2), mar = c(4, 4, 2.5, 1))
matplot(rbind(1, 2), rbind(pre, post), type = "b", pch = 19, lty = 1,
        col = ifelse(post > pre, "darkgreen", ifelse(post < pre, "firebrick", "grey50")),
        xaxt = "n", xlab = "", ylab = "Ingreso (S/)", main = "Ingreso por hogar")
axis(1, at = 1:2, labels = c("Antes", "Después"))
plot(sort(d), type = "h", lwd = 3, col = "#1856a0", ylab = "S/",
     xlab = "Hogares (ordenados)", main = "Diferencias post - pre"); abline(h = 0)

2.3.9 Conclusión e informe

Prueba de los signos Prueba de Wilcoxon
Usa solo la dirección dirección y magnitud
Supuesto adicional ninguno simetría de \(D\)
Estadístico \(B = 10\) de \(n^* = 11\) \(W^+ = 65\)
p-valor (unilateral) 0.0059 0.0024

Redacción sugerida: “El ingreso mensual de los hogares aumentó tras la intervención (mediana de las diferencias = S/ 60). La prueba de Wilcoxon de rangos con signo fue significativa (\(W^+ = 65\), \(p = 0.002\), \(r = 0.85\)), con un aumento típico estimado de S/ 70 (Hodges-Lehmann). La prueba de los signos llevó a la misma conclusión (\(p = 0.006\)).”

Cuidado con la causalidad. Sin un grupo de control no podemos atribuir el aumento al programa: el ingreso pudo subir por otras razones, como la temporada o la economía local.

2.3.10 Ejercicio 9.1

Con los datos de la evaluación (caso 1, sección 7), calcula a mano \(W^+\), \(E(W^+)\) y \(\mathrm{Var}(W^+)\) con la corrección por empates, y verifica tu resultado con wilcox.test().

3 Sesión 9.2 — Prueba U de Mann-Whitney

3.1 El caso: diferencias salariales por género

Se registró el salario mensual (S/) de 10 hombres y 9 mujeres que ocupan el mismo puesto en una empresa. ¿Existen diferencias salariales por género?

Ahora las muestras son independientes: son personas distintas y no hay emparejamiento.

hombres <- c(1850, 2100, 1720, 2600, 1980, 2300, 1650, 2450, 2050, 3100)
mujeres <- c(1600, 1750, 1500, 1900, 2020, 1680, 1450, 2200, 1580)
n1 <- length(hombres); n2 <- length(mujeres); N <- n1 + n2
ver("n1 (hombres)"       = n1,
    "n2 (mujeres)"       = n2,
    "Mediana hombres"    = median(hombres),
    "Mediana mujeres"    = median(mujeres))
  n1 (hombres)    : 10
  n2 (mujeres)    : 9
  Mediana hombres : 2075
  Mediana mujeres : 1680

3.2 Idea intuitiva

Juntamos los 19 salarios, los ordenamos y anotamos de qué grupo es cada uno. Si no hubiera diferencia entre grupos, los rangos de hombres y mujeres estarían bien mezclados. Si los hombres ocupan sistemáticamente los rangos altos, hay evidencia de que tienden a ganar más.

3.3 Supuestos e hipótesis

  • Dos muestras independientes entre sí, con observaciones independientes dentro de cada una.
  • Variable al menos ordinal, de distribución continua.

\[H_0: \text{las dos distribuciones son iguales} \;\; \big(P(X > Y) = \tfrac12\big)\] \[H_1: \text{una tiende a dar valores mayores que la otra} \;\; \big(P(X > Y) \neq \tfrac12\big)\]

Importante: Mann-Whitney contrasta si \(P(X > Y) = 1/2\). Solo equivale a comparar medianas si ambas distribuciones tienen la misma forma y difieren solo en su ubicación.

3.4 El estadístico U

  1. Ordenar las \(N = n_1 + n_2\) observaciones juntas y asignar rangos.
  2. \(R_1 =\) suma de los rangos del grupo 1; \(R_2 =\) suma de los rangos del grupo 2.
  3. Calcular \[U_1 = R_1 - \frac{n_1(n_1+1)}{2}, \qquad U_2 = n_1 n_2 - U_1 .\]

Interpretación de \(U_1\) (demostración). \(U_1\) es el número de pares \((X_i, Y_j)\) en los que el valor del grupo 1 supera al del grupo 2: \[U_1 = \#\{(i,j): X_i > Y_j\}.\] Demostración. Ordenemos el grupo 1: \(X_{(1)} < X_{(2)} < \cdots < X_{(n_1)}\). El rango de \(X_{(i)}\) en la muestra combinada es su posición: hay \(i - 1\) valores del grupo 1 por debajo de él, más los valores del grupo 2 menores que él. Por tanto \[\text{rango}(X_{(i)}) = i + \#\{j: Y_j < X_{(i)}\}.\] Sumando sobre \(i = 1, \dots, n_1\): \[R_1 = \sum_{i=1}^{n_1} i + \sum_{i=1}^{n_1} \#\{j: Y_j < X_{(i)}\} = \frac{n_1(n_1+1)}{2} + U_1. \qquad \blacksquare\]

Por eso \(\frac{U_1}{n_1 n_2}\) estima \(P(X > Y)\), la probabilidad de que un hombre elegido al azar gane más que una mujer elegida al azar.

Distribución bajo \(H_0\). Todas las asignaciones de rangos a los grupos son igualmente probables. Se demuestra que \[E(U) = \frac{n_1 n_2}{2}, \qquad \mathrm{Var}(U) = \frac{n_1 n_2 (N+1)}{12} \quad (\text{sin empates}),\] y para muestras grandes \(Z = \dfrac{U - E(U)}{\sqrt{\mathrm{Var}(U)}} \approx N(0,1)\). Para muestras pequeñas y sin empates se usa la distribución exacta (función pwilcox() en R).

3.5 Cálculo paso a paso

# Paso 1: rangos de la muestra combinada
todos <- c(hombres, mujeres)
grupo <- rep(c("Hombre", "Mujer"), c(n1, n2))
rg    <- rank(todos)
tabla_mw <- data.frame(salario = todos, grupo, rango = rg)
mostrar(tabla_mw[order(tabla_mw$rango), ])
 salario  grupo rango
    1450  Mujer     1
    1500  Mujer     2
    1580  Mujer     3
    1600  Mujer     4
    1650 Hombre     5
    1680  Mujer     6
    1720 Hombre     7
    1750  Mujer     8
    1850 Hombre     9
    1900  Mujer    10
    1980 Hombre    11
    2020  Mujer    12
    2050 Hombre    13
    2100 Hombre    14
    2200  Mujer    15
    2300 Hombre    16
    2450 Hombre    17
    2600 Hombre    18
    3100 Hombre    19
# Paso 2: sumas de rangos (comprobación: R1 + R2 = N(N+1)/2)
R1 <- sum(rg[grupo == "Hombre"]); R2 <- sum(rg[grupo == "Mujer"])

# Paso 3: estadísticos U (comprobación: U1 + U2 = n1 * n2)
U1 <- R1 - n1 * (n1 + 1) / 2
U2 <- n1 * n2 - U1

# Paso 4: verificar la interpretación de U1 contando los pares directamente
pares <- sum(outer(hombres, mujeres, ">"))

ver("R1 (hombres)"              = R1,
    "R2 (mujeres)"              = R2,
    "R1 + R2"                   = R1 + R2,
    "N(N + 1) / 2"              = N * (N + 1) / 2,
    "U1"                        = U1,
    "U2"                        = U2,
    "n1 * n2"                   = n1 * n2,
    "Pares con hombre > mujer"  = pares)
  R1 (hombres)             : 129
  R2 (mujeres)             : 61
  R1 + R2                  : 190
  N(N + 1) / 2             : 190
  U1                       : 74
  U2                       : 16
  n1 * n2                  : 90
  Pares con hombre > mujer : 74

El conteo directo confirma la demostración: en 74 de los 90 pares hombre–mujer, el hombre gana más.

# Paso 5: p-valor exacto bilateral = 2 * P(U <= min(U1, U2))
p_exacto <- 2 * pwilcox(min(U1, U2), n1, n2)
# Aproximación normal, solo para comparar
EU <- n1 * n2 / 2; VU <- n1 * n2 * (N + 1) / 12
Zu <- (U1 - EU) / sqrt(VU)
ver("E(U)"                  = EU,
    "Var(U)"                = VU,
    "Z"                     = Zu,
    "p-valor exacto"        = p_exacto,
    "p-valor aprox. normal" = 2 * pnorm(-abs(Zu)))
  E(U)                  : 45
  Var(U)                : 150
  Z                     : 2.3678
  p-valor exacto        : 0.0172
  p-valor aprox. normal : 0.0179

Con estos valores: \[U_1 = 129 - \frac{10 \cdot 11}{2} = 74, \qquad E(U) = \frac{90}{2} = 45,\] \[\mathrm{Var}(U) = \frac{90 \cdot 20}{12} = 150, \qquad Z = \frac{74 - 45}{\sqrt{150}} = 2.37 .\]

3.6 Confirmación con la función de R

res_mw <- wilcox.test(hombres, mujeres, alternative = "two.sided", exact = TRUE)
informe(res_mw)
-------------------------------------------------------------- 
  Prueba                 : U de Mann-Whitney (exacta)
  Hipótesis alternativa  : bilateral
  Estadístico            : W = 74
  p-valor                : 0.0172
  Decisión (alfa = 0.05) : Se rechaza H0
-------------------------------------------------------------- 

En R, el estadístico \(W\) de wilcox.test(x, y) es \(U_1\), la \(U\) del primer grupo.

3.7 Tamaño del efecto y estimación

  • Correlación biserial de rangos: \(r_{rb} = \dfrac{2U_1}{n_1 n_2} - 1 = 2\,\hat P(X>Y) - 1\). Va de \(-1\) a \(1\); el valor 0 indica que no hay diferencia.
  • Desplazamiento de Hodges-Lehmann: mediana de todas las diferencias \(X_i - Y_j\).
ver("P(hombre > mujer)"          = U1 / (n1 * n2),
    "Correlación biserial r_rb"  = 2 * U1 / (n1 * n2) - 1,
    "Hodges-Lehmann (S/)"        = hl_2m(hombres, mujeres))
  P(hombre > mujer)         : 0.8222
  Correlación biserial r_rb : 0.6444
  Hodges-Lehmann (S/)       : 400
boxplot(list(Hombres = hombres, Mujeres = mujeres), col = c("#cfdcf0", "#f3d9de"),
        ylab = "Salario (S/)", main = "Salario mensual por género")
stripchart(list(hombres, mujeres), vertical = TRUE, method = "jitter", add = TRUE, pch = 19)

3.8 Conclusión e informe

Redacción sugerida: “Los salarios de los hombres (Md = 2075) fueron mayores que los de las mujeres (Md = 1680) en el mismo puesto, \(U = 74\), \(p = 0.017\) (prueba exacta). En el 82 % de los pares hombre–mujer el hombre percibe más (\(r_{rb} = 0.64\), efecto grande), con una diferencia típica estimada de S/ 400 mensuales (Hodges-Lehmann).”

Para discutir: comparar a personas del mismo puesto controla parte de las diferencias, pero no otros factores como la antigüedad, las horas trabajadas o la formación.

3.8.1 Ejercicio 9.2

Agrega una mujer con salario de S/ 3200 y repite el análisis. ¿Cambia mucho \(U\)? ¿Y cambiaría mucho la diferencia de medias? Explica por qué las pruebas de rangos son robustas frente a valores extremos.

4 Sesión 10.1 — Prueba Chi-cuadrado de independencia

4.1 El caso: educación y acceso a servicios de salud

En una encuesta a 360 personas se registró el nivel educativo y si tuvieron acceso a servicios de salud cuando lo necesitaron. ¿El acceso depende del nivel educativo?

tabla <- matrix(c(45, 55, 90, 60, 85, 25), nrow = 3, byrow = TRUE,
                dimnames = list(Educacion = c("Primaria", "Secundaria", "Superior"),
                                Acceso = c("Si", "No")))
addmargins(tabla)
            Acceso
Educacion     Si  No Sum
  Primaria    45  55 100
  Secundaria  90  60 150
  Superior    85  25 110
  Sum        220 140 360

4.2 Idea intuitiva

Si el acceso no dependiera de la educación, la proporción con acceso sería la misma en los tres niveles, igual a la proporción global \(220/360 = 61.1\%\). La prueba compara las frecuencias observadas con las que esperaríamos si hubiera independencia.

4.3 Hipótesis y frecuencias esperadas (demostración)

\[H_0: \text{el acceso es independiente del nivel educativo} \qquad H_1: \text{existe asociación}.\]

Dos eventos \(A\) y \(B\) son independientes si \(P(A \cap B) = P(A)\,P(B)\). Estimando cada probabilidad marginal con su proporción muestral, \(\hat P(\text{fila } i) = f_i/n\) y \(\hat P(\text{columna } j) = c_j/n\), la frecuencia esperada en la celda \((i,j)\) bajo \(H_0\) es

\[E_{ij} = n \cdot \frac{f_i}{n} \cdot \frac{c_j}{n} = \frac{f_i \, c_j}{n} = \frac{(\text{total de la fila } i)(\text{total de la columna } j)}{n}.\]

4.4 El estadístico

\[\chi^2 = \sum_{i=1}^{r} \sum_{j=1}^{c} \frac{(O_{ij} - E_{ij})^2}{E_{ij}} \;\sim\; \chi^2_{(r-1)(c-1)} \quad \text{(aproximadamente, bajo } H_0).\]

  • Cada término mide cuánto se aleja la celda de lo esperado, en relación con lo esperado.
  • Grados de libertad: una vez fijados los totales de filas y columnas, solo \((r-1)(c-1)\) celdas pueden variar libremente; las demás quedan determinadas por los totales.
  • Rechazamos \(H_0\) si \(\chi^2\) es grande: la prueba es siempre de cola derecha.

Supuestos: observaciones independientes y frecuencias esperadas suficientemente grandes (\(E_{ij} \ge 5\) en todas las celdas, o al menos en el 80 % y ninguna menor que 1). Si no se cumplen, usamos la prueba exacta de Fisher.

4.5 Cálculo paso a paso

# Paso 1: totales marginales
f_i <- rowSums(tabla); c_j <- colSums(tabla); n <- sum(tabla)

# Paso 2: frecuencias esperadas E_ij = f_i * c_j / n
E <- outer(f_i, c_j) / n
round(E, 2)
              Si    No
Primaria   61.11 38.89
Secundaria 91.67 58.33
Superior   67.22 42.78
ver("¿Todas las esperadas >= 5?" = ifelse(all(E >= 5), "Sí", "No"))
  ¿Todas las esperadas >= 5? : Sí

Por ejemplo, \(E_{11} = \dfrac{100 \times 220}{360} = 61.11\): si hubiera independencia, esperaríamos 61 personas con primaria y con acceso, y observamos 45.

# Paso 3: contribución de cada celda y estadístico
contrib <- (tabla - E)^2 / E
round(contrib, 3)
            Acceso
Educacion       Si    No
  Primaria   4.247 6.675
  Secundaria 0.030 0.048
  Superior   4.702 7.388
chi2 <- sum(contrib)

# Paso 4: grados de libertad, valor crítico y p-valor
gl <- (nrow(tabla) - 1) * (ncol(tabla) - 1)
ver("Chi2 calculado"           = chi2,
    "Grados de libertad"       = gl,
    "Valor crítico (5 %)"      = qchisq(0.95, gl),
    "p-valor"                  = pchisq(chi2, gl, lower.tail = FALSE))
  Chi2 calculado      : 23.0897
  Grados de libertad  : 2
  Valor crítico (5 %) : 5.9915
  p-valor             : 9.69e-06

Decisión: \(\chi^2 = 23.09 > 5.99\) (valor crítico con 2 gl), o equivalentemente \(p < 0.001\). Rechazamos la independencia.

curve(dchisq(x, df = 2), from = 0, to = 26, lwd = 2, col = "#1856a0",
      ylab = "Densidad", xlab = expression(chi^2),
      main = "Distribución chi-cuadrado con 2 gl")
abline(v = qchisq(0.95, 2), lty = 2, col = "grey40")
abline(v = chi2, lwd = 2, col = "#80162a")
legend("topright", bty = "n", lty = c(2, 1), col = c("grey40", "#80162a"),
       legend = c("Valor crítico 5.99", "Valor observado 23.09"))

4.6 Confirmación con la función de R

prueba <- chisq.test(tabla, correct = FALSE)
informe(prueba)
-------------------------------------------------------------- 
  Prueba                 : Chi-cuadrado de independencia
  Hipótesis alternativa  : no aplica (cola derecha)
  Estadístico            : Chi2 = 23.0897
  Grados de libertad     : 2
  p-valor                : 9.69e-06
  Decisión (alfa = 0.05) : Se rechaza H0
-------------------------------------------------------------- 

4.7 ¿Dónde está la asociación y qué tan fuerte es?

Residuos estandarizados ajustados. Indican qué celdas se alejan más de lo esperado: \[r_{ij} = \frac{O_{ij} - E_{ij}}{\sqrt{E_{ij}\left(1 - \frac{f_i}{n}\right)\left(1 - \frac{c_j}{n}\right)}} \approx N(0,1).\] Valores con \(|r_{ij}| > 2\) señalan celdas con más casos (si es positivo) o menos casos (si es negativo) de los esperados.

r_aj <- (tabla - E) / sqrt(E * outer(1 - f_i / n, 1 - c_j / n))
round(r_aj, 3)                    # cálculo manual
            Acceso
Educacion        Si     No
  Primaria   -3.889  3.889
  Secundaria -0.365  0.365
  Superior    4.172 -4.172
round(prueba$stdres, 3)           # R los calcula igual
            Acceso
Educacion        Si     No
  Primaria   -3.889  3.889
  Secundaria -0.365  0.365
  Superior    4.172 -4.172

V de Cramér. Mide la fuerza de la asociación entre 0 (ninguna) y 1 (perfecta): \[V = \sqrt{\frac{\chi^2}{n\,(k-1)}}, \qquad k = \min(r, c).\]

k <- min(dim(tabla))
ver("V de Cramér" = sqrt(chi2 / (n * (k - 1))))
  V de Cramér : 0.2533
round(prop.table(tabla, 1), 3)    # proporciones por fila
            Acceso
Educacion       Si    No
  Primaria   0.450 0.550
  Secundaria 0.600 0.400
  Superior   0.773 0.227
barplot(prop.table(tabla, 1)[, "Si"], col = c("#80162a", "#1856a0", "#2c7a4b"),
        ylim = c(0, 1), ylab = "Proporción con acceso",
        main = "Acceso a servicios de salud por nivel educativo")
abline(h = sum(tabla[, "Si"]) / n, lty = 2)

Redacción sugerida: “El acceso a servicios de salud se asoció con el nivel educativo, \(\chi^2(2, N = 360) = 23.09\), \(p < 0.001\), \(V = 0.25\). El acceso aumentó de 45 % en primaria a 77 % en educación superior. Los residuos ajustados muestran que la asociación proviene de los extremos: primaria por debajo de lo esperado (\(r = -3.89\)) y superior por encima (\(r = 4.17\)).”

4.8 Tablas pequeñas: prueba exacta de Fisher

En un programa piloto con 20 personas se registró si participaron y si mejoraron:

t2 <- matrix(c(7, 2, 3, 8), 2, byrow = TRUE,
             dimnames = list(Programa = c("Si", "No"), Mejora = c("Si", "No")))
addmargins(t2)
        Mejora
Programa Si No Sum
     Si   7  2   9
     No   3  8  11
     Sum 10 10  20
round(outer(rowSums(t2), colSums(t2)) / sum(t2), 2)    # esperadas: todas < 5
    Si  No
Si 4.5 4.5
No 5.5 5.5

Las frecuencias esperadas son menores que 5, así que la aproximación chi-cuadrado no es confiable.

Fundamento de Fisher. Con los totales de filas y columnas fijos, la frecuencia \(a\) de la celda superior izquierda sigue una distribución hipergeométrica bajo \(H_0\): \[P(a) = \frac{\binom{a+b}{a}\binom{c+d}{c}}{\binom{n}{a+c}}.\] El p-valor bilateral suma las probabilidades de todas las tablas tan o menos probables que la observada.

# Valores posibles de a: de 0 a 9 (total de la fila 1).
# m = 10 mejoran, n = 10 no mejoran, k = 9 participan en el programa.
a_pos <- 0:9
prob  <- dhyper(a_pos, m = 10, n = 10, k = 9)
mostrar(data.frame(a = a_pos, probabilidad = prob), dec = 5)
 a probabilidad
 0      0.00006
 1      0.00268
 2      0.03215
 3      0.15004
 4      0.31508
 5      0.31508
 6      0.15004
 7      0.03215
 8      0.00268
 9      0.00006
p_fisher <- sum(prob[prob <= prob[a_pos == 7] * (1 + 1e-7)])
ver("p-valor de Fisher (manual)"   = p_fisher,
    "p-valor de fisher.test()"     = fisher.test(t2)$p.value,
    "Chi-cuadrado (no confiable)"  = chisq.test(t2, correct = FALSE)$p.value)
  p-valor de Fisher (manual)  : 0.0698
  p-valor de fisher.test()    : 0.0698
  Chi-cuadrado (no confiable) : 0.0246

Moraleja: el chi-cuadrado daría \(p = 0.025\) (significativo) y Fisher da \(p = 0.070\) (no significativo). Con muestras pequeñas, la elección de la prueba cambia la conclusión. Por eso siempre se revisan las frecuencias esperadas antes de interpretar.

4.8.1 Ejercicio 10.1

Duplica todas las frecuencias de la tabla t2 y repite ambas pruebas. ¿Qué ocurre con los p-valores? ¿Y con las frecuencias esperadas?

5 Sesión 10.2 — Taller: encuesta de salud pública

5.1 Los datos

Trabajaremos con una encuesta de 240 personas (datos simulados con fines didácticos, con una estructura similar a la de las encuestas de salud). La base viene incluida en este archivo.

# La base viene incluida en este mismo archivo (bloque oculto "base-incluida", al inicio),
# por lo que el notebook funciona sin archivos adicionales.
# Si prefiere leer un CSV desde su computadora, use en su lugar:
#   df <- read.csv(file.choose())
df <- read.csv(text = encuesta_csv)
write.csv(df, "encuesta_salud.csv", row.names = FALSE)   # deja una copia del CSV en la carpeta
ver("Personas (filas)" = nrow(df), "Variables (columnas)" = ncol(df))
  Personas (filas)     : 240
  Variables (columnas) : 10
mostrar(head(df, 6))                                        # primeras 6 filas
 id   sexo   area edad nivel_educ fuma actividad_min  imc pas_pre pas_post
  1  Mujer  Rural   22 Secundaria   No            74 26.0      NA       NA
  2 Hombre  Rural   29   Superior   No           289 23.3      NA       NA
  3  Mujer  Rural   28 Secundaria   Si            92 23.8      NA       NA
  4  Mujer Urbano   38 Secundaria   No            29 26.3      NA       NA
  5  Mujer Urbano   23   Superior   No           175 25.5     141      136
  6 Hombre Urbano   27 Secundaria   No           250 28.3     152      149
Variable Tipo Descripción
sexo, area categórica Mujer / Hombre; Urbano / Rural
edad numérica edad en años (18 a 69)
nivel_educ ordinal Primaria / Secundaria / Superior
fuma categórica Si / No
actividad_min numérica minutos de actividad física por semana
imc numérica índice de masa corporal (kg/m²)
pas_pre, pas_post numérica (pareada) presión arterial sistólica antes y después de un programa (solo 25 participantes)
# Resumen de las variables numéricas
num <- df[, c("edad", "actividad_min", "imc")]
mostrar(data.frame(variable = names(num),
                 minimo   = sapply(num, min),
                 mediana  = sapply(num, median),
                 media    = sapply(num, mean),
                 maximo   = sapply(num, max),
                 desv_est = sapply(num, sd)), dec = 2)
      variable minimo mediana  media maximo desv_est
          edad     18   43.00  42.92   69.0    15.41
 actividad_min      2  130.00 161.43 1392.0   147.93
           imc     21   25.35  25.89   39.4     2.89
# Frecuencias de las variables categóricas
addmargins(table(Area = df$area))
Area
 Rural Urbano    Sum 
    92    148    240 
addmargins(table(Sexo = df$sexo, Fuma = df$fuma))
        Fuma
Sexo      No  Si Sum
  Hombre  93  23 116
  Mujer  108  16 124
  Sum    201  39 240

Metodología del taller. Para cada pregunta seguimos los mismos pasos: (1) identificar el tipo de variable y de diseño; (2) plantear las hipótesis; (3) elegir y justificar la prueba; (4) ejecutarla; (5) interpretar.

5.2 Paso 1. ¿Es razonable suponer normalidad?

La prueba de Shapiro-Wilk contrasta \(H_0\): los datos provienen de una distribución normal. La complementamos con gráficos, porque con muestras grandes la prueba detecta desviaciones mínimas.

normalidad <- do.call(rbind, lapply(split(df$actividad_min, df$area), function(x) {
  sw <- shapiro.test(x)
  data.frame(n = length(x), mediana = median(x), media = mean(x),
             W = unname(sw$statistic), p_valor = sw$p.value)
}))
normalidad$p_valor <- format(normalidad$p_valor, digits = 3, scientific = TRUE)
mostrar(cbind(area = rownames(normalidad), normalidad))
   area   n mediana   media     W  p_valor
  Rural  92   151.5 199.043 0.733 1.24e-11
 Urbano 148   124.0 138.047 0.884 2.13e-09
par(mfrow = c(1, 2), mar = c(4, 4, 2.5, 1))
hist(df$actividad_min, breaks = 25, col = "#cfdcf0", border = "white",
     main = "Actividad física (min/sem)", xlab = "minutos")
abline(v = c(mean(df$actividad_min), median(df$actividad_min)), col = c("#80162a", "#1856a0"), lwd = 2)
legend("topright", bty = "n", col = c("#80162a", "#1856a0"), lwd = 2, legend = c("media", "mediana"))
qqnorm(df$actividad_min, pch = 19, cex = .6, main = "Gráfico Q-Q normal"); qqline(df$actividad_min, col = "#80162a", lwd = 2)

Interpretación: la distribución es muy asimétrica a la derecha (la media supera a la mediana y los puntos se alejan de la recta en el Q-Q). Shapiro-Wilk rechaza la normalidad en ambas áreas (\(p < 0.001\)). Usaremos pruebas basadas en rangos.

5.3 Paso 2. ¿Difiere la actividad física entre áreas? (Mann-Whitney)

  • Diseño: dos grupos independientes (rural y urbano); variable numérica asimétrica.
  • \(H_0\): la distribución de la actividad física es igual en ambas áreas; \(H_1\): es distinta.
rur <- df$actividad_min[df$area == "Rural"]
urb <- df$actividad_min[df$area == "Urbano"]
ver("n rural"         = length(rur),
    "n urbano"        = length(urb),
    "Mediana rural"   = median(rur),
    "Mediana urbano"  = median(urb))
  n rural        : 92
  n urbano       : 148
  Mediana rural  : 151.5
  Mediana urbano : 124
mw  <- wilcox.test(rur, urb, exact = FALSE, correct = TRUE)
U_r <- unname(mw$statistic)
informe(mw, extra = list(
  "P(rural > urbano)"          = U_r / (length(rur) * length(urb)),
  "Correlación biserial r_rb"  = 2 * U_r / (length(rur) * length(urb)) - 1,
  "Hodges-Lehmann (min)"       = hl_2m(rur, urb)))
-------------------------------------------------------------- 
  Prueba                    : U de Mann-Whitney (aprox. normal)
  Hipótesis alternativa     : bilateral
  Estadístico               : W = 7977.5
  p-valor                   : 0.0254
  Decisión (alfa = 0.05)    : Se rechaza H0
  P(rural > urbano)         : 0.5859
  Correlación biserial r_rb : 0.1718
  Hodges-Lehmann (min)      : 29
-------------------------------------------------------------- 

Hay empates y las muestras son grandes, así que R usa la aproximación normal (exact = FALSE).

Interpretación: la población rural realiza más actividad física (\(p = 0.025\)), con una diferencia típica de unos 29 minutos semanales. Sin embargo, el efecto es pequeño (\(r_{rb} = 0.17\)): en el 59 % de los pares rural–urbano, la persona rural se ejercita más.

5.4 Paso 3. ¿Está asociado el tabaquismo con el sexo? (Chi-cuadrado)

  • Diseño: dos variables categóricas; tabla \(2 \times 2\).
  • \(H_0\): el tabaquismo es independiente del sexo.
t <- table(Sexo = df$sexo, Fuma = df$fuma)
addmargins(t)
        Fuma
Sexo      No  Si Sum
  Hombre  93  23 116
  Mujer  108  16 124
  Sum    201  39 240
round(chisq.test(t)$expected, 2)        # esperadas: todas mayores que 5
        Fuma
Sexo         No    Si
  Hombre  97.15 18.85
  Mujer  103.85 20.15
informe(chisq.test(t))                  # con corrección de Yates (por defecto en 2x2)
-------------------------------------------------------------- 
  Prueba                 : Chi-cuadrado (corrección de Yates)
  Hipótesis alternativa  : no aplica (cola derecha)
  Estadístico            : Chi2 = 1.6333
  Grados de libertad     : 1
  p-valor                : 0.2012
  Decisión (alfa = 0.05) : No se rechaza H0
-------------------------------------------------------------- 
ver("p-valor sin corrección" = chisq.test(t, correct = FALSE)$p.value,
    "p-valor de Fisher"      = fisher.test(t)$p.value)
  p-valor sin corrección : 0.1462
  p-valor de Fisher      : 0.1638
round(prop.table(t, 1), 3)              # prevalencia por sexo
        Fuma
Sexo        No    Si
  Hombre 0.802 0.198
  Mujer  0.871 0.129

En tablas \(2 \times 2\), R aplica por defecto la corrección de Yates: \(\chi^2 = \sum \frac{(|O - E| - 0.5)^2}{E}\), que hace la prueba más conservadora.

Interpretación: la prevalencia de tabaquismo es 19.8 % en hombres y 12.9 % en mujeres, pero la diferencia no es significativa (\(p = 0.20\)). Atención: no significativo no significa “no hay diferencia”. Con solo 39 fumadores, la prueba tiene poca potencia para detectar diferencias de esta magnitud.

5.5 Paso 4. ¿Redujo el programa la presión arterial? (Wilcoxon pareado)

  • Diseño: mismas personas medidas antes y después, es decir, datos pareados (\(n = 25\)).
  • \(H_0\): la mediana del cambio (post - pre) es 0; \(H_1\): es menor que 0 (la presión bajó).
pa  <- na.omit(df[, c("pas_pre", "pas_post")])
dif <- pa$pas_post - pa$pas_pre
ver("Participantes"           = nrow(pa),
    "Mediana del cambio"      = median(dif),
    "Cambios negativos"       = sum(dif < 0),
    "Cambios positivos"       = sum(dif > 0),
    "Cambios nulos"           = sum(dif == 0))
  Participantes      : 25
  Mediana del cambio : -7
  Cambios negativos  : 23
  Cambios positivos  : 2
  Cambios nulos      : 0
res_pa <- wilcox.test(pa$pas_post, pa$pas_pre, paired = TRUE, alternative = "less",
                      exact = FALSE, correct = TRUE)
informe(res_pa, extra = list(
  "Hodges-Lehmann (mmHg)"     = hl_1m(dif[dif != 0]),
  "p-valor prueba de signos"  = prueba_signos(dif, alternative = "less")$p.value))
-------------------------------------------------------------- 
  Prueba                   : Wilcoxon de rangos con signo (aprox. normal)
  Hipótesis alternativa    : unilateral, menor (cola izquierda)
  Estadístico              : V = 20.5
  p-valor                  : 6.92e-05
  Decisión (alfa = 0.05)   : Se rechaza H0
  Hodges-Lehmann (mmHg)    : -7
  p-valor prueba de signos : 9.72e-06
-------------------------------------------------------------- 

Interpretación: la presión sistólica disminuyó de forma significativa (\(V = 20.5\), \(p < 0.001\)), con una reducción típica de 7 mmHg. La prueba de los signos coincide.

5.6 Paso 5. ¿La mediana del IMC supera 25? (prueba de los signos, una muestra)

  • Un IMC de 25 kg/m² es el umbral del sobrepeso.
  • \(H_0\): \(M = 25\); \(H_1\): \(M > 25\).
ver("Mediana del IMC"   = median(df$imc),
    "Por encima de 25"  = sum(df$imc > 25),
    "Por debajo de 25"  = sum(df$imc < 25),
    "Iguales a 25"      = sum(df$imc == 25))
  Mediana del IMC  : 25.35
  Por encima de 25 : 129
  Por debajo de 25 : 105
  Iguales a 25     : 6
informe(prueba_signos(df$imc, m0 = 25, alternative = "greater"))
-------------------------------------------------------------- 
  Prueba                 : Prueba de los signos (binomial exacta)
  Hipótesis alternativa  : unilateral, mayor (cola derecha)
  Estadístico            : B (signos +) = 129
  p-valor                : 0.0663
  Decisión (alfa = 0.05) : No se rechaza H0
-------------------------------------------------------------- 

Interpretación: aunque la mediana muestral (25.35) supera ligeramente a 25, la evidencia no es suficiente al 5 % (\(p = 0.066\)).

5.7 Resumen del taller

p_val <- c(shapiro.test(rur)$p.value, mw$p.value, chisq.test(t)$p.value,
           res_pa$p.value, prueba_signos(df$imc, 25, "greater")$p.value)
resumen <- data.frame(
  Pregunta = c("Normalidad", "Actividad por área",
               "Tabaquismo y sexo", "Presión pre/post", "Mediana IMC > 25"),
  Prueba   = c("Shapiro-Wilk", "Mann-Whitney", "Chi2 (Yates)",
               "Wilcoxon pareado", "Signos"),
  p_valor  = vapply(p_val, fmt, character(1)),
  Decision = c("No normal", "Diferencia pequeña", "No rechaza H0",
               "La presión bajó", "No rechaza H0"))
mostrar(resumen)
           Pregunta           Prueba  p_valor           Decision
         Normalidad     Shapiro-Wilk 1.24e-11          No normal
 Actividad por área     Mann-Whitney   0.0254 Diferencia pequeña
  Tabaquismo y sexo     Chi2 (Yates)   0.2012      No rechaza H0
   Presión pre/post Wilcoxon pareado 6.92e-05    La presión bajó
   Mediana IMC > 25           Signos   0.0663      No rechaza H0
par(mfrow = c(1, 3), mar = c(4, 4, 2.5, 1))
boxplot(actividad_min ~ area, data = df, col = c("#f3d9de", "#cfdcf0"),
        main = "Actividad física (min/sem)", xlab = "")
barplot(prop.table(t, 1)[, "Si"], col = c("#1856a0", "#80162a"), main = "Prevalencia de tabaquismo")
hist(dif, breaks = 10, col = "#2c7a4b", border = "white", main = "Cambio en PAS (post - pre)", xlab = "mmHg")
abline(v = 0, lwd = 2)

5.7.1 Ejercicio 10.2

Usando la base, contrasta si el IMC difiere entre fumadores y no fumadores, y si el nivel educativo se asocia con el área. Para cada caso, justifica la prueba elegida.

6 Sesión 11.1 — Limitaciones en muestras pequeñas

6.1 El p-valor mínimo alcanzable

Una prueba exacta solo puede tomar un número finito de valores. En la prueba de los signos (y en la de Wilcoxon), el resultado más extremo posible es que todos los signos sean iguales, y su probabilidad bilateral es \[p_{\min} = 2 \cdot \left(\tfrac12\right)^n .\] Con \(n \le 5\) se tiene \(p_{\min} \ge 0.0625\): ningún resultado puede ser significativo al 5 %, por grande que sea el efecto.

# Signos o Wilcoxon: p mínimo bilateral = 2 * (1/2)^n
mostrar(data.frame(n = 3:8, p_min_bilateral = 2 * 0.5^(3:8)), dec = 4)
 n p_min_bilateral
 3          0.2500
 4          0.1250
 5          0.0625
 6          0.0312
 7          0.0156
 8          0.0078
# Mann-Whitney con n1 = n2 = m: p mínimo bilateral = 2 / C(2m, m)
mostrar(data.frame(n_por_grupo = 2:4, p_min_bilateral = 2 / choose(2 * (2:4), 2:4)), dec = 4)
 n_por_grupo p_min_bilateral
           2          0.3333
           3          0.1000
           4          0.0286

Consecuencia ética: diseñar un estudio con 5 pares y concluir “el programa no tiene efecto” es un error metodológico, no un hallazgo.

6.2 Potencia por simulación

La potencia es la probabilidad de rechazar \(H_0\) cuando es falsa. La estimamos simulando muchas muestras con un efecto real (desplazamiento de 0.5) y contando cuántas veces se rechaza.

set.seed(123)
potencia <- function(n, rdist, delta = 0.5, B = 4000) {
  rech <- replicate(B, {
    x <- rdist(n) + delta                       # muestra con efecto real
    c(t = t.test(x)$p.value < 0.05,
      w = suppressWarnings(wilcox.test(x)$p.value) < 0.05)
  })
  rowMeans(rech)                                # proporción de rechazos
}
res <- expand.grid(n = c(8, 15, 30), dist = c("Normal", "t con 3 gl"), stringsAsFactors = FALSE)
pot <- t(mapply(function(n, dist)
  potencia(n, if (dist == "Normal") rnorm else function(k) rt(k, df = 3)), res$n, res$dist))
mostrar(data.frame(n = res$n, distribucion = res$dist,
                 potencia_t = pot[, "t"], potencia_wilcoxon = pot[, "w"]))
  n distribucion potencia_t potencia_wilcoxon
  8       Normal      0.230             0.185
 15       Normal      0.446             0.422
 30       Normal      0.756             0.743
  8   t con 3 gl      0.156             0.152
 15   t con 3 gl      0.252             0.286
 30   t con 3 gl      0.415             0.536

Lectura:

  • Con datos normales, Wilcoxon pierde muy poca potencia frente a \(t\) (su eficiencia relativa es \(3/\pi \approx 0.955\)).
  • Con datos de colas pesadas (\(t\) con 3 gl, parecidos a ingresos con valores extremos), Wilcoxon es más potente que \(t\).
  • Con \(n = 8\), la potencia es menor que 25 %: tres de cada cuatro efectos reales pasarían inadvertidos.

6.3 Preguntas para el debate

  1. El caso 9.1 tiene 12 hogares. ¿Qué podría afirmar el municipio en su informe y qué no?
  2. En el taller, el tabaquismo no se asoció con el sexo. ¿Debe concluirse que no hay diferencia?
  3. Con datos de solo 6 comunidades, ¿es ético publicar un ranking de comunidades?
  4. ¿Cuándo es preferible un análisis descriptivo honesto a una prueba de hipótesis?

7 Sesiones 12.1 y 12.2 — Evaluación parcial y solucionario

Para cada caso: (a) plantea \(H_0\) y \(H_1\); (b) justifica la prueba; (c) ejecútala; (d) reporta el estadístico, el p-valor y el tamaño del efecto; (e) interpreta en el contexto.

7.1 Caso 1: digitalización de citas en centros de salud

Tiempo de espera promedio (minutos) en 10 centros, antes y después de implementar citas digitales.

antes   <- c(35, 42, 28, 50, 38, 45, 33, 40, 55, 30)
despues <- c(30, 35, 29, 41, 30, 38, 30, 36, 44, 27)
dd <- despues - antes
mostrar(data.frame(centro = 1:10, antes, despues, dif = dd, rango_abs = rank(abs(dd))))
 centro antes despues dif rango_abs
      1    35      30  -5       5.0
      2    42      35  -7       6.5
      3    28      29   1       1.0
      4    50      41  -9       9.0
      5    38      30  -8       8.0
      6    45      38  -7       6.5
      7    33      30  -3       2.5
      8    40      36  -4       4.0
      9    55      44 -11      10.0
     10    30      27  -3       2.5

Solución. Datos pareados; \(H_0\): la mediana del cambio es 0; \(H_1\): el tiempo disminuyó.

# Prueba de los signos: 9 negativos y 1 positivo
ver("Diferencias negativas" = sum(dd < 0), "Diferencias positivas" = sum(dd > 0))
  Diferencias negativas : 9
  Diferencias positivas : 1
informe(prueba_signos(dd, alternative = "less"))
-------------------------------------------------------------- 
  Prueba                 : Prueba de los signos (binomial exacta)
  Hipótesis alternativa  : unilateral, menor (cola izquierda)
  Estadístico            : B (signos +) = 1
  p-valor                : 0.0107
  Decisión (alfa = 0.05) : Se rechaza H0
-------------------------------------------------------------- 
# Wilcoxon: el único positivo (+1) tiene el rango 1, así que W+ = 1
informe(wilcox.test(despues, antes, paired = TRUE, alternative = "less",
                    exact = FALSE, correct = TRUE),
        extra = list("Hodges-Lehmann (min)" = hl_1m(dd)))
-------------------------------------------------------------- 
  Prueba                 : Wilcoxon de rangos con signo (aprox. normal)
  Hipótesis alternativa  : unilateral, menor (cola izquierda)
  Estadístico            : V = 1
  p-valor                : 0.004
  Decisión (alfa = 0.05) : Se rechaza H0
  Hodges-Lehmann (min)   : -5.5
-------------------------------------------------------------- 

Conclusión: el tiempo de espera se redujo de forma significativa (signos \(p = 0.011\); Wilcoxon \(W^+ = 1\), \(p = 0.004\)). La reducción típica es de unos 5.5 minutos por centro.

7.2 Caso 2: gasto en salud según tenencia de seguro

con_seguro <- c(120, 85, 60, 150, 95, 70, 110)
sin_seguro <- c(180, 140, 210, 160, 125, 240, 175, 130)
w2 <- wilcox.test(sin_seguro, con_seguro, alternative = "greater", exact = TRUE)
informe(w2, extra = list(
  "Correlación biserial r_rb" = 2 * unname(w2$statistic) / (7 * 8) - 1,
  "Hodges-Lehmann (S/)"       = hl_2m(sin_seguro, con_seguro)))
-------------------------------------------------------------- 
  Prueba                    : U de Mann-Whitney (exacta)
  Hipótesis alternativa     : unilateral, mayor (cola derecha)
  Estadístico               : W = 53
  p-valor                   : 0.0011
  Decisión (alfa = 0.05)    : Se rechaza H0
  Correlación biserial r_rb : 0.8929
  Hodges-Lehmann (S/)       : 67.5
-------------------------------------------------------------- 

Solución. Dos grupos independientes y muestras pequeñas con gasto asimétrico, así que no podemos verificar la normalidad: usamos Mann-Whitney. Los hogares sin seguro gastan significativamente más (\(U = 53\) de 56 pares posibles, \(p = 0.001\)), con un efecto muy grande (\(r_{rb} = 0.89\)) y una diferencia típica de S/ 67.5 mensuales.

7.3 Caso 3: vacunación completa por región natural

vac <- matrix(c(120, 30, 95, 55, 60, 40), 3, byrow = TRUE,
              dimnames = list(Region = c("Costa", "Sierra", "Selva"),
                              Vacunacion = c("Completa", "Incompleta")))
c3 <- chisq.test(vac, correct = FALSE)
informe(c3, extra = list("V de Cramér" = unname(sqrt(c3$statistic / sum(vac)))))
-------------------------------------------------------------- 
  Prueba                 : Chi-cuadrado de independencia
  Hipótesis alternativa  : no aplica (cola derecha)
  Estadístico            : Chi2 = 14.4485
  Grados de libertad     : 2
  p-valor                : 7.29e-04
  Decisión (alfa = 0.05) : Se rechaza H0
  V de Cramér            : 0.1901
-------------------------------------------------------------- 
round(c3$expected, 2)                       # todas > 5: supuesto cumplido
        Vacunacion
Region   Completa Incompleta
  Costa    103.12      46.88
  Sierra   103.12      46.88
  Selva     68.75      31.25
round(c3$stdres, 2)                         # residuos ajustados
        Vacunacion
Region   Completa Incompleta
  Costa      3.76      -3.76
  Sierra    -1.81       1.81
  Selva     -2.18       2.18
round(prop.table(vac, 1), 3)                # proporción por región
        Vacunacion
Region   Completa Incompleta
  Costa     0.800      0.200
  Sierra    0.633      0.367
  Selva     0.600      0.400

Solución. La vacunación completa depende de la región (\(\chi^2 = 14.45\), gl = 2, \(p < 0.001\)), con una asociación débil a moderada (\(V = 0.19\)). La Costa (80 %) supera a la Sierra (63 %) y a la Selva (60 %). Recomendación: priorizar las campañas de vacunación en la Sierra y la Selva.

7.4 Errores frecuentes en la evaluación

  1. Tratar datos pareados como independientes (usar Mann-Whitney en el caso 1).
  2. No descartar las diferencias nulas o no considerar los empates.
  3. Confundir el \(W\) de R con \(U_2\): verifica siempre que \(U_1 + U_2 = n_1 n_2\).
  4. Aplicar chi-cuadrado a porcentajes en lugar de conteos.
  5. Reportar solo “se rechaza \(H_0\)”, sin la dirección, el tamaño del efecto ni el contexto.
  6. Concluir causalidad a partir de un diseño antes/después sin grupo de control.

8 Resumen de la unidad

8.1 Fórmulas principales

Prueba Estadístico Distribución bajo \(H_0\) Tamaño del efecto
Signos \(B = \#\{D_i > 0\}\) \(\text{Bin}(n^*, 1/2)\) proporción de signos +
Wilcoxon (signo) \(W^+ = \sum\) rangos de \(D_i > 0\) \(E = \frac{n(n+1)}{4}\), \(V = \frac{n(n+1)(2n+1)}{24}\) \(r = Z/\sqrt{n}\)
Mann-Whitney \(U_1 = R_1 - \frac{n_1(n_1+1)}{2}\) \(E = \frac{n_1 n_2}{2}\), \(V = \frac{n_1 n_2 (N+1)}{12}\) \(r_{rb} = \frac{2U_1}{n_1 n_2} - 1\)
Chi-cuadrado \(\sum \frac{(O - E)^2}{E}\), \(E_{ij} = \frac{f_i c_j}{n}\) \(\chi^2_{(r-1)(c-1)}\) \(V = \sqrt{\frac{\chi^2}{n(k-1)}}\)
Fisher celda \(a\) de la tabla \(2\times2\) hipergeométrica odds ratio

8.2 ¿Qué prueba uso?

Situación Prueba Función de R
Mediana de una muestra, o datos pareados, sin suponer simetría Signos binom.test()
Una muestra o pares, distribución simétrica Wilcoxon de rangos con signo wilcox.test(x, y, paired = TRUE)
Dos muestras independientes Mann-Whitney wilcox.test(x, y)
Dos variables categóricas, esperadas \(\ge 5\) Chi-cuadrado chisq.test(tabla)
Dos variables categóricas, esperadas \(< 5\) Fisher exacta fisher.test(tabla)

8.3 Plantilla para redactar resultados

“Se aplicó la prueba [nombre] porque [tipo de datos y diseño; supuesto que no se cumple]. Se obtuvo [estadístico] = [valor], $p = $ [valor], con un tamaño del efecto de [valor] ([pequeño / mediano / grande]). Esto indica que [conclusión en el contexto]. Limitaciones: [tamaño de muestra, diseño, generalización].”

Referencias

  • Agresti, A. (2019). An Introduction to Categorical Data Analysis (3.ª ed.), cap. 2. Wiley.
  • Conover, W. J. (1999). Practical Nonparametric Statistics (3.ª ed.), cap. 5. Wiley.
  • Hollander, M., Wolfe, D. A. y Chicken, E. (2014). Nonparametric Statistical Methods (3.ª ed.), cap. 3. Wiley.
  • Siegel, S. y Castellan, N. J. (1988). Nonparametric Statistics for the Behavioral Sciences (2.ª ed.). McGraw-Hill.
  • Wasserstein, R. L. y Lazar, N. A. (2016). The ASA Statement on p-Values. The American Statistician, 70(2), 129–133.
  • R Core Team (2024). R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing.