Se continuará con el ejemplo de vitamina C en jugo de naranja, pero se utilizará un cuadrado latino de orden 5 para comparar cinco métodos de conservación y controlar simultáneamente dos fuentes de variabilidad: filas y columnas.
En un cuadrado latino de orden 5 existen:
Cada tratamiento aparece exactamente una vez en cada fila y una vez en cada columna.12
Se desea evaluar el efecto de cinco métodos de conservación sobre el contenido de vitamina C en jugo de naranja después de siete días.
| Código | Método de conservación | Descripción |
|---|---|---|
| T1 | Ambiente | 25 °C |
| T2 | Refrigeración | 4 °C |
| T3 | Congelación | −18 °C |
| T4 | Envase opaco | 4 °C, protegido de la luz |
| T5 | Atmósfera reducida | 4 °C, con mínimo contacto con oxígeno |
La variable respuesta será:
\[ Y=\text{contenido de vitamina C en mg/100 mL} \]
El número de tratamientos determina el orden:
\[ p=5 \]
\[ N=p^2=5^2=25 \]
Por lo tanto:
Cada envase individual de jugo de naranja de 200 mL.
El valor de vitamina C medido en cada envase.
Método de conservación, con cinco niveles.
Para este ejemplo:
La elección de filas y columnas debe estar justificada. No se deben utilizar dos factores de bloqueo solamente porque el diseño lo exige.
El modelo del cuadrado latino es:
\[ Y_{ijk}=\mu+\tau_i+\rho_j+\kappa_k+\varepsilon_{ijk} \]
donde:
En R:
VitaminaC_mg100mL ~ Fila + Columna + Tratamiento
\[ H_0:\tau_1=\tau_2=\tau_3=\tau_4=\tau_5=0 \]
No existen diferencias entre los métodos de conservación.
\[ H_1: \]
Al menos un tratamiento presenta una media diferente.
Para un cuadrado latino de orden \(p=5\):
| Fuente de variación | Grados de libertad |
|---|---|
| Filas | \(p-1=4\) |
| Columnas | \(p-1=4\) |
| Tratamientos | \(p-1=4\) |
| Error | \((p-1)(p-2)=12\) |
| Total | \(p^2-1=24\) |
La aleatorización se realiza en tres etapas:
No se deben sortear las 25 celdas de manera independiente, porque se perdería la propiedad de que cada tratamiento aparece una sola vez por fila y columna. La permutación de filas, columnas y etiquetas conserva la estructura del cuadrado.34
T1 T2 T3 T4 T5
T2 T3 T4 T5 T1
T3 T4 T5 T1 T2
T4 T5 T1 T2 T3
T5 T1 T2 T3 T4
Cada tratamiento aparece una vez en cada fila y columna.
# ============================================================
# ALEATORIZACIÓN DE UN CUADRADO LATINO DE ORDEN 5
# Ejemplo: vitamina C en jugo de naranja
# ============================================================
library(dplyr)
library(tidyr)
library(writexl)
set.seed(20260901)
# Tratamientos
tratamientos <- c(
"T1_25C",
"T2_4C",
"T3_menos18C",
"T4_opaco",
"T5_atmosfera_reducida"
)
# Filas y columnas
filas <- paste0("F", 1:5)
columnas <- paste0("C", 1:5)
# ------------------------------------------------------------
# 1. Crear cuadrado latino básico
# ------------------------------------------------------------
cuadrado_base <- matrix(
c(
"A", "B", "C", "D", "E",
"B", "C", "D", "E", "A",
"C", "D", "E", "A", "B",
"D", "E", "A", "B", "C",
"E", "A", "B", "C", "D"
),
nrow = 5,
byrow = TRUE,
dimnames = list(filas, columnas)
)
print("Cuadrado latino básico:")
print(cuadrado_base)
# ------------------------------------------------------------
# 2. Aleatorizar filas y columnas
# ------------------------------------------------------------
orden_filas <- sample(filas)
orden_columnas <- sample(columnas)
cuadrado_permutado <- cuadrado_base[
orden_filas,
orden_columnas,
drop = FALSE
]
# ------------------------------------------------------------
# 3. Aleatorizar las etiquetas de tratamientos
# ------------------------------------------------------------
letras <- c("A", "B", "C", "D", "E")
tratamientos_aleatorizados <- sample(tratamientos)
correspondencia <- data.frame(
Letra = letras,
Tratamiento = tratamientos_aleatorizados
)
# Reemplazar letras por tratamientos
for (i in seq_along(letras)) {
cuadrado_permutado[
cuadrado_permutado == letras[i]
] <- tratamientos_aleatorizados[i]
}
print("Orden aleatorio de filas:")
print(orden_filas)
print("Orden aleatorio de columnas:")
print(orden_columnas)
print("Correspondencia de letras y tratamientos:")
print(correspondencia)
print("Cuadrado latino aleatorizado:")
print(cuadrado_permutado)
# Convertir la matriz a formato largo
plan <- as.data.frame(as.table(cuadrado_permutado))
names(plan) <- c(
"Fila",
"Columna",
"Tratamiento"
)
# Crear identificadores de unidades experimentales
plan <- plan %>%
mutate(
UE = paste0("UE", sprintf("%02d", 1:n())),
Fila = factor(Fila, levels = filas),
Columna = factor(Columna, levels = columnas),
Tratamiento = factor(
Tratamiento,
levels = tratamientos
),
Temp_Conservacion_C = case_when(
Tratamiento == "T1_25C" ~ 25,
Tratamiento == "T2_4C" ~ 4,
Tratamiento == "T3_menos18C" ~ -18,
Tratamiento == "T4_opaco" ~ 4,
Tratamiento == "T5_atmosfera_reducida" ~ 4
)
) %>%
select(
UE,
Fila,
Columna,
Tratamiento,
Temp_Conservacion_C
)
print(plan)
with(plan, table(Fila, Tratamiento))
Cada fila debe contener una vez cada tratamiento:
T1 T2 T3 T4 T5
F1 1 1 1 1 1
F2 1 1 1 1 1
F3 1 1 1 1 1
F4 1 1 1 1 1
F5 1 1 1 1 1
with(plan, table(Columna, Tratamiento))
También debe contener únicamente unos:
T1 T2 T3 T4 T5
C1 1 1 1 1 1
C2 1 1 1 1 1
C3 1 1 1 1 1
C4 1 1 1 1 1
C5 1 1 1 1 1
table(plan$Tratamiento)
Resultado esperado:
T1_25C 5
T2_4C 5
T3_menos18C 5
T4_opaco 5
T5_atmosfera_reducida 5
Se agregan las variables que se completarán durante el ensayo:
plan <- plan %>%
mutate(
Vol_DCPIP_mL = NA_real_,
VitaminaC_mg100mL = NA_real_,
Fecha_Analisis = NA_character_,
Analista = NA_character_,
Observaciones = NA_character_
)
La planilla tendrá una estructura como esta:
| UE | Fila | Columna | Tratamiento | Temperatura | Vol. DCPIP | Vitamina C |
|---|---|---|---|---|---|---|
| UE01 | F1 | C1 | T3_menos18C | −18 | ||
| UE02 | F1 | C2 | T5_atmosfera_reducida | 4 | ||
| UE03 | F1 | C3 | T1_25C | 25 |
Una fila representa una unidad experimental y una columna representa una variable.
# Tabla de asignación de tratamientos
asignacion <- plan %>%
select(
Fila,
Columna,
UE,
Tratamiento,
Temp_Conservacion_C
)
# Resumen del diseño
resumen <- data.frame(
Parametro = c(
"Diseño",
"Orden del cuadrado",
"Número de tratamientos",
"Número de filas",
"Número de columnas",
"Total de unidades experimentales",
"Repeticiones por tratamiento"
),
Valor = c(
"Cuadrado latino",
5,
5,
5,
5,
25,
5
)
)
# Exportar
write_xlsx(
list(
Plan_Cuadrado_Latino = plan,
Asignacion = asignacion,
Resumen_Diseno = resumen,
Correspondencia = correspondencia
),
"plan_cuadrado_latino_orden5.xlsx"
)
Una vez realizado el ensayo, se completan:
Vol_DCPIP_mL;VitaminaC_mg100mL;Fecha_Analisis;Analista;Observaciones.Los datos simulados se encuentran en archivo llamado:
datos_vitamina_c_DCL.xlsx
# ============================================================
# IMPORTACIÓN DE DATOS
# ============================================================
library(readxl)
library(janitor)
library(dplyr)
datos <- read_excel(
"datos_vitamina_c_DCL.xlsx",
sheet = "Datos_Raw"
) %>%
clean_names()
names(datos)
str(datos)
summary(datos)
Conversión de variables:
datos <- datos %>%
mutate(
ue = factor(ue),
fila = factor(fila),
columna = factor(columna),
tratamiento = factor(
tratamiento,
levels = c(
"T1_25C",
"T2_4C",
"T3_menos18C",
"T4_opaco",
"T5_atmosfera_reducida"
)
),
vitamina_c = as.numeric(vitamina_c_mg100m_l)
)
Si el nombre de la columna cambia al usar clean_names(),
verificarlo mediante:
names(datos)
# ============================================================
# ESTADÍSTICA DESCRIPTIVA
# ============================================================
descriptivos <- datos %>%
group_by(tratamiento) %>%
summarise(
n = n(),
media = mean(vitamina_c),
mediana = median(vitamina_c),
desviacion_estandar = sd(vitamina_c),
varianza = var(vitamina_c),
error_estandar =
desviacion_estandar / sqrt(n),
minimo = min(vitamina_c),
maximo = max(vitamina_c),
cv =
desviacion_estandar / media * 100
)
print(descriptivos)
Resumen por filas:
datos %>%
group_by(fila) %>%
summarise(
n = n(),
media = mean(vitamina_c),
desviacion_estandar = sd(vitamina_c)
)
Resumen por columnas:
datos %>%
group_by(columna) %>%
summarise(
n = n(),
media = mean(vitamina_c),
desviacion_estandar = sd(vitamina_c)
)
library(ggplot2)
ggplot(
datos,
aes(
x = tratamiento,
y = vitamina_c,
fill = tratamiento
)
) +
geom_boxplot(alpha = 0.65) +
geom_jitter(
width = 0.10,
size = 2.5,
color = "black"
) +
labs(
title = "Contenido de vitamina C por tratamiento",
x = "Método de conservación",
y = "Vitamina C (mg/100 mL)"
) +
theme_minimal() +
theme(
legend.position = "none",
axis.text.x = element_text(
angle = 25,
hjust = 1
)
)
ggplot(
datos,
aes(
x = columna,
y = fila,
fill = tratamiento
)
) +
geom_tile(
color = "white",
linewidth = 1
) +
geom_text(
aes(label = round(vitamina_c, 1)),
color = "black",
size = 4
) +
labs(
title = "Cuadrado latino de orden 5",
subtitle = "Valores observados de vitamina C",
x = "Columna",
y = "Fila",
fill = "Tratamiento"
) +
theme_minimal()
ggplot(
descriptivos,
aes(
x = tratamiento,
y = media,
fill = tratamiento
)
) +
geom_col(alpha = 0.7) +
geom_errorbar(
aes(
ymin = media - error_estandar,
ymax = media + error_estandar
),
width = 0.2
) +
labs(
title = "Medias de vitamina C por tratamiento",
x = "Tratamiento",
y = "Media de vitamina C (mg/100 mL)"
) +
theme_minimal() +
theme(
legend.position = "none",
axis.text.x = element_text(
angle = 25,
hjust = 1
)
)
# ============================================================
# MODELO CUADRADO LATINO DE ORDEN 5
# ============================================================
modelo_cl5 <- aov(
vitamina_c ~ fila + columna + tratamiento,
data = datos
)
summary(modelo_cl5)
anova(modelo_cl5)
La fórmula incluye los tres efectos:
vitamina_c ~ fila + columna + tratamiento
No debe incluirse una interacción:
vitamina_c ~ fila * columna * tratamiento
porque el cuadrado latino clásico tiene una sola observación por celda y no permite estimar adecuadamente esas interacciones.
# ============================================================
# NORMALIDAD DE LOS RESIDUOS
# ============================================================
residuos <- residuals(modelo_cl5)
shapiro.test(residuos)
qqnorm(
residuos,
main = "Q-Q plot de residuos"
)
qqline(
residuos,
col = "red",
lwd = 2
)
Con 12 grados de libertad residuales, esta evaluación será más informativa que en el cuadrado de orden 3. Sin embargo, el p-valor debe interpretarse junto con el gráfico y el conocimiento del proceso.
library(car)
leveneTest(
vitamina_c ~ tratamiento,
data = datos
)
También se puede utilizar un gráfico de residuos:
plot(
modelo_cl5,
which = 1,
main = "Residuos versus valores ajustados"
)
par(mfrow = c(2, 2))
plot(modelo_cl5)
par(mfrow = c(1, 1))
Se deben buscar:
# ============================================================
# TUKEY PARA TRATAMIENTOS
# ============================================================
tukey_cl5 <- TukeyHSD(
modelo_cl5,
which = "tratamiento",
conf.level = 0.95
)
print(tukey_cl5)
plot(
tukey_cl5,
las = 1,
col = "steelblue"
)
La prueba compara los diez pares posibles entre cinco tratamientos:
\[ \binom{5}{2}=10 \]
Es decir:
library(emmeans)
medias_ajustadas <- emmeans(
modelo_cl5,
~ tratamiento
)
print(medias_ajustadas)
Comparaciones:
comparaciones_tukey <- pairs(
medias_ajustadas,
adjust = "tukey"
)
print(comparaciones_tukey)
confint(comparaciones_tukey)
Agrupamiento con letras:
library(multcomp)
library(multcompView)
grupos_tukey <- cld(
medias_ajustadas,
adjust = "tukey",
Letters = letters
)
print(grupos_tukey)
Los tratamientos que comparten una letra no presentan diferencias significativas según Tukey.
La conclusión debe responder:
¿Existen diferencias en el contenido de vitamina C entre los cinco métodos de conservación después de controlar simultáneamente la variabilidad asociada a las filas y las columnas?
# ============================================================
# ANÁLISIS COMPLETO
# CUADRADO LATINO DE ORDEN 5
# ============================================================
library(readxl)
library(openxlsx)
library(tidyverse)
library(janitor)
library(car)
library(emmeans)
library(multcomp)
library(multcompView)
# 1. Importar
datos <- read_excel(
"datos_vitamina_c_DCL.xlsx",
sheet = "Datos_Raw"
) %>%
clean_names()
str(datos)
# 2. Preparar
datos <- datos %>%
mutate(
ue = factor(ue),
fila = factor(fila),
columna = factor(columna),
tratamiento = factor(
tratamiento,
levels = c(
"T1_25C",
"T2_4C",
"T3_menos18C",
"T4_opaco",
"T5_atmosfera_reducida"
)
),
vitamina_c = as.numeric(vitamina_c_mg100m_l)
)
# 3. Verificar estructura
str(datos)
summary(datos)
with(datos, table(fila, tratamiento))
with(datos, table(columna, tratamiento))
table(datos$tratamiento)
# 4. Descriptivos
descriptivos <- datos %>%
group_by(tratamiento) %>%
summarise(
n = n(),
media = mean(vitamina_c),
mediana = median(vitamina_c),
desviacion_estandar = sd(vitamina_c),
error_estandar = sd(vitamina_c) / sqrt(n()),
minimo = min(vitamina_c),
maximo = max(vitamina_c),
cv = sd(vitamina_c) / mean(vitamina_c) * 100
)
print(descriptivos)
gráficos
ggplot(
datos,
aes(
x = tratamiento,
y = vitamina_c,
fill = tratamiento
)
) +
geom_boxplot(alpha = 0.65) +
geom_jitter(
width = 0.10,
size = 2.5,
color = "black"
) +
labs(
title = "Contenido de vitamina C por tratamiento",
x = "Método de conservación",
y = "Vitamina C (mg/100 mL)"
) +
theme_minimal() +
theme(
legend.position = "none",
axis.text.x = element_text(
angle = 25,
hjust = 1
)
)
# 5. Modelo
modelo_cl5 <- aov(
vitamina_c ~ fila + columna + tratamiento,
data = datos
)
# 6. ANOVA
summary(modelo_cl5)
anova(modelo_cl5)
# 7. Supuestos
residuos <- residuals(modelo_cl5)
shapiro.test(residuos)
qqnorm(residuos)
qqline(residuos, col = "red", lwd = 2)
leveneTest(
vitamina_c ~ tratamiento,
data = datos
)
par(mfrow = c(2, 2))
plot(modelo_cl5)
par(mfrow = c(1, 1))
# 8. Tukey
tukey_cl5 <- TukeyHSD(
modelo_cl5,
which = "tratamiento"
)
print(tukey_cl5)
plot(tukey_cl5)
# 9. Medias ajustadas
medias <- emmeans(
modelo_cl5,
~ tratamiento
)
print(medias)
comparaciones <- pairs(
medias,
adjust = "tukey"
)
print(comparaciones)
confint(comparaciones)
# 10. Letras
grupos <- cld(
medias,
adjust = "tukey",
Letters = letters
)
print(grupos)
# 11. Exportar
# Descriptivos
write.xlsx(
descriptivos,
file = "descriptivos_cuadrado_latino_orden5.xlsx",
sheetName = "Descriptivos",
rowNames = FALSE
)
# ANOVA
write.xlsx(
as.data.frame(anova(modelo_cl5)),
file = "anova_cuadrado_latino_orden5.xlsx",
sheetName = "ANOVA",
rowNames = TRUE
)
# Comparaciones
write.xlsx(
as.data.frame(comparaciones),
file = "tukey_cuadrado_latino_orden5.xlsx",
sheetName = "Tukey",
rowNames = FALSE
)
# Grupos Tukey
write.xlsx(
as.data.frame(grupos),
file = "grupos_tukey_cuadrado_latino_orden5.xlsx",
sheetName = "Grupos",
rowNames = FALSE
)
El cuadrado latino de orden 5 permite controlar dos fuentes de variación con solo 25 unidades, pero exige que:
Nota de uso: Este material ha sido elaborado por Ivone Carolina Humacata para fines académicos en la Facultad de Ciencias Agrarias – UNJu, con apoyo de herramientas de inteligencia artificial (Perplexity, Microsoft Copilot). En caso de utilizarlo, por favor cite de la siguiente manera: Humacata, I. C. (2026). Clase práctica: Diseño Cuadrado Latino (DCL). Universidad Nacional de Jujuy. Material docente elaborado con apoyo de inteligencia artificial.
⁂
https://spanish.arabpsychology.com/trm/cuadrado-latino-equilibrado-balanced-latin-square/↩︎
https://es.slideshare.net/slideshow/diseno-de-bloque-un-4-1-pptvvcccvvccccbhmmm/283732585↩︎
https://www.scribd.com/presentation/864513158/07-Latin-Square-Design-LSD-1↩︎
https://www.scribd.com/document/969550307/The-square-design-latino-2016-pdf↩︎
https://gpai.app/s/cheatsheet/xIhTFlbf/latin-square-design↩︎
https://r-statistics.co/Experimental-Design-Exercises-in-R.html↩︎
https://www.scribd.com/document/914036709/Latin-square-design↩︎
https://www.studocu.com/pe/document/institucion-educativa-jorge-basadre/matematica/diseno-cuadrado-latino/144727926?origin=related-document↩︎
https://socialsci.libretexts.org/Courses/Taft_College/Research_Methods_for_the_Social_and_Behavioral_Sciences/08:\_\_Experimental_Research/8.04:\_Repeated_Measures_Design↩︎
https://es.scribd.com/document/892662818/Diseno-contrabalanceado-o-diseno-de-cuadrado-latino↩︎