A veces queremos comparar medias entre muchos grupos. Inicialmente, podríamos pensar en hacer comparaciones por pares. Por ejemplo, si hubiera tres grupos, podríamos sentirnos tentados a comparar la primera media con la segunda, luego con la tercera y, finalmente, comparar la segunda y la tercera media para un total de tres comparaciones. Sin embargo, esta estrategia puede ser peligrosa. Si tenemos muchos grupos y hacemos muchas comparaciones, es probable que finalmente encontremos una diferencia solo por casualidad, incluso si no hay diferencia en las poblaciones. En cambio, deberíamos aplicar una prueba holística para verificar si hay evidencia de que al menos un par de grupos son de hecho diferentes, que es donde el ANOVA (Análisis de Varianza) interviene para ayudarnos (Çetinkaya-Rundel & Hardin, 2024).
El ANOVA es una técnica estadística que se utiliza para comparar las medias de tres o más grupos. La idea básica detrás del ANOVA es comparar la variabilidad entre los grupos con la variabilidad dentro de los grupos. Si la variabilidad entre los grupos es significativamente mayor que la variabilidad dentro de los grupos, entonces podemos concluir que al menos un par de grupos son diferentes.
El estadístico de contraste para el ANOVA es la razón de dos varianzas:
\[ F_c = \frac{MS_{\text{between}}}{MS_{\text{within}}}\tag{1} \]
donde \(MS_{\text{between}}\) es la media de las varianzas entre los grupos y \(MS_{\text{within}}\) es la media de las varianzas dentro de los grupos. Si la hipótesis nula es cierta, entonces \(F_c\) sigue una distribución \(F\) con \(k-1\) y \(n-k\) grados de libertad, donde \(k\) es el número de grupos y \(n\) es el número total de observaciones.
Figura 1. Diagrama conceptual del análisis de varianza (ANOVA) que muestra que la varianza total es la suma de la varianza entre grupos y la varianza dentro del grupo.
Las hipótesis para el ANOVA son:
El conjunto de datos ChickWeight
contiene datos sobre el
peso de los pollitos alimentados con diferentes dietas durante un
período de tiempo. Las variables son:
Vamos a calcular las medias y desviaciones estándar de los pesos de los pollitos alimentados con las cuatro dietas.
Tabla 1. Estadísticas descriptivas de los pesos de los pollitos por dieta.
Diet | mean_weight | sd_weight |
---|---|---|
1 | 102.6 | 56.7 |
2 | 122.6 | 71.6 |
3 | 142.9 | 86.5 |
4 | 135.3 | 68.8 |
Y graficamos la media de peso de los pollitos por dieta en el día 21.
# Graficar los pesos de los pollitos por dieta solamente para el último día
library(ggplot2)
# filtrar los datos para el último día
ChickWeight %>%
filter(Time == max(Time)) %>%
ggplot(aes(x = Diet, y = weight, fill = factor(Diet))) +
geom_boxplot() +
geom_point(stat = "summary", fun = mean, color = "red", shape = 18, size = 3) +
labs(x = "Dieta", y = "Peso")
Figura 2. Boxplot de los pesos de los pollitos por dieta en el último día.
Para comparar las medias de los pesos de los pollitos alimentados con las cuatro dietas, en el último día del experimento, formulamos las hipótesis:
Vamos a calcular los estadísticos del ANOVA para comparar las medias de los pesos de los pollitos alimentados con las cuatro dietas.
Las fórmulas para calcular los estadísticos del ANOVA son:
# Filtrar los datos para el último día
ChickWeight_last_day <- ChickWeight %>% filter(Time == max(Time))
# Calcular la suma de cuadrados total
SS_total <- sum((ChickWeight_last_day$weight - mean(ChickWeight_last_day$weight))^2)
# Calcular la suma de cuadrados entre grupos
SS_between <- sum(table(ChickWeight_last_day$Diet) * (tapply(ChickWeight_last_day$weight, ChickWeight_last_day$Diet, mean) - mean(ChickWeight_last_day$weight))^2)
# Calcular la suma de cuadrados dentro de grupos
SS_within <- sum((ChickWeight_last_day$weight - ave(ChickWeight_last_day$weight, ChickWeight_last_day$Diet, FUN = mean))^2)
# Calcular los grados de libertad
k <- length(unique(ChickWeight_last_day$Diet))
n <- nrow(ChickWeight_last_day)
df_between <- k - 1
# Calcular las medias cuadráticas
MS_between <- SS_between / df_between
MS_within <- SS_within / (n - k)
# Calcular el estadístico de contraste
F_c <- MS_between / MS_within
# Crear tabla con los estadísticos
anova_table <- data.frame(
Source = c("Between", "Within", "Total"),
SS = c(SS_between, SS_within, SS_total),
df = c(df_between, n - k, n - 1),
MS = c(MS_between, MS_within, NA),
F = c(F_c, NA, NA)
)
tabla2 <- gt(anova_table)
# calcular p-value
p_value <- 1 - pf(F_c, df_between, n - k)
p_value <- round(p_value, 4)
Tabla 2. Estadísticos del ANOVA para comparar las medias de los pesos de los pollitos alimentados con las cuatro dietas.
Source | SS | df | MS | F |
---|---|---|---|---|
Between | 57164.22 | 3 | 19054.741 | 4.654713 |
Within | 167839.42 | 41 | 4093.644 | NA |
Total | 225003.64 | 44 | NA | NA |
Vamos a implementar el ANOVA para comparar las medias de los pesos de los pollitos alimentados con las cuatro dietas, para el último día del experimento.
# Cargar el paquete necesario
library(stats)
# Implementar el ANOVA para el último día
modelo_anova <- aov(weight ~ Diet, data = ChickWeight %>% filter(Time == max(Time)))
Tabla 3. Resultados del ANOVA para comparar las medias de los pesos de los pollitos alimentados con las cuatro dietas, el último día del experimento.
summary(modelo_anova)
## Df Sum Sq Mean Sq F value Pr(>F)
## Diet 3 57164 19055 4.655 0.00686 **
## Residuals 41 167839 4094
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
El estadístico de contraste \(F_c\) es 4.6547132 y el valor-p asociado es 0.0069. Dado que el valor-p es menor que 0.05, rechazamos la hipótesis nula y concluimos que al menos un par de medias de grupos son diferentes.
Si el ANOVA es significativo, podemos realizar pruebas post-hoc para determinar qué pares de medias son diferentes. Una de las pruebas post-hoc más comunes es la prueba de Tukey.
# Cargar el paquete necesario
library(emmeans)
# Realizar la prueba de Tukey
tukey_results <- emmeans(modelo_anova, pairwise ~ Diet)
Tabla 4. Resultados de la prueba de Tukey para comparar las medias de los pesos de los pollitos alimentados con las cuatro dietas, el último día del experimento.
tukey_results
## $emmeans
## Diet emmean SE df lower.CL upper.CL
## 1 178 16.0 41 145 210
## 2 215 20.2 41 174 256
## 3 270 20.2 41 229 311
## 4 239 21.3 41 195 282
##
## Confidence level used: 0.95
##
## $contrasts
## contrast estimate SE df t.ratio p.value
## Diet1 - Diet2 -37.0 25.8 41 -1.433 0.4868
## Diet1 - Diet3 -92.5 25.8 41 -3.588 0.0047
## Diet1 - Diet4 -60.8 26.7 41 -2.281 0.1193
## Diet2 - Diet3 -55.6 28.6 41 -1.943 0.2264
## Diet2 - Diet4 -23.9 29.4 41 -0.811 0.8487
## Diet3 - Diet4 31.7 29.4 41 1.080 0.7036
##
## P value adjustment: tukey method for comparing a family of 4 estimates
El ANOVA tiene varios supuestos que deben cumplirse para que los resultados sean válidos:
Podemos realizar una prueba de homogeneidad de varianzas para verificar si las varianzas de los pesos de los pollitos alimentados con las cuatro dietas son iguales. La hipótesis a contrastar es:
# Cargar el paquete necesario
library(car)
# Realizar la prueba de homogeneidad de varianzas
leveneTest(weight ~ Diet, data = ChickWeight %>% filter(Time == max(Time)))
## Levene's Test for Homogeneity of Variance (center = median)
## Df F value Pr(>F)
## group 3 1.1597 0.3367
## 41
La prueba de homogeneidad de varianzas no es significativa, lo que indica que las varianzas de los pesos de los pollitos alimentados con las cuatro dietas son iguales.
Si los supuestos del ANOVA no se cumplen, podemos utilizar una alternativa no paramétrica, como la prueba de Kruskal-Wallis, para comparar las medias de los grupos.
# Realizar la prueba de Kruskal-Wallis
kruskal.test(weight ~ Diet, data = ChickWeight %>% filter(Time == max(Time)))
##
## Kruskal-Wallis rank sum test
##
## data: weight by Diet
## Kruskal-Wallis chi-squared = 10.585, df = 3, p-value = 0.0142
La prueba de Kruskal-Wallis es significativa, lo que indica que al menos un par de medias de grupos son diferentes.
En algunos experimentos, las observaciones se recopilan en diferentes momentos o bajo diferentes condiciones. En estos casos, es importante tener en cuenta la estructura de los datos y aplicar un ANOVA con repeticiones para tener en cuenta la correlación entre las observaciones.
El conjunto de datos ChickWeight
contiene datos sobre el
peso de los pollitos alimentados con diferentes dietas durante un
período de tiempo. Vamos a comparar las medias de los pesos de los
pollitos alimentados con las cuatro dietas, a lo largo del tiempo.
Vamos a calcular las medias y desviaciones estándar de los pesos de los pollitos alimentados con las cuatro dietas, a lo largo del tiempo.
# Calcular las medias y desviaciones estándar por dieta y tiempo
tabla3 <- ChickWeight %>%
group_by(Diet, Time) %>%
summarise(mean_weight = round(mean(weight), 1), sd_weight = round(sd(weight), 1)) %>%
gt()
Tabla 5. Estadísticas descriptivas de los pesos de los pollitos por dieta (1, 2, 3, 4) y tiempo (días).
Time | mean_weight | sd_weight |
---|---|---|
1 | ||
0 | 41.4 | 1.0 |
2 | 47.2 | 4.3 |
4 | 56.5 | 4.1 |
6 | 66.8 | 7.8 |
8 | 79.7 | 13.8 |
10 | 93.1 | 22.5 |
12 | 108.5 | 32.6 |
14 | 123.4 | 37.4 |
16 | 144.6 | 45.0 |
18 | 158.9 | 49.2 |
20 | 170.4 | 55.4 |
21 | 177.8 | 58.7 |
2 | ||
0 | 40.7 | 1.5 |
2 | 49.4 | 2.9 |
4 | 59.8 | 2.3 |
6 | 75.4 | 4.2 |
8 | 91.7 | 14.8 |
10 | 108.5 | 24.3 |
12 | 131.3 | 37.5 |
14 | 141.9 | 43.7 |
16 | 164.7 | 52.8 |
18 | 187.7 | 63.3 |
20 | 205.6 | 70.3 |
21 | 214.7 | 78.1 |
3 | ||
0 | 40.8 | 1.0 |
2 | 50.4 | 2.4 |
4 | 62.2 | 2.8 |
6 | 77.9 | 5.7 |
8 | 98.4 | 12.3 |
10 | 117.1 | 20.2 |
12 | 144.4 | 27.1 |
14 | 164.5 | 34.5 |
16 | 197.4 | 44.6 |
18 | 233.1 | 57.6 |
20 | 258.9 | 65.2 |
21 | 270.3 | 71.6 |
4 | ||
0 | 41.0 | 1.1 |
2 | 51.8 | 1.9 |
4 | 64.5 | 2.5 |
6 | 83.9 | 5.1 |
8 | 105.6 | 9.3 |
10 | 126.0 | 11.4 |
12 | 151.4 | 15.3 |
14 | 161.8 | 15.7 |
16 | 182.0 | 25.3 |
18 | 202.9 | 33.6 |
20 | 233.9 | 37.6 |
21 | 238.6 | 43.3 |
Para comparar las medias de los pesos de los pollitos alimentados con las cuatro dietas, a lo largo del tiempo, formulamos las hipótesis:
Vamos a implementar el ANOVA con repeticiones para comparar las medias de los pesos de los pollitos alimentados con las cuatro dietas, a lo largo del tiempo.
# Implementar el ANOVA con repeticiones
modelo_anova_rep <- aov(weight ~ Diet * Time + Error(Chick), data = ChickWeight)
# Resumen del ANOVA con repeticiones
tabla6 <- summary(modelo_anova_rep)
Tabla 6. Resultados del ANOVA con repeticiones para comparar las medias de los pesos de los pollitos alimentados con las cuatro dietas, a lo largo del tiempo.
tabla6$`Error: Chick`[[1]]
## Df Sum Sq Mean Sq F value Pr(>F)
## Diet 3 155863 51954 7.2207 0.0004822 ***
## Time 1 55175 55175 7.6683 0.0081965 **
## Diet:Time 1 2482 2482 0.3450 0.5599840
## Residuals 44 316586 7195
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Tabla 7. Resultados del ANOVA con repeticiones para comparar las medias de los pesos de los pollitos alimentados con las cuatro dietas, a lo largo del tiempo.
tabla6$`Error: Within`[[1]]
## Df Sum Sq Mean Sq F value Pr(>F)
## Time 1 1962914 1962914 3049.280 < 2.2e-16 ***
## Diet:Time 3 84222 28074 43.612 < 2.2e-16 ***
## Residuals 524 337315 644
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Çetinkaya-Rundel, M., Hardin, J., 2024. Introduction to Modern Statistics (2e), Second. ed. https://openintro-ims.netlify.app/