Pregunta de investigación. ¿Existen diferencias en el rendimiento (t/ha) de cuatro variedades de aceitunas de mesa cultivadas bajo un diseño completamente al azar con distinto número de repeticiones?
Diseño: un factor fijo (variedad), cuatro tratamientos y 24 unidades experimentales. Se adopta un nivel de significación de \(\alpha=0.05\).
datos <- 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)
)
knitr::kable(datos, col.names=c('Variedad','Rendimiento (t/ha)'),
caption='Datos originales de rendimiento por unidad experimental.', digits=2)| Variedad | Rendimiento (t/ha) |
|---|---|
| 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 |
resumen <- datos %>% group_by(Tratamiento) %>%
summarise(n=n(), media=mean(Rendimiento), mediana=median(Rendimiento),
de=sd(Rendimiento), varianza=var(Rendimiento),
minimo=min(Rendimiento), maximo=max(Rendimiento), .groups='drop')
knitr::kable(resumen, digits=3,
col.names=c('Variedad','n','Media','Mediana','DE','Varianza','Mín.','Máx.'),
caption='Resumen descriptivo por tratamiento.')| Variedad | n | Media | Mediana | DE | Varianza | Mín. | Máx. |
|---|---|---|---|---|---|---|---|
| Sevillana | 6 | 8.417 | 8.95 | 2.031 | 4.126 | 4.9 | 10.5 |
| Ascolana | 7 | 5.886 | 5.60 | 1.220 | 1.488 | 4.7 | 8.2 |
| Empeltre | 5 | 4.900 | 4.90 | 0.474 | 0.225 | 4.3 | 5.6 |
| Ilo | 6 | 9.633 | 9.75 | 0.799 | 0.639 | 8.7 | 10.6 |
La asignación es desbalanceada: las variedades cuentan con 6, 7, 5 y 6 repeticiones, respectivamente. Las observaciones deben ser independientes por construcción del experimento; esto no puede verificarse solo mediante pruebas sobre los rendimientos.
g_box <- ggplot(datos, aes(Tratamiento,Rendimiento,fill=Tratamiento)) +
geom_boxplot(width=.57,alpha=.8,outlier.shape=NA,color='#344450') +
geom_jitter(width=.09,height=0,size=2.6,alpha=.83,color='#273943') +
stat_summary(fun=mean,geom='point',shape=23,size=3.7,
fill='white',color='#253241',stroke=1) +
scale_fill_manual(values=colores) +
labs(title='Distribución del rendimiento',
subtitle='Puntos: unidades experimentales | Rombos: media',
x='Variedad',y='Rendimiento (t/ha)') + tema
g_boxFigura 1. Boxplots, observaciones individuales y medias (rombos blancos) por variedad.
medias <- resumen %>% mutate(
ee=de/sqrt(n),
li=media-qt(.975,df=n-1)*ee,
ls=media+qt(.975,df=n-1)*ee)
g_medias <- ggplot(medias,aes(Tratamiento,media,color=Tratamiento)) +
geom_errorbar(aes(ymin=li,ymax=ls),width=.14,linewidth=.8) +
geom_point(size=3.8) +
scale_color_manual(values=colores) +
labs(title='Rendimiento medio e incertidumbre',
subtitle='IC del 95 % calculados por separado en cada tratamiento',
x='Variedad',y='Media del rendimiento (t/ha)') + tema
g_mediasFigura 2. Medias muestrales con intervalos t de confianza del 95 % por variedad (descriptivos, sin ajuste por comparaciones múltiples).
El modelo clásico de efectos fijos es:
\[Y_{ij}=\mu+\tau_i+\varepsilon_{ij},\qquad \varepsilon_{ij}\overset{iid}{\sim}N(0,\sigma^2).\]
modelo <- aov(Rendimiento ~ Tratamiento, data=datos)
tab_aov <- as.data.frame(summary(modelo)[[1]])
knitr::kable(tab_aov, digits=5,
col.names=c('GL','Suma de cuadrados','Cuadrado medio','F','p'),
caption='Tabla ANOVA de una vía.')| GL | Suma de cuadrados | Cuadrado medio | F | p | |
|---|---|---|---|---|---|
| Tratamiento | 3 | 82.88976 | 27.62992 | 16.42183 | 1e-05 |
| Residuals | 20 | 33.65024 | 1.68251 | NA | NA |
Resultado. \(F(3, 20)=16.422\), \(p\) < 0.001. El tamaño del efecto descriptivo \(\eta^2=0.711\) indica la proporción de variabilidad total explicada por el factor tratamiento en esta muestra.
prueba_shapiro <- shapiro.test(residuals(modelo))
knitr::kable(data.frame(W=unname(prueba_shapiro$statistic),
p=prueba_shapiro$p.value),digits=5,
caption='Shapiro–Wilk aplicado a residuos del ANOVA.')| W | p |
|---|---|
| 0.94672 | 0.22986 |
Interpretación: \(p\) = 0.2299. No se rechaza la hipótesis de normalidad residual. Una prueba no significativa no demuestra normalidad.
residuos_df <- data.frame(Ajustados=fitted(modelo),
Residuos=residuals(modelo),
Tratamiento=datos$Tratamiento)
g_qq <- ggplot(residuos_df,aes(sample=Residuos)) +
stat_qq(size=2.5,color='#39796d',alpha=.8) +
stat_qq_line(color='#be8251',linewidth=1) +
labs(title='Normalidad: gráfico Q–Q',x='Cuantiles teóricos',
y='Cuantiles observados de los residuos') + tema
g_qqFigura 3. Gráfico Q–Q de residuos del ANOVA; desviaciones sistemáticas de la recta sugieren incumplimiento de normalidad.
prueba_levene <- car::leveneTest(Rendimiento ~ Tratamiento,
data=datos,center=median)
prueba_bartlett <- bartlett.test(Rendimiento ~ Tratamiento,data=datos)
comparacion_varianzas <- data.frame(
Prueba=c('Levene (centrado en la mediana)','Bartlett'),
Estadistico=c(prueba_levene[['F value']][1], unname(prueba_bartlett$statistic)),
p=c(prueba_levene[['Pr(>F)']][1],prueba_bartlett$p.value))
knitr::kable(comparacion_varianzas,digits=5,
caption='Contrastes de igualdad de varianzas.')| Prueba | Estadistico | p |
|---|---|---|
| Levene (centrado en la mediana) | 1.8990 | 0.16231 |
| Bartlett | 8.4254 | 0.03799 |
g_res <- ggplot(residuos_df,aes(Ajustados,Residuos,color=Tratamiento)) +
geom_hline(yintercept=0,linetype='dashed',color='#768992') +
geom_point(size=2.7,alpha=.85,
position=position_jitter(width=.08,height=0)) +
scale_color_manual(values=colores) +
labs(title='Dispersión de residuos por valor ajustado',
x='Rendimiento ajustado (t/ha)',y='Residuo') +
tema + theme(legend.position='bottom')
g_resFigura 4. Residuos frente a valores ajustados. Se inspeccionan dispersión, patrones y valores atípicos.
sh_grupos <- do.call(rbind,lapply(split(datos$Rendimiento,datos$Tratamiento),
function(x) data.frame(W=unname(shapiro.test(x)$statistic),
p=shapiro.test(x)$p.value)))
sh_grupos <- data.frame(Tratamiento=rownames(sh_grupos),sh_grupos,row.names=NULL)
knitr::kable(sh_grupos,digits=4,
caption='Shapiro–Wilk por variedad; interpretarlo con cautela debido a n pequeño.')| Tratamiento | W | p |
|---|---|---|
| Sevillana | 0.9189 | 0.4975 |
| Ascolana | 0.8913 | 0.2813 |
| Empeltre | 0.9744 | 0.9024 |
| Ilo | 0.9021 | 0.3865 |
Welch relaja la hipótesis de igualdad de varianzas y resulta especialmente pertinente cuando el diseño es desbalanceado.
prueba_welch <- oneway.test(Rendimiento ~ Tratamiento,data=datos,
var.equal=FALSE)
knitr::kable(data.frame(F=unname(prueba_welch$statistic),
gl_num=unname(prueba_welch$parameter[1]),
gl_den=unname(prueba_welch$parameter[2]),
p=prueba_welch$p.value),digits=5,
caption='ANOVA de Welch (grados de libertad ajustados).')| F | gl_num | gl_den | p |
|---|---|---|---|
| 45.999 | 3 | 10.68583 | 0 |
La prueba de Tukey se presenta como seguimiento del ANOVA clásico. Bajo heterocedasticidad relevante, considerar Games–Howell como alternativa.
tukey <- TukeyHSD(modelo)
tukey_tab <- data.frame(Comparacion=rownames(tukey$Tratamiento),
as.data.frame(tukey$Tratamiento),row.names=NULL,
check.names=FALSE)
knitr::kable(tukey_tab,digits=4,
col.names=c('Comparación','Diferencia','Límite inferior','Límite superior','p ajustado'),
caption='Comparaciones por pares de Tukey, con IC simultáneos al 95 %.')| Comparación | Diferencia | Límite inferior | Límite 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 |
tukey_plot <- data.frame(
comparacion=rownames(tukey$Tratamiento),
diferencia=tukey$Tratamiento[,'diff'],
li=tukey$Tratamiento[,'lwr'],
ls=tukey$Tratamiento[,'upr'],
significativo=tukey$Tratamiento[,'p adj']<.05)
g_tukey <- ggplot(tukey_plot,aes(x=reorder(comparacion,diferencia),y=diferencia,
color=significativo)) +
geom_hline(yintercept=0,linetype='dashed',color='#768992') +
geom_errorbar(aes(ymin=li,ymax=ls),width=.15,linewidth=.8) +
geom_point(size=3) + coord_flip() +
scale_color_manual(values=c('TRUE'='#39796d','FALSE'='#a6aeb3')) +
labs(title='Comparaciones múltiples de Tukey',
subtitle='Intervalos simultáneos de confianza del 95 %',
x='Contraste (primera variedad − segunda variedad)',
y='Diferencia de medias (t/ha)') + tema
g_tukeyFigura 5. Diferencias de medias e intervalos simultáneos de Tukey (95 %). Los intervalos que cruzan cero no indican diferencia estadísticamente significativa.
Kruskal–Wallis utiliza rangos. No exige normalidad ni homocedasticidad para contrastar igualdad de distribuciones, pero sí requiere independencia. Su interpretación específica como comparación de medianas exige distribuciones de forma y dispersión comparables.
prueba_kw <- kruskal.test(Rendimiento ~ Tratamiento,data=datos)
knitr::kable(data.frame(H=unname(prueba_kw$statistic),
gl=unname(prueba_kw$parameter),
p=prueba_kw$p.value),digits=5,
caption='Prueba de Kruskal–Wallis con corrección por empates.')| H | gl | p |
|---|---|---|
| 15.22975 | 3 | 0.00163 |
Resultado: \(H(3)=15.23\), \(p\) = 0.0016.
resultado_dunn <- FSA::dunnTest(Rendimiento ~ Tratamiento,
data=datos,method='holm')$res
knitr::kable(resultado_dunn,digits=5,
col.names=c('Comparación','Z','p sin ajustar','p ajustado (Holm)'),
caption='Pruebas de Dunn por pares, con control de multiplicidad de Holm.')| Comparación | Z | p sin ajustar | p ajustado (Holm) |
|---|---|---|---|
| Sevillana - Ascolana | 1.79000 | 0.07345 | 0.22036 |
| Sevillana - Empeltre | 2.48947 | 0.01279 | 0.05117 |
| Ascolana - Empeltre | 0.87369 | 0.38229 | 0.38229 |
| Sevillana - Ilo | -1.00108 | 0.31679 | 0.63358 |
| Ascolana - Ilo | -2.82887 | 0.00467 | 0.02336 |
| Empeltre - Ilo | -3.44396 | 0.00057 | 0.00344 |
| Procedimiento | p | Decision |
|---|---|---|
| ANOVA clásico | 0.00001 | p < 0.05 |
| Shapiro–Wilk (residuos) | 0.22986 | p ≥ 0.05 |
| Levene (mediana) | 0.16231 | p ≥ 0.05 |
| Bartlett | 0.03799 | p < 0.05 |
| ANOVA de Welch | 0.00000 | p < 0.05 |
| Kruskal–Wallis | 0.00163 | p < 0.05 |
El ANOVA detecta diferencias estadísticamente significativas entre las medias. Kruskal–Wallis también detecta diferencias globales entre las distribuciones. El rendimiento más alto observado corresponde a Ilo (9.63 t/ha) y el menor a Empeltre (4.90 t/ha).
El siguiente bloque se mantiene oculto por defecto. Cambie
eval=FALSE a eval=TRUE para exportar los
archivos a su directorio de trabajo.
ggsave('Figura_1_Boxplot.png',g_box,width=9,height=5.5,dpi=300)
ggsave('Figura_2_Medias_IC.png',g_medias,width=9,height=5.5,dpi=300)
ggsave('Figura_3_QQplot.png',g_qq,width=9,height=5.5,dpi=300)
ggsave('Figura_4_Residuos.png',g_res,width=9,height=5.5,dpi=300)
ggsave('Figura_5_Tukey.png',g_tukey,width=9,height=5.5,dpi=300)
write.csv(datos,'Datos_Aceitunas.csv',row.names=FALSE)Reproducibilidad: para generar este informe en
RStudio, abra el archivo .Rmd, instale los paquetes
requeridos y pulse Knit. También puede ejecutar
rmarkdown::render('Informe_DCA_Aceitunas.Rmd') (requiere el
paquete rmarkdown).