Este informe compara el rendimiento observado en cuatro tratamientos de aceitunas: Sevillana, Ascolana, Empeltre e Ilo. Se presentan estadísticas descriptivas, evaluación de supuestos, pruebas inferenciales y visualizaciones para facilitar la interpretación de los resultados.
Nota metodológica. La elección entre ANOVA y métodos no paramétricos debe considerar los gráficos, los supuestos y el diseño del estudio. Las pruebas de normalidad tienen poca potencia con tamaños muestrales pequeños; por ello, no deben interpretarse de forma aislada.
Los datos se incorporan directamente al documento para que el análisis sea reproducible.
df_tidy <- data.frame(
tratamiento_aceitunas = factor(
c(rep("Sevillana", 6), rep("Ascolana", 7), rep("Empeltre", 5), rep("Ilo", 6)),
levels = c("Sevillana", "Ascolana", "Empeltre", "Ilo")
),
rendimiento = c(
4.9, 8.5, 9.4, 9.8, 7.4, 10.5,
8.2, 4.7, 5.6, 6.3, 6.4, 5.2, 4.8,
5.6, 4.9, 5.0, 4.7, 4.3,
10.6, 9.6, 8.7, 10.3, 9.9, 8.7
)
)
stopifnot(!anyNA(df_tidy))knitr::kable(head(df_tidy, 10),
col.names = c("Tratamiento", "Rendimiento"),
caption = "Primeras 10 observaciones") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE, position = "center")| Tratamiento | Rendimiento |
|---|---|
| Sevillana | 4.9 |
| Sevillana | 8.5 |
| Sevillana | 9.4 |
| Sevillana | 9.8 |
| Sevillana | 7.4 |
| Sevillana | 10.5 |
| Ascolana | 8.2 |
| Ascolana | 4.7 |
| Ascolana | 5.6 |
| Ascolana | 6.3 |
Se resumen el tamaño de muestra, la media, la desviación estándar, la mediana y el rango observado en cada tratamiento.
resumen <- df_tidy %>%
group_by(tratamiento_aceitunas) %>%
summarise(
n = n(),
media = mean(rendimiento),
desviacion_estandar = sd(rendimiento),
mediana = median(rendimiento),
minimo = min(rendimiento),
maximo = max(rendimiento),
rango = maximo - minimo,
.groups = "drop"
)
knitr::kable(resumen, digits = 2,
col.names = c("Tratamiento", "n", "Media", "Desv. estándar", "Mediana", "Mínimo", "Máximo", "Rango"),
caption = "Estadísticos descriptivos por tratamiento") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = TRUE, position = "center") %>%
row_spec(which.max(resumen$media), bold = TRUE, color = "white", background = "#287271")| Tratamiento | n | Media | Desv. estándar | Mediana | Mínimo | Máximo | Rango |
|---|---|---|---|---|---|---|---|
| Sevillana | 6 | 8.42 | 2.03 | 8.95 | 4.9 | 10.5 | 5.6 |
| Ascolana | 7 | 5.89 | 1.22 | 5.60 | 4.7 | 8.2 | 3.5 |
| Empeltre | 5 | 4.90 | 0.47 | 4.90 | 4.3 | 5.6 | 1.3 |
| Ilo | 6 | 9.63 | 0.80 | 9.75 | 8.7 | 10.6 | 1.9 |
medias_plot <- resumen %>%
ggplot(aes(x = reorder(tratamiento_aceitunas, media), y = media, fill = tratamiento_aceitunas)) +
geom_col(width = 0.68, show.legend = FALSE, alpha = 0.9) +
geom_text(aes(label = sprintf("%.2f", media)), hjust = -0.15, size = 4, color = "#23343B") +
coord_flip() +
scale_fill_brewer(palette = "Set2") +
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
labs(title = "Rendimiento medio por tratamiento", x = NULL, y = "Rendimiento medio") +
theme_minimal(base_size = 13) +
theme(plot.title = element_text(face = "bold", color = "#174A5B"),
panel.grid.major.y = element_blank())
medias_plotEl diagrama de cajas permite comparar medianas y dispersión; los puntos muestran cada observación individual. El punto rojo representa la media aritmética.
ggplot(df_tidy, aes(x = tratamiento_aceitunas, y = rendimiento, fill = tratamiento_aceitunas)) +
geom_boxplot(alpha = 0.75, outlier.shape = NA, width = 0.52, color = "#263238") +
geom_jitter(width = 0.12, size = 2.4, alpha = 0.78, color = "#263238") +
stat_summary(fun = mean, geom = "point", shape = 21, size = 3.7,
fill = "#D1495B", color = "white", stroke = 0.8) +
scale_fill_brewer(palette = "Set2") +
labs(title = "Comparación de la distribución del rendimiento",
subtitle = "Cada punto representa una observación; el punto rojo indica la media",
x = "Tratamiento de aceituna", y = "Rendimiento") +
theme_minimal(base_size = 13) +
theme(plot.title = element_text(face = "bold", color = "#174A5B"),
plot.subtitle = element_text(color = "#52636A"),
legend.position = "none",
panel.grid.major.x = element_blank(),
axis.line = element_line(color = "#52636A"))Se aplica Shapiro–Wilk por grupo. La hipótesis nula es que los datos del grupo proceden de una distribución normal.
prueba_shapiro <- df_tidy %>%
group_by(tratamiento_aceitunas) %>%
summarise(
n = n(),
W = unname(shapiro.test(rendimiento)$statistic),
p_valor = shapiro.test(rendimiento)$p.value,
.groups = "drop"
)
knitr::kable(prueba_shapiro, digits = 4,
col.names = c("Tratamiento", "n", "W de Shapiro–Wilk", "Valor p"),
caption = "Prueba de normalidad por tratamiento") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE, position = "center")| Tratamiento | n | W de Shapiro–Wilk | Valor p |
|---|---|---|---|
| Sevillana | 6 | 0.9189 | 0.4975 |
| Ascolana | 7 | 0.8913 | 0.2813 |
| Empeltre | 5 | 0.9744 | 0.9024 |
| Ilo | 6 | 0.9021 | 0.3865 |
modelo_anova <- aov(rendimiento ~ tratamiento_aceitunas, data = df_tidy)
residuos <- residuals(modelo_anova)
shapiro_residuos <- shapiro.test(residuos)
cat("Shapiro–Wilk para residuos del ANOVA\n")## Shapiro–Wilk para residuos del ANOVA
cat("W =", round(unname(shapiro_residuos$statistic), 4),
" | p =", format.pval(shapiro_residuos$p.value, digits = 4), "\n")## W = 0.9467 | p = 0.2299
par(mfrow = c(1, 2))
plot(modelo_anova, which = 1, main = "Residuos vs. valores ajustados")
plot(modelo_anova, which = 2, main = "Gráfico Q–Q de residuos")Levene es relativamente robusta ante desviaciones de normalidad; Bartlett es más sensible a ellas. En ambas pruebas, la hipótesis nula es que las varianzas de los grupos son iguales.
prueba_levene <- car::leveneTest(rendimiento ~ tratamiento_aceitunas, data = df_tidy)
prueba_bartlett <- bartlett.test(rendimiento ~ tratamiento_aceitunas, data = df_tidy)
knitr::kable(data.frame(
Prueba = c("Levene", "Bartlett"),
Estadistico = c(unname(prueba_levene[1, "F value"]), unname(prueba_bartlett$statistic)),
gl = c(paste(prueba_levene[1, "Df"], prueba_levene[2, "Df"], sep = ", "),
as.character(unname(prueba_bartlett$parameter))),
p_valor = c(prueba_levene[1, "Pr(>F)"], prueba_bartlett$p.value)
), digits = 4,
col.names = c("Prueba", "Estadístico", "Grados de libertad", "Valor p"),
caption = "Pruebas de homogeneidad de varianzas") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE, position = "center")| Prueba | Estadístico | Grados de libertad | Valor p |
|---|---|---|---|
| Levene | 1.899 | 3, 20 | 0.1623 |
| Bartlett | 8.425 | 3 | 0.0380 |
El ANOVA contrasta la hipótesis nula de igualdad de medias entre los cuatro tratamientos. Un valor p inferior a 0,05 aporta evidencia de que al menos una media difiere; por sí solo, no identifica qué grupos difieren.
## Df Sum Sq Mean Sq F value Pr(>F)
## tratamiento_aceitunas 3 82.9 27.63 16.4 0.000013 ***
## Residuals 20 33.7 1.68
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Si el ANOVA resulta significativo, Tukey HSD permite examinar las diferencias por pares controlando el error familiar bajo los supuestos del modelo.
# Convertir la salida de TukeyHSD directamente a un data.frame.
# Esto evita depender de los nombres de columnas que entregue broom::tidy().
tukey_lista <- TukeyHSD(modelo_anova, "tratamiento_aceitunas")
tukey_tabla <- as.data.frame(tukey_lista[["tratamiento_aceitunas"]])
tukey_tabla$Comparacion <- rownames(tukey_tabla)
rownames(tukey_tabla) <- NULL
tukey_tabla <- tukey_tabla %>%
select(Comparacion, diff, lwr, upr, `p adj`) %>%
mutate(across(where(is.numeric), ~ round(.x, 4)))
knitr::kable(
tukey_tabla,
col.names = c("Comparación", "Diferencia", "Límite inferior", "Límite superior", "Valor p ajustado"),
caption = "Comparaciones por pares: prueba HSD de Tukey",
digits = 4,
row.names = FALSE
) %>%
kableExtra::kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = TRUE,
position = "center"
)| Comparación | Diferencia | Límite inferior | Límite superior | Valor p ajustado |
|---|---|---|---|---|
| Ascolana-Sevillana | -2.5310 | -4.5508 | -0.5111 | 0.0110 |
| Empeltre-Sevillana | -3.5167 | -5.7151 | -1.3183 | 0.0012 |
| Ilo-Sevillana | 1.2167 | -0.8794 | 3.3128 | 0.3880 |
| Empeltre-Ascolana | -0.9857 | -3.1115 | 1.1401 | 0.5748 |
| Ilo-Ascolana | 3.7476 | 1.7278 | 5.7675 | 0.0002 |
| Ilo-Empeltre | 4.7333 | 2.5349 | 6.9317 | 0.0000 |
Kruskal–Wallis es una alternativa basada en rangos que contrasta diferencias en las distribuciones entre grupos. No es estrictamente una prueba de igualdad de medias; interpretar el resultado como diferencia de medianas requiere condiciones adicionales, como formas de distribución similares.
##
## Kruskal-Wallis rank sum test
##
## data: rendimiento by tratamiento_aceitunas
## Kruskal-Wallis chi-squared = 15, df = 3, p-value = 0.002
alpha <- 0.05
p_anova <- summary(modelo_anova)[[1]][["Pr(>F)"]][1]
p_kw <- resultado_kw$p.value
mejor_tratamiento <- resumen$tratamiento_aceitunas[which.max(resumen$media)]
media_mejor <- max(resumen$media)
cat("- La media muestral más alta corresponde a **", as.character(mejor_tratamiento),
"** (", sprintf("%.2f", media_mejor), ").\n", sep = "")if (p_anova < alpha) {
cat("- El ANOVA es estadísticamente significativo (p = ", format.pval(p_anova, digits = 4),
"): existe evidencia de diferencias entre al menos dos medias. Consulte Tukey para identificar los pares.\n", sep = "")
} else {
cat("- El ANOVA no alcanza significación estadística al nivel de 0,05 (p = ",
format.pval(p_anova, digits = 4), "). No se rechaza la hipótesis de igualdad de medias.\n", sep = "")
}if (p_kw < alpha) {
cat("- Kruskal–Wallis también resulta significativo (p = ", format.pval(p_kw, digits = 4),
"), lo que indica diferencias en las distribuciones de rangos entre grupos.\n", sep = "")
} else {
cat("- Kruskal–Wallis no resulta significativo al nivel de 0,05 (p = ",
format.pval(p_kw, digits = 4), ").\n", sep = "")
}cat("\n**Interpretación prudente:** los resultados deben leerse junto con los gráficos diagnósticos, el tamaño muestral y el contexto de cómo se obtuvieron las observaciones. Una diferencia estadística no implica necesariamente una diferencia agronómica importante.\n")Interpretación prudente: los resultados deben leerse junto con los gráficos diagnósticos, el tamaño muestral y el contexto de cómo se obtuvieron las observaciones. Una diferencia estadística no implica necesariamente una diferencia agronómica importante.
knitr::kable(df_tidy,
col.names = c("Tratamiento", "Rendimiento"),
caption = "Conjunto completo de observaciones") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE, position = "center")| Tratamiento | Rendimiento |
|---|---|
| Sevillana | 4.9 |
| Sevillana | 8.5 |
| Sevillana | 9.4 |
| Sevillana | 9.8 |
| Sevillana | 7.4 |
| Sevillana | 10.5 |
| Ascolana | 8.2 |
| Ascolana | 4.7 |
| Ascolana | 5.6 |
| Ascolana | 6.3 |
| Ascolana | 6.4 |
| Ascolana | 5.2 |
| Ascolana | 4.8 |
| Empeltre | 5.6 |
| Empeltre | 4.9 |
| Empeltre | 5.0 |
| Empeltre | 4.7 |
| Empeltre | 4.3 |
| Ilo | 10.6 |
| Ilo | 9.6 |
| Ilo | 8.7 |
| Ilo | 10.3 |
| Ilo | 9.9 |
| Ilo | 8.7 |
Informe generado con R Markdown. Los resultados y las conclusiones se calculan al renderizar el documento a partir de los datos incluidos.