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
)| 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 |
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"
)| 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.
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.
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%.
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"
)| 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.
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"
)| Variedad | W | Valor p |
|---|---|---|
| Sevillana | 0.9189 | 0.4975 |
| Ascolana | 0.8913 | 0.2813 |
| Empeltre | 0.9744 | 0.9024 |
| Ilo | 0.9021 | 0.3865 |
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.
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.
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"
)| Fuente | GL | SC | CM | F | p |
|---|---|---|---|---|---|
| Variedad | 3 | 82.8898 | 27.6299 | 16.4218 | 0 |
| Residuos | 20 | 33.6502 | 1.6825 | NA | NA |
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.
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"
)| 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.
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"
)| 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.
Las pruebas globales no identifican por sí solas cuáles variedades difieren. Las siguientes comparaciones incorporan ajustes por multiplicidad.
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.")
}| 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 |
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.")
}| 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í |
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.
Se registra el entorno de R para documentar las versiones utilizadas.
## 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