1 Objetivo y datos

Se compara el rendimiento de cuatro variedades de aceituna: Sevillana, Ascolana, Empeltre e Ilo. El análisis incluye estadística descriptiva, evaluación de supuestos y comparación de grupos con un nivel de significación de 0,05.

La unidad de medida del rendimiento no fue especificada. Se conserva la escala original de los datos.

datos_aceitunas <- data.frame(
  tratamiento = 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(
  nrow(datos_aceitunas) == 24L,
  !anyNA(datos_aceitunas),
  all(table(datos_aceitunas$tratamiento) >= 3)
)

knitr::kable(
  datos_aceitunas,
  col.names = c("Variedad", "Rendimiento"),
  caption = "Observaciones utilizadas en el análisis",
  digits = 2
)
Observaciones utilizadas en el análisis
Variedad 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

2 Análisis descriptivo

Las tablas y gráficos permiten examinar diferencias de localización, dispersión y posibles observaciones extremas antes de realizar las pruebas.

grupos <- split(
  datos_aceitunas$rendimiento,
  datos_aceitunas$tratamiento
)

resumen <- do.call(
  rbind,
  lapply(names(grupos), function(nombre) {
    x <- grupos[[nombre]]
    n <- length(x)
    error_estandar <- sd(x) / sqrt(n)
    margen <- qt(0.975, df = n - 1) * error_estandar

    data.frame(
      Variedad = nombre,
      n = n,
      Media = mean(x),
      Mediana = median(x),
      DE = sd(x),
      Minimo = min(x),
      Maximo = max(x),
      IC_inferior = mean(x) - margen,
      IC_superior = mean(x) + margen
    )
  })
)

resumen$Variedad <- factor(
  resumen$Variedad,
  levels = levels(datos_aceitunas$tratamiento)
)

knitr::kable(
  resumen,
  digits = 2,
  col.names = c(
    "Variedad", "n", "Media", "Mediana", "DE",
    "Mínimo", "Máximo", "IC 95% inferior", "IC 95% superior"
  ),
  caption = "Resumen descriptivo e intervalos de confianza para la media"
)
Resumen descriptivo e intervalos de confianza para la media
Variedad n Media Mediana DE Mínimo Máximo IC 95% inferior IC 95% superior
Sevillana 6 8.42 8.95 2.03 4.9 10.5 6.29 10.55
Ascolana 7 5.89 5.60 1.22 4.7 8.2 4.76 7.01
Empeltre 5 4.90 4.90 0.47 4.3 5.6 4.31 5.49
Ilo 6 9.63 9.75 0.80 8.7 10.6 8.79 10.47

Los intervalos descriptivos se calculan con la distribución t de Student para cada grupo y no son intervalos simultáneos. Su interpretación supone observaciones independientes y normalidad aproximadamente válida dentro de cada variedad.

2.1 Distribución del rendimiento

Cada punto representa una observación. Las cajas muestran la mediana y el rango intercuartílico; el rombo blanco identifica la media.

ggplot(
  datos_aceitunas,
  aes(x = tratamiento, y = rendimiento, fill = tratamiento)
) +
  geom_boxplot(
    width = 0.58,
    alpha = 0.65,
    outlier.shape = NA,
    color = "#34495E"
  ) +
  geom_jitter(
    width = 0.10,
    height = 0,
    size = 2.8,
    alpha = 0.85,
    color = "#243746"
  ) +
  stat_summary(
    fun = mean,
    geom = "point",
    shape = 23,
    size = 3.5,
    fill = "white",
    color = "#243746"
  ) +
  scale_fill_manual(values = colores) +
  labs(
    title = "Distribución del rendimiento",
    subtitle = "Observaciones individuales, mediana, dispersión y media",
    x = "Variedad",
    y = "Rendimiento"
  )
Distribución del rendimiento por variedad.

Distribución del rendimiento por variedad.

2.2 Medias e intervalos de confianza

Este gráfico muestra la magnitud de las diferencias observadas y la incertidumbre de cada media. El solapamiento de los intervalos no sustituye una prueba formal de comparación.

ggplot(
  resumen,
  aes(x = Variedad, y = Media, color = Variedad)
) +
  geom_errorbar(
    aes(ymin = IC_inferior, ymax = IC_superior),
    width = 0.12,
    linewidth = 0.9
  ) +
  geom_point(size = 4) +
  geom_text(
    aes(label = sprintf("%.2f", Media)),
    nudge_x = 0.18,
    hjust = 0,
    size = 3.8,
    show.legend = FALSE
  ) +
  scale_color_manual(values = colores) +
  scale_x_discrete(expand = expansion(add = 0.6)) +
  labs(
    title = "Rendimiento promedio por variedad",
    subtitle = "Barras: intervalos de confianza individuales del 95%",
    x = "Variedad",
    y = "Media del rendimiento"
  )
Medias e intervalos de confianza individuales del 95%.

Medias e intervalos de confianza individuales del 95%.

3 Evaluación de supuestos

El ANOVA clásico supone errores independientes, aproximadamente normales y con varianza común. La independencia debe justificarse con el diseño experimental; no puede verificarse con estas pruebas.

Con muestras de cinco a siete observaciones por variedad, las pruebas de supuestos tienen capacidad limitada para detectar desviaciones. Un valor p mayor que 0,05 no demuestra que el supuesto se cumpla.

modelo_lm <- lm(
  rendimiento ~ tratamiento,
  data = datos_aceitunas
)

test_normalidad <- shapiro.test(residuals(modelo_lm))

# Levene centrado en la mediana: variante robusta de Brown-Forsythe.
test_levene <- car::leveneTest(
  rendimiento ~ tratamiento,
  data = datos_aceitunas,
  center = median
)

tabla_supuestos <- data.frame(
  Prueba = c(
    "Shapiro-Wilk de residuos",
    "Levene centrado en la mediana"
  ),
  Estadistico = c(
    unname(test_normalidad$statistic),
    test_levene[1, "F value"]
  ),
  p = c(
    test_normalidad$p.value,
    test_levene[1, "Pr(>F)"]
  )
)

tabla_supuestos$Resultado <- ifelse(
  tabla_supuestos$p < alpha,
  "Se rechaza la hipótesis nula",
  "No se rechaza la hipótesis nula"
)

knitr::kable(
  tabla_supuestos,
  digits = 4,
  col.names = c("Prueba", "Estadístico", "Valor p", "Resultado"),
  caption = "Evaluación de normalidad y homogeneidad de varianzas"
)
Evaluación de normalidad y homogeneidad de varianzas
Prueba Estadístico Valor p Resultado
Shapiro-Wilk de residuos 0.9467 0.2299 No se rechaza la hipótesis nula
Levene centrado en la mediana 1.8990 0.1623 No se rechaza la hipótesis nula

Normalidad de residuos: p = 0,230. No se detecta evidencia suficiente para rechazar la normalidad.

Homogeneidad de varianzas: p = 0,162. No se detecta evidencia suficiente para rechazar la igualdad de varianzas.

3.1 Normalidad por variedad

Estas pruebas se presentan como diagnóstico complementario, no como una regla automática para seleccionar el análisis.

tabla_normalidad <- do.call(
  rbind,
  lapply(names(grupos), function(nombre) {
    prueba <- shapiro.test(grupos[[nombre]])

    data.frame(
      Variedad = nombre,
      W = unname(prueba$statistic),
      p = prueba$p.value
    )
  })
)

knitr::kable(
  tabla_normalidad,
  digits = 4,
  col.names = c("Variedad", "W", "Valor p"),
  caption = "Prueba de Shapiro-Wilk por variedad"
)
Prueba de Shapiro-Wilk por variedad
Variedad W Valor p
Sevillana 0.9189 0.4975
Ascolana 0.8913 0.2813
Empeltre 0.9744 0.9024
Ilo 0.9021 0.3865

3.2 Diagnóstico visual del modelo

El gráfico de residuos frente a valores ajustados ayuda a identificar cambios en la dispersión. El gráfico Q-Q permite evaluar visualmente desviaciones de la normalidad.

op <- par(mfrow = c(1, 2), mar = c(4.5, 4.5, 3, 1))

plot(
  fitted(modelo_lm),
  residuals(modelo_lm),
  pch = 19,
  col = "#487CA5",
  xlab = "Valores ajustados",
  ylab = "Residuos",
  main = "Residuos vs. ajustados"
)
abline(h = 0, lty = 2, col = "#C0504D", lwd = 2)

qqnorm(
  residuals(modelo_lm),
  pch = 19,
  col = "#487CA5",
  main = "Gráfico Q-Q de residuos",
  xlab = "Cuantiles teóricos",
  ylab = "Cuantiles observados"
)
qqline(residuals(modelo_lm), col = "#C0504D", lwd = 2)
Diagnóstico de residuos del modelo de una vía.

Diagnóstico de residuos del modelo de una vía.

par(op)

4 Comparación estadística

Se presentan tres análisis con objetivos y supuestos distintos. No deben considerarse una votación entre pruebas ni seleccionarse únicamente por cuál produce el menor valor p.

  • ANOVA clásico: compara medias bajo el supuesto de varianza común.
  • ANOVA de Welch: compara medias sin exigir igualdad de varianzas.
  • Kruskal-Wallis: compara rangos; no es, en general, una prueba exclusiva de igualdad de medianas.

4.1 ANOVA clásico de una vía

La hipótesis nula establece que las cuatro medias poblacionales son iguales.

res_anova <- aov(
  rendimiento ~ tratamiento,
  data = datos_aceitunas
)

tabla_anova <- summary(res_anova)[[1]]
p_anova <- tabla_anova[1, "Pr(>F)"]

knitr::kable(
  data.frame(
    Fuente = c("Variedad", "Residuos"),
    GL = tabla_anova[, "Df"],
    SC = tabla_anova[, "Sum Sq"],
    CM = tabla_anova[, "Mean Sq"],
    F = tabla_anova[, "F value"],
    p = tabla_anova[, "Pr(>F)"]
  ),
  digits = 4,
  row.names = FALSE,
  caption = "Tabla del ANOVA clásico"
)
Tabla del ANOVA clásico
Fuente GL SC CM F p
Variedad 3 82.8898 27.6299 16.4218 0
Residuos 20 33.6502 1.6825 NA NA
eta2 <- tabla_anova[1, "Sum Sq"] / sum(tabla_anova[, "Sum Sq"])

El ANOVA clásico presenta p < 0,001. Bajo los supuestos del modelo, existe evidencia de que al menos una media difiere.

El tamaño del efecto observado es eta cuadrado = 0,711. En esta muestra, el factor variedad representa aproximadamente el 71,1% de la variación total, sin implicar por sí mismo una relación causal.

4.2 ANOVA de Welch

Welch se incluye como análisis de sensibilidad ante posibles diferencias de varianza y tamaños de grupo desiguales.

res_welch <- oneway.test(
  rendimiento ~ tratamiento,
  data = datos_aceitunas,
  var.equal = FALSE
)

knitr::kable(
  data.frame(
    F = unname(res_welch$statistic),
    GL_numerador = unname(res_welch$parameter[1]),
    GL_denominador = unname(res_welch$parameter[2]),
    p = res_welch$p.value
  ),
  digits = 4,
  caption = "ANOVA de Welch"
)
ANOVA de Welch
F GL_numerador GL_denominador p
45.999 3 10.6858 0

El ANOVA de Welch presenta p < 0,001. Se detecta evidencia de diferencias entre las medias sin suponer varianzas iguales.

4.3 Kruskal-Wallis

La interpretación como comparación de medianas requiere distribuciones de forma y dispersión similares. En caso contrario, una diferencia puede reflejar otros cambios en las distribuciones.

res_kruskal <- kruskal.test(
  rendimiento ~ tratamiento,
  data = datos_aceitunas
)

knitr::kable(
  data.frame(
    H = unname(res_kruskal$statistic),
    GL = unname(res_kruskal$parameter),
    p = res_kruskal$p.value
  ),
  digits = 4,
  caption = "Prueba de Kruskal-Wallis"
)
Prueba de Kruskal-Wallis
H GL p
15.2297 3 0.0016

Kruskal-Wallis presenta p = 0,002. Existe evidencia de diferencias en los rangos entre al menos dos variedades.

5 Comparaciones por pares

Las pruebas globales no identifican por sí solas cuáles variedades difieren. Las siguientes comparaciones incorporan ajustes por multiplicidad.

5.1 Tukey para el modelo de varianza común

Tukey se presenta cuando el ANOVA clásico resulta significativo. Sus conclusiones dependen de los supuestos de ese modelo; si la homogeneidad de varianzas es dudosa, se deben priorizar las comparaciones de Welch.

if (p_anova < alpha) {
  tukey <- TukeyHSD(res_anova, "tratamiento", conf.level = 0.95)
  tabla_tukey <- as.data.frame(tukey$tratamiento)

  tabla_tukey <- data.frame(
    Comparacion = rownames(tabla_tukey),
    Diferencia = tabla_tukey$diff,
    IC_inferior = tabla_tukey$lwr,
    IC_superior = tabla_tukey$upr,
    p_ajustado = tabla_tukey[["p adj"]],
    row.names = NULL
  )

  knitr::kable(
    tabla_tukey,
    digits = 4,
    caption = "Comparaciones de Tukey: diferencia del primer grupo menos el segundo"
  )
} else {
  cat("No se presentan comparaciones de Tukey porque el ANOVA global no fue significativo.")
}
Comparaciones de Tukey: diferencia del primer grupo menos el segundo
Comparacion Diferencia IC_inferior IC_superior 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

5.2 Comparaciones de Welch con ajuste de Holm

Si el ANOVA de Welch resulta significativo, se comparan las medias mediante pruebas t de Welch por pares. Holm controla el error familiar asociado a las comparaciones múltiples.

if (res_welch$p.value < alpha) {
  pares <- combn(levels(datos_aceitunas$tratamiento), 2, simplify = FALSE)

  tabla_pares <- do.call(
    rbind,
    lapply(pares, function(par) {
      x <- grupos[[par[1]]]
      y <- grupos[[par[2]]]
      prueba <- t.test(x, y, var.equal = FALSE)

      data.frame(
        Comparacion = paste(par[1], "-", par[2]),
        Diferencia_medias = mean(x) - mean(y),
        p = prueba$p.value
      )
    })
  )

  tabla_pares$p_Holm <- p.adjust(tabla_pares$p, method = "holm")
  tabla_pares$Significativa <- ifelse(
    tabla_pares$p_Holm < alpha, "Sí", "No"
  )

  knitr::kable(
    tabla_pares,
    digits = 4,
    caption = "Comparaciones de Welch por pares con ajuste de Holm"
  )
} else {
  cat("No se presentan comparaciones por pares porque el ANOVA de Welch no fue significativo.")
}
Comparaciones de Welch por pares con ajuste de Holm
Comparacion Diferencia_medias p p_Holm Significativa
Sevillana - Ascolana 2.5310 0.0287 0.0860 No
Sevillana - Empeltre 3.5167 0.0072 0.0287 Sí
Sevillana - Ilo -1.2167 0.2174 0.2174 No
Ascolana - Empeltre 0.9857 0.0869 0.1739 No
Ascolana - Ilo -3.7476 0.0000 0.0002 Sí
Empeltre - Ilo -4.7333 0.0000 0.0000 Sí

6 Conclusiones y alcance

  • Mayor media observada: Ilo con 9,63 unidades.
  • Menor media observada: Empeltre con 4,90 unidades.
  • Comparación de medias con Welch: se detectan diferencias globales estadísticamente significativas.
  • Análisis por rangos: Kruskal-Wallis detecta diferencias globales entre variedades.

La variedad con mayor media muestral no necesariamente supera estadísticamente a todas las demás; esa afirmación requiere revisar las comparaciones por pares.

Los resultados están limitados por el tamaño reducido de los grupos y la información disponible sobre el diseño. Si las observaciones proceden de mediciones repetidas, parcelas compartidas o bloques, este modelo de una vía puede no ser apropiado. Sin información sobre aleatorización y unidad experimental, no se atribuyen causalmente las diferencias a la variedad.

7 Información de reproducibilidad

Se registra el entorno de R para documentar las versiones utilizadas.

sessionInfo()
## R version 4.6.1 (2026-06-24 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26200)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=Spanish_Panama.utf8  LC_CTYPE=Spanish_Panama.utf8    LC_MONETARY=Spanish_Panama.utf8
## [4] LC_NUMERIC=C                    LC_TIME=Spanish_Panama.utf8    
## 
## time zone: America/Panama
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] ggplot2_4.0.3
## 
## loaded via a namespace (and not attached):
##  [1] vctrs_0.7.3        cli_3.6.6          knitr_1.52         rlang_1.3.0        xfun_0.62         
##  [6] Formula_1.2-6      car_3.1-5          generics_0.1.4     S7_0.2.2           jsonlite_2.0.0    
## [11] labeling_0.4.3     glue_1.8.1         htmltools_0.5.9    sass_0.4.10        scales_1.4.0      
## [16] rmarkdown_2.32     grid_4.6.1         abind_1.4-8        carData_3.0-6      tibble_3.3.1      
## [21] evaluate_1.0.5     jquerylib_0.1.4    fastmap_1.2.0      yaml_2.3.12        lifecycle_1.0.5   
## [26] compiler_4.6.1     dplyr_1.2.1        RColorBrewer_1.1-3 pkgconfig_2.0.3    farver_2.1.2      
## [31] digest_0.6.39      R6_2.6.1           tidyselect_1.2.1   pillar_1.11.1      magrittr_2.0.5    
## [36] bslib_0.12.0       withr_3.0.3        tools_4.6.1        gtable_0.3.6       cachem_1.1.0