Las 5 réplicas por combinación permiten estimar el error experimental puro. Con ese error se puede probar estadísticamente la interacción \(A \times B\), que con una sola repetición quedaría confundida con él. El azar reparte entre todos los tratamientos las diferencias de luz o de posición en el vivero.
¿La altura de las plántulas depende de la dosis de fertilizante, de la frecuencia de riego o de su combinación? Es decir, ¿el efecto del fertilizante cambia según qué tan seguido se riega?
dosis <- factor(c(
"F10", "F10", "F5", "F5", "F10", "F10",
"F0", "F5", "F0", "F0", "F5", "F10",
"F10", "F5", "F0", "F10", "F5", "F0",
"F0", "F0", "F0", "F5", "F10", "F0",
"F10", "F5", "F0", "F10", "F5", "F5"
), levels = c("F0", "F5", "F10"))
riego <- factor(c(
"R2", "R1", "R2", "R1", "R2", "R1",
"R1", "R2", "R1", "R2", "R1", "R1",
"R1", "R2", "R1", "R2", "R1", "R2",
"R1", "R1", "R2", "R2", "R1", "R2",
"R2", "R1", "R2", "R2", "R1", "R2"
), levels = c("R1", "R2"))
df_experimento <- data.frame(
Bolsa = 1:30,
Dosis_NPK = dosis,
Frecuencia_Riego = riego
)
# Simulación usando extracción segura por índice de columna
set.seed(123)
df_experimento[['Altura_CM']] <- round(
rnorm(30, mean = 20, sd = 1.8) +
(as.numeric(df_experimento[['Dosis_NPK']]) * 4.2) -
(as.numeric(df_experimento[['Frecuencia_Riego']]) * 1.5) +
(as.numeric(df_experimento[['Dosis_NPK']]) * as.numeric(df_experimento[['Frecuencia_Riego']]) * 0.9),
2
)
A continuación se muestran las primeras filas de la matriz de diseño utilizando la codificación de referencia de R (dummy coding), donde \(F_0\) y \(R_1\) actúan como los niveles base.
matriz_diseno <- model.matrix(~ Dosis_NPK * Frecuencia_Riego, data = df_experimento)
head(matriz_diseno, 10)
## (Intercept) Dosis_NPKF5 Dosis_NPKF10 Frecuencia_RiegoR2
## 1 1 0 1 1
## 2 1 0 1 0
## 3 1 1 0 1
## 4 1 1 0 0
## 5 1 0 1 1
## 6 1 0 1 0
## 7 1 0 0 0
## 8 1 1 0 1
## 9 1 0 0 0
## 10 1 0 0 1
## Dosis_NPKF5:Frecuencia_RiegoR2 Dosis_NPKF10:Frecuencia_RiegoR2
## 1 0 1
## 2 0 0
## 3 1 0
## 4 0 0
## 5 0 1
## 6 0 0
## 7 0 0
## 8 1 0
## 9 0 0
## 10 0 0
Analizamos el comportamiento descriptivo del crecimiento agrupando los datos por cada combinación específica de tratamiento.
df_experimento[['Tratamiento']] <- interaction(df_experimento[['Dosis_NPK']], df_experimento[['Frecuencia_Riego']], sep = "-")
tabla_descriptivos <- aggregate(Altura_CM ~ Tratamiento, data = df_experimento,
FUN = function(x) c(Media = mean(x), Varianza = var(x)))
do.call(data.frame, tabla_descriptivos)
## Tratamiento Altura_CM.Media Altura_CM.Varianza
## 1 F0-R1 23.400 1.33415
## 2 F5-R1 28.328 4.60477
## 3 F10-R1 34.240 3.27790
## 4 F0-R2 21.788 3.37737
## 5 F5-R2 29.520 4.26055
## 6 F10-R2 35.318 3.07277
boxplot(Altura_CM ~ Tratamiento, data = df_experimento,
main = "Boxplot: Altura de Plántulas por Tratamiento",
xlab = "Tratamientos (Dosis - Riego)",
ylab = "Altura de la Plántula (cm)",
col = c("lightblue", "lightcyan", "lightyellow", "orange", "lightgreen", "darkgreen"),
las = 1, cex.axis = 0.8)
Figura 1: Variabilidad y promedios de la altura de ocobos por tratamiento.
modelo_factorial <- aov(Altura_CM ~ Dosis_NPK * Frecuencia_Riego, data = df_experimento)
summary(modelo_factorial)
## Df Sum Sq Mean Sq F value Pr(>F)
## Dosis_NPK 2 742.7 371.4 111.817 6.87e-13 ***
## Frecuencia_Riego 1 0.4 0.4 0.109 0.745
## Dosis_NPK:Frecuencia_Riego 2 12.6 6.3 1.896 0.172
## Residuals 24 79.7 3.3
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
sc_total <- sum((df_experimento[['Altura_CM']] - mean(df_experimento[['Altura_CM']]))^2)
sc_residual <- sum(residuals(modelo_factorial)^2)
r_cuadrado <- 1 - (sc_residual / sc_total)
media_general <- mean(df_experimento[['Altura_CM']])
rmse <- sqrt(mean(residuals(modelo_factorial)^2))
cv <- (rmse / media_general) * 100
prueba_tukey <- TukeyHSD(modelo_factorial, "Dosis_NPK:Frecuencia_Riego")
print(prueba_tukey)
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = Altura_CM ~ Dosis_NPK * Frecuencia_Riego, data = df_experimento)
##
## $`Dosis_NPK:Frecuencia_Riego`
## diff lwr upr p adj
## F5:R1-F0:R1 4.928 1.364222 8.491778 0.0031764
## F10:R1-F0:R1 10.840 7.276222 14.403778 0.0000000
## F0:R2-F0:R1 -1.612 -5.175778 1.951778 0.7274620
## F5:R2-F0:R1 6.120 2.556222 9.683778 0.0002478
## F10:R2-F0:R1 11.918 8.354222 15.481778 0.0000000
## F10:R1-F5:R1 5.912 2.348222 9.475778 0.0003871
## F0:R2-F5:R1 -6.540 -10.103778 -2.976222 0.0001011
## F5:R2-F5:R1 1.192 -2.371778 4.755778 0.9016439
## F10:R2-F5:R1 6.990 3.426222 10.553778 0.0000391
## F0:R2-F10:R1 -12.452 -16.015778 -8.888222 0.0000000
## F5:R2-F10:R1 -4.720 -8.283778 -1.156222 0.0049259
## F10:R2-F10:R1 1.078 -2.485778 4.641778 0.9332415
## F5:R2-F0:R2 7.732 4.168222 11.295778 0.0000084
## F10:R2-F0:R2 13.530 9.966222 17.093778 0.0000000
## F10:R2-F5:R2 5.798 2.234222 9.361778 0.0004944
if(!require(agricolae)) { install.packages("agricolae"); library(agricolae) }
prueba_fisher <- LSD.test(modelo_factorial, c("Dosis_NPK", "Frecuencia_Riego"), console = FALSE)
print(prueba_fisher[['groups']])
## Altura_CM groups
## F10:R2 35.318 a
## F10:R1 34.240 a
## F5:R2 29.520 b
## F5:R1 28.328 b
## F0:R1 23.400 c
## F0:R2 21.788 c
residuos <- residuals(modelo_factorial)
predichos <- predict(modelo_factorial)
shapiro.test(residuos)
##
## Shapiro-Wilk normality test
##
## data: residuos
## W = 0.96008, p-value = 0.3113
bartlett.test(residuos ~ interaction(Dosis_NPK, Frecuencia_Riego), data = df_experimento)
##
## Bartlett test of homogeneity of variances
##
## data: residuos by interaction(Dosis_NPK, Frecuencia_Riego)
## Bartlett's K-squared = 1.4961, df = 5, p-value = 0.9135
par(mfrow = c(1, 2))
qqnorm(residuos, main = "Q-Q Plot de Residuos", pch = 19, col = "darkblue")
qqline(residuos, col = "red", lwd = 2)
plot(predichos, residuos,
main = "Residuos vs. Valores Predichos",
xlab = "Valores Ajustados (Predichos)", ylab = "Residuos",
pch = 19, col = "darkgreen")
abline(h = 0, col = "red", lwd = 2, lty = 2)
Figura 2: Evaluación visual de la normalidad e homogeneidad de varianzas.
par(mfrow = c(1, 1))
interaction.plot(
x.factor = df_experimento[['Dosis_NPK']],
trace.factor = df_experimento[['Frecuencia_Riego']],
response = df_experimento[['Altura_CM']],
type = "b", col = c("blue", "red"), pch = c(16, 18), lwd = 2,
xlab = "Dosis de Fertilizante NPK",
ylab = "Altura Promedio de la Plántula (cm)",
legend = TRUE, trace.label = "Frecuencia Riego",
main = "Gráfico de Interacción Factores A x B"
)
Figura 3: Perfil de respuestas del factor Dosis NPK según la Frecuencia de Riego.