1 Resumen ejecutivo

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.

2 Datos y preparación

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")
Primeras 10 observaciones
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

3 Estadística descriptiva

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")
Estadísticos descriptivos por tratamiento
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_plot

4 Distribución y variabilidad

El 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"))

5 Evaluación de los supuestos

5.1 Normalidad por tratamiento

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")
Prueba de normalidad por tratamiento
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

5.2 ANOVA y normalidad de residuos

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")

par(mfrow = c(1, 1))

5.3 Homogeneidad de varianzas

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")
Pruebas de homogeneidad de varianzas
Prueba Estadístico Grados de libertad Valor p
Levene 1.899 3, 20 0.1623
Bartlett 8.425 3 0.0380

6 Comparación inferencial entre tratamientos

6.1 ANOVA de un factor

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.

summary(modelo_anova)
##                       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

6.2 Comparaciones múltiples de Tukey

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"
  )
Comparaciones por pares: prueba HSD de Tukey
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

6.3 Kruskal–Wallis

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.

resultado_kw <- kruskal.test(rendimiento ~ tratamiento_aceitunas, data = df_tidy)
resultado_kw
## 
##  Kruskal-Wallis rank sum test
## 
## data:  rendimiento by tratamiento_aceitunas
## Kruskal-Wallis chi-squared = 15, df = 3, p-value = 0.002

7 Conclusiones automáticas orientativas

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 = "")
  • La media muestral más alta corresponde a Ilo (9.63).
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 = "")
}
  • El ANOVA es estadísticamente significativo (p = 0.0000128): existe evidencia de diferencias entre al menos dos medias. Consulte Tukey para identificar los pares.
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 = "")
}
  • Kruskal–Wallis también resulta significativo (p = 0.00163), lo que indica diferencias en las distribuciones de rangos entre grupos.
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.

8 Apéndice: datos completos

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")
Conjunto completo de observaciones
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.