En las investigaciones biológicas, muchas veces trabajamos con datos categóricos - observaciones que caen en categorías o grupos distintos. Este documento cubre los principales métodos estadísticos para analizar variables categóricas, incluyendo:
Supongamos que tenemos dos poblaciones y queremos comparar la proporción de éxitos o casos de interés en ambas (\(p_1\) y \(p_2\)). Para ello, consideramos dos muestras aleatorias independientes de tamaño \(n_1\) y \(n_2\) de las poblaciones 1 y 2, respectivamente.
El error estándar de la diferencia entre las proporciones (\(p_1 - p_2\)) en ambas poblaciones se calcula utilizando la fórmula:
\[SE = \sqrt{\frac{p_1(1-p_1)}{n_1} + \frac{p_2(1-p_2)}{n_2}}\]
La estimación de la diferencia entre las proporciones de éxitos en ambas poblaciones y su intervalo de confianza se puede calcular utilizando la fórmula:
\[(p_1 - p_2) \pm z_{\alpha/2} \sqrt{\frac{p_1(1-p_1)}{n_1} + \frac{p_2(1-p_2)}{n_2}}\]
donde \(z_{\alpha/2}\) es el valor crítico de la distribución normal estándar para un nivel de confianza de \(1-\alpha\).
El valor z se calcula como:
\[z = \frac{p_1 - p_2}{SE}\]
Con este valor z se puede calcular el valor-p para la prueba de hipótesis de que la diferencia entre las proporciones es cero, utilizando la distribución normal estándar.
Cálculo del valor-p:
\[p = 2(1 - \Phi(|z|))\]
donde \(\Phi\) es la función de
distribución acumulada de la distribución normal estándar (la función
pnorm en R).
La mamografía es un procedimiento de rayos X que se utiliza para detectar cáncer de mama. Se realizó un estudio de 30 años con casi 90,000 participantes femeninas. Durante un período de detección de 5 años, cada mujer fue asignada aleatoriamente a uno de dos grupos: en el primer grupo, las mujeres recibieron mamografías regulares para detectar el cáncer de mama, y en el segundo grupo, las mujeres recibieron exámenes regulares de cáncer de mama sin mamografía.
Hipótesis:
library(gt)
library(dplyr)
# Crear tabla de datos
death_table_df <- data.frame(
Grupo = c("Mamografía", "Control"),
Muertes = c(500, 505),
Sin_Muertes = c(44425, 44405)
)
# Mostrar tabla
death_table_df %>%
gt() %>%
tab_header(
title = "TABLA 1. Muertes por Cáncer de Mama",
subtitle = "Comparación entre Mamografía y Control"
) %>%
cols_label(
Grupo = "Grupo",
Muertes = "Muertes por Cáncer de Mama (Sí)",
Sin_Muertes = "Muertes por Cáncer de Mama (No)"
) %>%
fmt_number(
columns = c(Muertes, Sin_Muertes),
decimals = 0
)| TABLA 1. Muertes por Cáncer de Mama | ||
| Comparación entre Mamografía y Control | ||
| Grupo | Muertes por Cáncer de Mama (Sí) | Muertes por Cáncer de Mama (No) |
|---|---|---|
| Mamografía | 500 | 44,425 |
| Control | 505 | 44,405 |
# Datos del estudio
mammogram_deaths <- 500
mammogram_total <- 500 + 44425
control_deaths <- 505
control_total <- 505 + 44405
# Calcular proporciones
p1 <- mammogram_deaths / mammogram_total
p2 <- control_deaths / control_total
# Diferencia en proporciones
p_diff <- p1 - p2
# Error estándar de la diferencia
SEd <- sqrt((p1*(1-p1)/mammogram_total) + (p2*(1-p2)/control_total))
# Intervalo de confianza de la diferencia
CId <- p_diff + c(-1, 1) * qnorm(0.975) * SEd
# Calcular valor z
z <- (p1 - p2) / SEd
# Calcular valor-p (prueba de dos colas)
p_value <- 2 * (1 - pnorm(abs(z)))
# Crear tabla de resultados
results_df <- data.frame(
Estadística = c("Proporción 1", "Proporción 2", "Diferencia",
"Error Estándar", "Intervalo de Confianza",
"Valor Z", "Valor p"),
Valor = c(round(p1, 5), round(p2, 5), round(p_diff, 5),
round(SEd, 6),
paste0("(", round(CId[1], 4), ", ", round(CId[2], 4), ")"),
round(z, 3), round(p_value, 3))
)
results_df %>%
gt() %>%
tab_header(
title = "TABLA 2. Resultados de la Prueba de Hipótesis",
subtitle = "Comparación de Proporciones de Muertes por Cáncer de Mama"
) %>%
cols_label(
Estadística = "Estadístico",
Valor = "Valor"
)| TABLA 2. Resultados de la Prueba de Hipótesis | |
| Comparación de Proporciones de Muertes por Cáncer de Mama | |
| Estadístico | Valor |
|---|---|
| Proporción 1 | 0.01113 |
| Proporción 2 | 0.01124 |
| Diferencia | -0.00012 |
| Error Estándar | 0.000702 |
| Intervalo de Confianza | (-0.0015, 0.0013) |
| Valor Z | -0.164 |
| Valor p | 0.87 |
prop.test()# Realizar prueba de proporciones
prop_test_result <- prop.test(
x = c(mammogram_deaths, control_deaths),
n = c(mammogram_total, control_total),
alternative = "two.sided",
correct = FALSE
)
prop_test_result##
## 2-sample test for equality of proportions without continuity correction
##
## data: c(mammogram_deaths, control_deaths) out of c(mammogram_total, control_total)
## X-squared = 0.026874, df = 1, p-value = 0.8698
## alternative hypothesis: two.sided
## 95 percent confidence interval:
## -0.001490590 0.001260488
## sample estimates:
## prop 1 prop 2
## 0.01112966 0.01124471
alpha <- 0.05
if (p_value < alpha) {
cat("Rechazar H0: Existe una diferencia significativa entre las proporciones.\n")
} else {
cat("No se rechaza H0: No hay diferencia significativa entre las proporciones.\n")
}## No se rechaza H0: No hay diferencia significativa entre las proporciones.
library(ggplot2)
# Crear datos para la distribución normal
x <- seq(-4, 4, length = 1000)
y <- dnorm(x)
data <- data.frame(x = x, y = y)
# Valores críticos
z_alpha <- qnorm(alpha/2)
# Gráfica
ggplot(data, aes(x = x, y = y)) +
geom_line(color = "blue", size = 1) +
geom_area(data = subset(data, x <= z_alpha),
aes(x = x, y = y), fill = "red", alpha = 0.5) +
geom_area(data = subset(data, x >= -z_alpha),
aes(x = x, y = y), fill = "red", alpha = 0.5) +
geom_vline(xintercept = z, color = "black",
linetype = "dashed", size = 1) +
annotate("text", x = z, y = 0.2,
label = paste("Z =", round(z, 3)),
color = "black", hjust = -0.1) +
labs(x = "Valor Z", y = "Densidad") +
theme_minimal()FIGURA 1. Distribución normal estándar con región crítica y estadístico Z observado.
La prueba de bondad de ajuste se usa para determinar si una muestra de datos se ajusta a una distribución de probabilidad específica.
Hipótesis:
Estadístico de Prueba:
\[\chi^2 = \sum \frac{(O_i - E_i)^2}{E_i}\]
donde:
Supuestos:
La distribución chi-cuadrado es una distribución de probabilidad continua que se utiliza en estadística para probar la independencia de dos eventos. La distribución chi-cuadrado tiene un solo parámetro llamado grados de libertad (gl), que influye en la forma, el centro y la dispersión de la distribución.
# Crear distribuciones chi-cuadrado
chi_df <- data.frame(x = seq(0, 20, by = 0.1))
chi_df$df1 <- dchisq(chi_df$x, df = 1)
chi_df$df2 <- dchisq(chi_df$x, df = 2)
chi_df$df4 <- dchisq(chi_df$x, df = 4)
# Gráfica
ggplot(chi_df, aes(x = x)) +
geom_line(aes(y = df1, color = "gl = 1"), size = 1) +
geom_line(aes(y = df2, color = "gl = 2"), size = 1) +
geom_line(aes(y = df4, color = "gl = 4"), size = 1) +
labs(x = "Valor del estadístico", y = "Densidad",
color = "Grados de Libertad") +
scale_color_manual(values = c("gl = 1" = "red",
"gl = 2" = "blue",
"gl = 4" = "green")) +
theme_minimal()FIGURA 2. Distribución Chi-cuadrado para diferentes grados de libertad.
En una observación realizada en los jardines de la UPRH, encontramos que debajo de un árbol de Palo de María (Calophyllum antillanum), había plántulas de dos tipos: con hojas verdes y con hojas crema (etiolizadas).
Sospechamos que la etiolización de las plántulas es debida a un gen recesivo. Si ese es el caso y se cumple el supuesto de cruces al azar, entonces la proporción de plántulas con hojas crema debería ser de 1/4.
Datos observados:
Hipótesis:
# Datos observados
observed <- c(270, 86)
# Proporción esperada
expected <- c(3/4, 1/4) * sum(observed)
# Crear tabla con los datos observados y esperados
data.frame(
Tipo = c("Hojas Verdes", "Hojas Crema"),
Observado = observed,
Esperado = expected
) %>%
gt() %>%
tab_header(
title = "TABLA 3. Plántulas de Palo de María",
subtitle = "Comparación de frecuencias observadas y esperadas (3:1)"
)| TABLA 3. Plántulas de Palo de María | ||
| Comparación de frecuencias observadas y esperadas (3:1) | ||
| Tipo | Observado | Esperado |
|---|---|---|
| Hojas Verdes | 270 | 267 |
| Hojas Crema | 86 | 89 |
Para realizar la prueba de bondad de ajuste, seguimos los siguientes pasos:
qchisq().pchisq().# Calcular el estadístico de prueba
chi2 <- sum((observed - expected)^2 / expected)
cat("Estadístico de prueba χ²:", round(chi2, 4), "\n")## Estadístico de prueba χ²: 0.1348
## Grados de libertad: 1
# Valor crítico
alpha <- 0.05
critical_value <- qchisq(1 - alpha, df)
cat("Valor crítico (α = 0.05):", round(critical_value, 4), "\n")## Valor crítico (α = 0.05): 3.8415
## P-value: 0.7135
# Decisión
if (chi2 > critical_value) {
decision <- "Rechazamos H0"
} else {
decision <- "No rechazamos H0"
}
cat("\nDecisión:", decision, "\n")##
## Decisión: No rechazamos H0
# Gráfica de la distribución chi-cuadrado
x <- seq(0, 8, 0.01)
y <- dchisq(x, df)
ggplot(data.frame(x = x, y = y), aes(x = x, y = y)) +
geom_line(color = "blue", size = 1) +
geom_vline(xintercept = chi2, color = "darkgreen",
linetype = "dashed", size = 1) +
geom_area(data = subset(data.frame(x = x, y = y), x > critical_value),
aes(x = x, y = y), fill = "red", alpha = 0.5) +
annotate("text", x = chi2, y = 0.3,
label = paste("χ² =", round(chi2, 2)),
hjust = -0.1, color = "darkgreen") +
labs(x = "Chi-cuadrado", y = "f(Chi-cuadrado)") +
coord_cartesian(xlim = c(0, 8), ylim = c(0, 1)) +
theme_minimal()FIGURA 3. Distribución Chi-cuadrado con Región Crítica (α = 0.05) y Estadístico χ² Observado.
chisq.test()##
## Chi-squared test for given probabilities
##
## data: observed
## X-squared = 0.13483, df = 1, p-value = 0.7135
No rechazamos la hipótesis nula. Los datos son consistentes con la proporción esperada de 3:1, lo que sugiere que la etiolización de las plántulas podría estar controlada por un gen recesivo siguiendo las leyes de Mendel.
En un sistema dialélico, la proporción esperada de genotipos en la descendencia de un cruce monohíbrido es 1:2:1. Supongamos que realizamos un experimento genético y obtenemos los siguientes resultados:
# Frecuencias observadas y esperadas
observed_gen <- c(24, 63, 15)
total <- sum(observed_gen)
expected_gen <- total * c(1/4, 2/4, 1/4)
# Crear tabla de comparación
data.frame(
Genotipo = c("AA", "Aa", "aa"),
Observado = observed_gen,
Esperado = expected_gen
) %>%
gt() %>%
tab_header(
title = "TABLA 4. Frecuencias Genotípicas Observadas vs Esperadas",
subtitle = "Probando la proporción Mendeliana 1:2:1"
)| TABLA 4. Frecuencias Genotípicas Observadas vs Esperadas | ||
| Probando la proporción Mendeliana 1:2:1 | ||
| Genotipo | Observado | Esperado |
|---|---|---|
| AA | 24 | 25.5 |
| Aa | 63 | 51.0 |
| aa | 15 | 25.5 |
# Realizar prueba Chi-cuadrado
chi_sq_test <- chisq.test(x = observed_gen, p = c(1/4, 2/4, 1/4))
print(chi_sq_test)##
## Chi-squared test for given probabilities
##
## data: observed_gen
## X-squared = 7.2353, df = 2, p-value = 0.02685
# Generar distribución Chi-cuadrado
df_gen <- length(observed_gen) - 1
x_vals <- seq(0, 15, by = 0.01)
y_vals <- dchisq(x_vals, df = df_gen)
chi_data <- data.frame(x = x_vals, y = y_vals)
# Valor crítico y estadístico observado
critical_value_gen <- qchisq(0.95, df = df_gen)
observed_stat <- chi_sq_test$statistic
# Gráfica
ggplot(chi_data, aes(x = x, y = y)) +
geom_line(color = "blue", size = 1) +
geom_area(data = subset(chi_data, x > critical_value_gen),
aes(x = x, y = y), fill = "red", alpha = 0.5) +
geom_vline(xintercept = observed_stat, color = "darkgreen",
linetype = "dashed", size = 1) +
annotate("text", x = observed_stat, y = max(y_vals) * 0.5,
label = paste("χ² =", round(observed_stat, 2)),
hjust = -0.1, color = "darkgreen") +
labs(x = "Estadístico chi-cuadrado",
y = "Densidad") +
theme_minimal()FIGURA 4. Distribución Chi-cuadrado con Región Crítica (α = 0.05) y Estadístico χ² Observado.
Con p-value = 0.0268 < 0.05, rechazamos la hipótesis nula. Los datos no se ajustan a la distribución de probabilidad esperada de 1:2:1.
En un estudio de biodiversidad en un bosque tropical, se encontraron las siguientes frecuencias de especies de árboles. Se sospecha que la distribución de especies en el bosque sigue una distribución uniforme.
# Datos observados
observed_sp <- c(20, 30, 40, 10)
species_names <- c("Especie A", "Especie B", "Especie C", "Especie D")
# Esperado bajo distribución uniforme
expected_sp <- rep(sum(observed_sp) / length(observed_sp), length(observed_sp))
# Crear tabla
data.frame(
Especie = species_names,
Observado = observed_sp,
Esperado = expected_sp
) %>%
gt() %>%
tab_header(
title = "TABLA 5. Distribución de Especies",
subtitle = "Probando distribución uniforme"
)| TABLA 5. Distribución de Especies | ||
| Probando distribución uniforme | ||
| Especie | Observado | Esperado |
|---|---|---|
| Especie A | 20 | 25 |
| Especie B | 30 | 25 |
| Especie C | 40 | 25 |
| Especie D | 10 | 25 |
# Calcular estadístico chi-cuadrado
chi2_sp <- sum((observed_sp - expected_sp)^2 / expected_sp)
df_sp <- length(observed_sp) - 1
cat("Estadístico de prueba:", round(chi2_sp, 2), "\n")## Estadístico de prueba: 20
## Grados de libertad: 3
# Valor crítico y p-valor
critical_value_sp <- qchisq(0.95, df = df_sp)
p_value_sp <- 1 - pchisq(chi2_sp, df_sp)
cat("Valor crítico:", round(critical_value_sp, 4), "\n")## Valor crítico: 7.8147
## P-value: 2e-04
# Decisión
if (chi2_sp > critical_value_sp) {
cat("\nDecisión: Rechazamos H0\n")
} else {
cat("\nDecisión: No rechazamos H0\n")
}##
## Decisión: Rechazamos H0
# Prueba con chisq.test
chi_test_sp <- chisq.test(observed_sp,
p = rep(1/length(observed_sp), length(observed_sp)))
print(chi_test_sp)##
## Chi-squared test for given probabilities
##
## data: observed_sp
## X-squared = 20, df = 3, p-value = 0.0001697
Con p-value = 2^{-4} < 0.05, rechazamos la hipótesis nula. La distribución de especies no es uniforme.
Una tabla de contingencia es una tabla que muestra la distribución conjunta de dos o más variables categóricas. La prueba de independencia se utiliza para determinar si existe una relación significativa entre dos variables categóricas.
Hipótesis:
Estadístico de Prueba:
\[\chi^2 = \sum_{i=1}^{r} \sum_{j=1}^{c} \frac{(O_{ij} - E_{ij})^2}{E_{ij}}\]
Frecuencia Esperada:
\[E_{ij} = \frac{R_i \times C_j}{N}\]
donde:
Grados de Libertad:
\[gl = (R - 1) \times (C - 1)\]
Vamos a considerar un estudio clínico en el que se evalúa la eficacia de un tratamiento para una enfermedad. Se registraron los resultados (mejoría, igual y empeora) de los pacientes tratados con la droga y un placebo.
# Entrada de datos
datos_tc <- matrix(c(40, 5, 5, 18, 12, 20),
nrow = 2, byrow = TRUE,
dimnames = list(
Tratamiento = c("Droga", "Placebo"),
Resultado = c("Mejoría", "No Cambio", "Empeora")
))
# Mostrar tabla
as.data.frame.table(datos_tc) %>%
tidyr::pivot_wider(names_from = Resultado, values_from = Freq) %>%
gt() %>%
tab_header(
title = "TABLA 6. Tabla de Contingencia de Tratamiento y Resultado",
subtitle = "Estudio clínico"
)| TABLA 6. Tabla de Contingencia de Tratamiento y Resultado | |||
| Estudio clínico | |||
| Tratamiento | Mejoría | No Cambio | Empeora |
|---|---|---|---|
| Droga | 40 | 5 | 5 |
| Placebo | 18 | 12 | 20 |
# Valores esperados
expected_values <- chisq.test(datos_tc)$expected
as.data.frame.table(expected_values) %>%
tidyr::pivot_wider(names_from = Resultado, values_from = Freq) %>%
gt() %>%
tab_header(
title = "TABLA 7. Valores Esperados en la Tabla de Contingencia"
) %>%
fmt_number(
columns = c(Mejoría, `No Cambio`, Empeora),
decimals = 2
)| TABLA 7. Valores Esperados en la Tabla de Contingencia | |||
| Tratamiento | Mejoría | No Cambio | Empeora |
|---|---|---|---|
| Droga | 29.00 | 8.50 | 12.50 |
| Placebo | 29.00 | 8.50 | 12.50 |
# Realizar prueba chi-cuadrado de independencia
chi_test_clinical <- chisq.test(datos_tc)
print(chi_test_clinical)##
## Pearson's Chi-squared test
##
## data: datos_tc
## X-squared = 20.227, df = 2, p-value = 4.053e-05
# Gráfica de distribución chi-cuadrado
df_clinical <- chi_test_clinical$parameter
x_vals <- seq(0, 25, by = 0.01)
y_vals <- dchisq(x_vals, df = df_clinical)
chi_data_clinical <- data.frame(x = x_vals, y = y_vals)
critical_value <- qchisq(0.95, df = df_clinical)
observed_stat <- chi_test_clinical$statistic
ggplot(chi_data_clinical, aes(x = x, y = y)) +
geom_line(color = "blue", size = 1) +
geom_area(data = subset(chi_data_clinical, x > critical_value),
aes(x = x, y = y), fill = "red", alpha = 0.5) +
geom_vline(xintercept = observed_stat, color = "darkgreen",
linetype = "dashed", size = 1) +
annotate("text", x = observed_stat, y = max(y_vals) * 0.5,
label = paste("χ² =", round(observed_stat, 2)),
hjust = -0.1, color = "darkgreen") +
labs(subtitle = paste("gl =", df_clinical, ", p-value =",
round(chi_test_clinical$p.value, 5)),
x = "Estadístico chi-cuadrado",
y = "Densidad") +
theme_minimal()FIGURA 5. Distribución Chi-cuadrado con Región Crítica (α = 0.05) y Estadístico χ² Observado.
library(vcd)
# Renombrar para mejor visualización
contingency_table <- datos_tc
rownames(contingency_table) <- c("Droga", "Placebo")
colnames(contingency_table) <- c("Mejoría", "NC", "Emp")
# Crear gráfico de mosaico
mosaic(contingency_table, shade = TRUE, legend = TRUE,
labeling = labeling_values)FIGURA 6. Gráfico de Mosaico: Tratamiento vs Resultado. Incluye leyenda de residuos estandarizados y sombreado.
Con p-value = 4.05e-05 < 0.05, rechazamos la hipótesis nula. Existe una asociación significativa entre el tipo de tratamiento y el resultado del paciente.
Vamos a realizar los cálculos manualmente para entender mejor el proceso.
# Crear tabla de contingencia
tabla <- matrix(c(5, 60, 35, 40), nrow = 2, byrow = TRUE)
rownames(tabla) <- c("Hombres", "Mujeres")
colnames(tabla) <- c("Bajo Peso", "Peso Normal")
# Mostrar tabla
as.data.frame.table(tabla) %>%
tidyr::pivot_wider(names_from = Var2, values_from = Freq) %>%
gt() %>%
tab_header(title = "TABLA 8. Género y Estado de Peso")| TABLA 8. Género y Estado de Peso | ||
| Var1 | Bajo Peso | Peso Normal |
|---|---|---|
| Hombres | 5 | 60 |
| Mujeres | 35 | 40 |
# Calcular totales
total_tabla <- sum(tabla)
total_filas <- apply(tabla, 1, sum)
total_columnas <- apply(tabla, 2, sum)
cat("Tamaño total de la muestra:", total_tabla, "\n")## Tamaño total de la muestra: 140
## Totales de filas: 65 75
## Totales de columnas: 40 100
# Calcular valores esperados
valores_esperados <- total_filas %*% t(total_columnas) / total_tabla
rownames(valores_esperados) <- rownames(tabla)
colnames(valores_esperados) <- colnames(tabla)
cat("\nValores esperados:\n")##
## Valores esperados:
## Bajo Peso Peso Normal
## Hombres 18.57 46.43
## Mujeres 21.43 53.57
# Calcular estadístico chi-cuadrado manualmente
chi_cuadrado_manual <- sum((tabla - valores_esperados)^2 / valores_esperados)
cat("\nEstadístico chi-cuadrado manual:", round(chi_cuadrado_manual, 4), "\n")##
## Estadístico chi-cuadrado manual: 25.9179
# Grados de libertad
grados_libertad <- (nrow(tabla) - 1) * (ncol(tabla) - 1)
cat("Grados de libertad:", grados_libertad, "\n")## Grados de libertad: 1
# Valor crítico
valor_critico <- qchisq(0.95, df = grados_libertad)
cat("Valor crítico (α = 0.05):", round(valor_critico, 4), "\n")## Valor crítico (α = 0.05): 3.8415
# Decisión
if (chi_cuadrado_manual > valor_critico) {
cat("\nDecisión: Rechazar H0 - Las variables están asociadas\n")
} else {
cat("\nDecisión: No rechazar H0 - Las variables son independientes\n")
}##
## Decisión: Rechazar H0 - Las variables están asociadas
# Gráfico de barras
tabla_df <- as.data.frame.table(tabla)
colnames(tabla_df) <- c("Genero", "Peso", "Frecuencia")
ggplot(tabla_df, aes(x = Genero, y = Frecuencia, fill = Peso)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "Género", y = "Frecuencia") +
theme_minimal()FIGURA 7. Gráfico de barras de la distribución de Estado de Peso por Género.
FIGURA 8. Gráfico de Mosaico de las variables Género vs Estado de Peso.
| Prueba | Caso de Uso | Ejemplo |
|---|---|---|
| Dos Proporciones | Comparar tasas de éxito entre dos grupos | Ensayo clínico: tratamiento vs control |
| Bondad de Ajuste | Probar si los datos siguen una distribución esperada | Proporciones Mendelianas, distribución uniforme |
| Independencia | Probar relación entre dos variables categóricas | Tipo de tratamiento vs resultado |