Universidad Nacional de Jujuy

Facultad de Ciencias Agrarias

Cátedra de Bioestadística y Diseño Experimental

Profesora: Ing. Agr. Ivone Carolina Humacata

Clase práctica: Diseño en Bloques Completos al Azar (DBCA)


1. Propósito de la clase

Se continuará con el ejemplo del contenido de vitamina C en jugo de naranja, pero se incorporará una fuente conocida de variabilidad: el día de análisis.

El objetivo es comparar tres métodos de conservación:

  • T1: temperatura ambiente, 25 °C.
  • T2: refrigeración, 4 °C.
  • T3: congelación, −5 °C.

La variable respuesta será el contenido de vitamina C, expresado en mg/100 mL.

A diferencia del diseño completamente aleatorizado, en este caso las unidades experimentales se agrupan en bloques homogéneos. Dentro de cada bloque deben aparecer todos los tratamientos exactamente una vez. El modelo habitual es aditivo, sin incluir interacción tratamiento × bloque cuando existe una sola observación por combinación.12


2. ¿Por qué utilizar bloques?

Supongamos que el análisis de vitamina C no puede realizarse sobre las 24 muestras exactamente en las mismas condiciones. Puede haber diferencias entre días o corridas analíticas debido a:

  • temperatura ambiental;
  • calibración de la bureta;
  • concentración del reactivo DCPIP;
  • analista responsable;
  • tiempo transcurrido desde la apertura de las muestras;
  • condiciones de iluminación;
  • pequeñas variaciones del procedimiento.

Si esas diferencias se ignoran, pueden aumentar artificialmente el error experimental. Para controlarlas, se forman bloques internamente homogéneos. En cada bloque se incluyen los tres tratamientos y se aleatoriza su orden de análisis.

Ejemplo de bloqueo

Se utilizarán:

  • 3 tratamientos;
  • 8 bloques;
  • 1 unidad de cada tratamiento por bloque.

Por lo tanto:

\[ N = t \times b = 3 \times 8 = 24 \]

donde:

  • \(N\) = total de unidades experimentales;
  • \(t\) = cantidad de tratamientos;
  • \(b\) = cantidad de bloques.

Cada tratamiento tendrá 8 repeticiones, pero cada repetición estará asociada a un bloque diferente.


3. Estructura experimental

Población

Todos los jugos de naranja pasteurizados de la marca y lote seleccionados.

Muestra

24 envases de 200 mL, procedentes del mismo lote.

Unidad experimental

Cada envase individual de jugo.

Unidad de observación

La medición del contenido de vitamina C obtenida de cada envase.

Factor de interés

Método de conservación, con tres niveles:

Código Tratamiento Temperatura
T1 Temperatura ambiente 25 °C
T2 Refrigeración 4 °C
T3 Congelación −5 °C

Factor de bloqueo

Día de análisis:

  • Bloque 1: día de análisis 1.
  • Bloque 2: día de análisis 2.
  • Bloque 8: día de análisis 8.

Cada bloque contiene:

\[ \{T1, T2, T3\} \]

Variable respuesta

Contenido de vitamina C en mg/100 mL.

Variables de control

  • marca;
  • lote;
  • volumen del envase;
  • tiempo de conservación;
  • volumen de muestra titulado;
  • método de titulación;
  • concentración del reactivo;
  • temperatura de conservación.

4. Modelo matemático

El modelo para un diseño en bloques completos al azar es:

\[ Y_{ij}=\mu+\tau_i+\beta_j+\varepsilon_{ij} \]

donde:

  • \(Y_{ij}\): contenido de vitamina c para el tratamiento \(i\) en el bloque \(j\);
  • \(\mu\): media general;
  • \(\tau_i\): efecto del método de conservación \(i\);
  • \(\beta_j\): efecto de la corrida analítica \(j\);
  • \(\varepsilon_{ij}\): error experimental aleatorio.

Los índices son:

\[ i=25°C, 4°C, -5°C \]

para los tratamientos, y:

\[ j=1,2,\ldots,8 \]

para los bloques.

Hipótesis para tratamientos

\[ H_0:\tau_1=\tau_2=\tau_3=0 \]

No existen diferencias entre los métodos de conservación.

\[ H_1: \]

Al menos un tratamiento presenta una media diferente.

Hipótesis para bloques

\[ H_0:\beta_1=\beta_2=\cdots=\beta_8=0 \]

No existen diferencias entre bloques.

El efecto de los bloques no es el objetivo principal del ensayo. Su función es controlar una fuente de variabilidad conocida.


5. Aleatorización del diseño

5.1. Principio de aleatorización

La aleatorización se realiza en dos niveles:

  1. Aleatorización de las unidades experimentales dentro de los bloques.
  2. Aleatorización de los tratamientos dentro de cada bloque.

Cada bloque debe contener exactamente un envase de cada tratamiento. No se debe asignar, por ejemplo, T1 a todas las primeras unidades, T2 a todas las segundas y T3 a todas las terceras, porque eso podría confundir el efecto del tratamiento con el orden de análisis.

Dentro de cada bloque, los tres tratamientos se mezclan aleatoriamente. La semilla permite reproducir la asignación posteriormente. La aleatorización dentro de cada bloque es el procedimiento estándar del DBCA.34


5.2. Identificación de las unidades

Primero se generan 24 envases identificados como:

UE01, UE02, ..., UE24

Se asignan aleatoriamente tres unidades a cada bloque:

Bloque Unidades
B1 UE03, UE02, UE023
B2 UE22, UE05, UE09
B3 UE17, UE04, UE12
B4 UE07, UE14, UE18
B5 UE10, UE11, UE15
B6 UE01, UE06, UE08
B7 UE16, UE20, UE21
B8 UE19, UE13, UE24

Posteriormente, dentro de cada bloque se sortean T1, T2 y T3.


5.3. Script para aleatorizar unidades y tratamientos

# ============================================================
# ALEATORIZACIÓN DE UN DISEÑO EN BLOQUES COMPLETOS AL AZAR
# Ejemplo: vitamina C en jugo de naranja
# ============================================================

library(dplyr)
library(writexl)

set.seed(20260824)

# Parámetros
tratamientos <- c(
  "T1_25C",
  "T2_4C",
  "T3_menos5C"
)

numero_bloques <- 8
tratamientos_por_bloque <- length(tratamientos)
total_unidades <- numero_bloques * tratamientos_por_bloque

# ------------------------------------------------------------
# 1. Crear las unidades como data.frame
# ------------------------------------------------------------

unidades <- data.frame(
  UE = paste0("UE", sprintf("%02d", 1:total_unidades)),
  stringsAsFactors = FALSE
)

# ------------------------------------------------------------
# 2. Aleatorizar las UE antes de formar los bloques
# ------------------------------------------------------------

unidades <- unidades[
  sample(seq_len(nrow(unidades))),
  ,
  drop = FALSE
]

# Crear bloques de tres unidades
unidades$Bloque <- rep(
  paste0("B", 1:numero_bloques),
  each = tratamientos_por_bloque
)

# Verificar
print(unidades)

# ------------------------------------------------------------
# 3. Aleatorizar tratamientos dentro de cada bloque
# ------------------------------------------------------------

plan <- unidades %>%
  group_by(Bloque) %>%
  mutate(
    Tratamiento = sample(
      tratamientos,
      size = n(),
      replace = FALSE
    ),
    Orden_Analisis = sample(
      seq_len(n()),
      size = n(),
      replace = FALSE
    )
  ) %>%
  ungroup()

# ------------------------------------------------------------
# 4. Agregar temperatura
# ------------------------------------------------------------

plan <- plan %>%
  mutate(
    Temp_Conservacion = case_when(
      Tratamiento == "T1_25C" ~ 25,
      Tratamiento == "T2_4C" ~ 4,
      Tratamiento == "T3_menos5C" ~ -5
    )
  ) %>%
  arrange(Bloque, Orden_Analisis)

# Mostrar la planificación final
print(plan)

# ------------------------------------------------------------
# 5. Comprobaciones
# ------------------------------------------------------------

cat("\nCantidad de unidades por bloque:\n")
print(table(plan$Bloque))

cat("\nTratamientos dentro de cada bloque:\n")
print(with(plan, table(Bloque, Tratamiento)))

cat("\nCantidad total por tratamiento:\n")
print(table(plan$Tratamiento))

# ------------------------------------------------------------
# 6. Exportar
# ------------------------------------------------------------

write_xlsx(
  list(
    Plan_Completo = plan,
    Unidades_Bloques = plan %>%
      arrange(Bloque) %>%
      select(Bloque, UE),
    Tratamientos_Bloques = plan %>%
      arrange(Bloque, Orden_Analisis) %>%
      select(Bloque, Orden_Analisis, UE, Tratamiento)
  ),
  "aleatorizacion_DBCA.xlsx"
)

5.4. Comprobación de la aleatorización

La siguiente tabla debe mostrar una sola observación por combinación de bloque y tratamiento:

with(plan, table(Bloque, Tratamiento))

El resultado esperado es una tabla donde cada celda tenga valor 1:

        T1_25C T2_4C T3_menos5C
B1          1      1           1
B2          1      1           1
B3          1      1           1
B4          1      1           1
B5          1      1           1
B6          1      1           1
B7          1      1           1
B8          1      1           1

Si algún bloque tiene dos unidades del mismo tratamiento o carece de otro tratamiento, la aleatorización es incorrecta y debe repetirse.


5.5. Croquis experimental

El archivo generado por R puede producir, por ejemplo, una asignación de este tipo:

Bloque Orden de análisis UE Tratamiento
B1 1 UE02 T3_menos5C
B1 2 UE01 T1_25C
B1 3 UE03 T2_4C
B2 1 UE06 T1_25C
B2 2 UE04 T2_4C
B2 3 UE05 T3_menos5C

El orden exacto dependerá de la semilla y del algoritmo de aleatorización. Lo importante es que cada tratamiento aparezca una vez en cada bloque.


6. Carga de datos

La planilla de campo puede organizarse de la siguiente manera:

UE Bloque Orden Tratamiento Temperatura Volumen DCPIP Vitamina C
UE02 B1 1 T3_menos5C −5 11.20 56.00
UE01 B1 2 T1_25C 25 8.60 43.00
UE03 B1 3 T2_4C 4 10.10 50.50

La estructura debe respetar el principio:

Una fila representa una unidad experimental y cada columna representa una variable.

Para el análisis en R, el archivo Excel se llama:

datos_vitamina_c_DBCA.xlsx

Y debe incluir, como mínimo, estas columnas:

UE
Bloque
Orden_Analisis
Tratamiento
Temp_Conservacion
Vol_DCPIP_mL
VitaminaC_mg100mL
Fecha_Analisis
Analista
Observaciones

7. Script para el análisis estadístico

7.1. Importación y preparación

# ============================================================
# ANÁLISIS ESTADÍSTICO DE UN DBCA
# Vitamina C en jugo de naranja
# ============================================================

# Instalar una sola vez, si fuera necesario
# install.packages(c(
#   "readxl", "openxlsx", tidyverse", "janitor", "car",
#   "emmeans", "agricolae", "writexl", "broom"
# ))

library(readxl)
library(tidyverse)
library(janitor)
library(car)
library(emmeans)
library(agricolae)
library(writexl)
library(broom)
library(openxlsx)

# Importar datos desde Excel
datos_raw <- read_excel(
  "datos_vitamina_c_DBCA.xlsx",
  sheet = "Datos_Raw"
)

# Limpiar nombres de columnas
datos <- datos_raw %>%
  clean_names()

# Revisar nombres originales después de clean_names()
names(datos)

# Adaptar estos nombres si la planilla fue creada con nombres diferentes
datos <- datos %>%
  rename(
    ue = ue,
    bloque = bloque,
    orden_analisis = orden_analisis,
    tratamiento = tratamiento,
    temp_conservacion = temp_conservacion_c,
    volumen_dcpip = vol_dcpip_m_l,
    vitamina_c = vitamina_c_mg100m_l
  )

# Convertir variables categóricas a factores
datos <- datos %>%
  mutate(
    ue = factor(ue),
    bloque = factor(bloque),
    tratamiento = factor(
      tratamiento,
      levels = c("T1_25C", "T2_4C", "T3_menos5C")
    ),
    orden_analisis = as.numeric(orden_analisis),
    vitamina_c = as.numeric(vitamina_c)
  )

# Revisar estructura
str(datos)
summary(datos)

# Comprobar valores faltantes
colSums(is.na(datos))

# Comprobar cantidad de unidades
nrow(datos)

# Comprobar balance del DBCA
with(datos, table(bloque, tratamiento))

7.2. Estadística descriptiva

# ============================================================
# ESTADÍSTICA DESCRIPTIVA
# ============================================================

descriptivos_tratamiento <- 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),
    coeficiente_variacion =
      desviacion_estandar / media * 100,
    minimo = min(vitamina_c),
    maximo = max(vitamina_c),
    cuartil_1 = quantile(vitamina_c, 0.25),
    cuartil_3 = quantile(vitamina_c, 0.75)
  )

print(descriptivos_tratamiento)

descriptivos_bloque <- datos %>%
  group_by(bloque) %>%
  summarise(
    n = n(),
    media = mean(vitamina_c),
    desviacion_estandar = sd(vitamina_c)
  )

print(descriptivos_bloque)

# Exportar descriptivos
write_xlsx(
  list(
    Descriptivos_Tratamiento = descriptivos_tratamiento,
    Descriptivos_Bloque = descriptivos_bloque
  ),
  "descriptivos_DBCA_vitamina_c.xlsx"
)

7.3. Gráficos exploratorios

Boxplot por tratamiento

grafico_boxplot <- ggplot(
  datos,
  aes(x = tratamiento, y = vitamina_c, fill = tratamiento)
) +
  geom_boxplot(alpha = 0.65, width = 0.6) +
  geom_jitter(
    width = 0.12,
    size = 2.4,
    color = "black",
    alpha = 0.75
  ) +
  stat_summary(
    fun = mean,
    geom = "point",
    shape = 23,
    size = 4,
    fill = "white"
  ) +
  labs(
    title = "Contenido de vitamina C por tratamiento",
    x = "Metodo de conservacion",
    y = "Vitamina C (mg/100 mL)"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

print(grafico_boxplot)

ggsave(
  "boxplot_DBCA_vitamina_c.png",
  grafico_boxplot,
  width = 8,
  height = 6,
  dpi = 300
)

Gráfico de medias por tratamiento

grafico_medias <- ggplot(
  descriptivos_tratamiento,
  aes(x = tratamiento, y = media, fill = tratamiento)
) +
  geom_col(width = 0.6, alpha = 0.7) +
  geom_errorbar(
    aes(
      ymin = media - error_estandar,
      ymax = media + error_estandar
    ),
    width = 0.2
  ) +
  labs(
    title = "Media de vitamina C por tratamiento",
    subtitle = "Barras de error: ± error estandar",
    x = "Tratamiento",
    y = "Vitamina C (mg/100 mL)"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

print(grafico_medias)

ggsave(
  "medias_DBCA_vitamina_c.png",
  grafico_medias,
  width = 8,
  height = 6,
  dpi = 300
)

Visualización por bloque

grafico_bloques <- ggplot(
  datos,
  aes(
    x = tratamiento,
    y = vitamina_c,
    group = bloque,
    color = bloque
  )
) +
  geom_line(alpha = 0.65) +
  geom_point(size = 2.5) +
  labs(
    title = "Variacion de la respuesta dentro de cada bloque",
    x = "Tratamiento",
    y = "Vitamina C (mg/100 mL)",
    color = "Bloque"
  ) +
  theme_minimal()

print(grafico_bloques)

ggsave(
  "perfil_bloques_DBCA.png",
  grafico_bloques,
  width = 8,
  height = 6,
  dpi = 300
)

Este último gráfico permite observar si hay diferencias sistemáticas entre bloques. Si todas las líneas están desplazadas hacia arriba o hacia abajo, puede existir un efecto del día de análisis.


8. Ajuste del modelo DBCA

8.1. Modelo correcto

# ============================================================
# MODELO DEL DISEÑO EN BLOQUES COMPLETOS AL AZAR
# ============================================================

modelo_dbca <- aov(
  vitamina_c ~ tratamiento + bloque,
  data = datos
)

summary(modelo_dbca)

La fórmula contiene:

vitamina_c ~ tratamiento + bloque

El orden de los términos no cambia el modelo aditivo en este caso, pero se recomienda colocar primero el tratamiento de interés:

vitamina_c ~ tratamiento + bloque

Advertencia importante

No se debe utilizar:

aov(vitamina_c ~ tratamiento * bloque, data = datos)

cuando existe una sola observación por combinación tratamiento × bloque. En ese caso no quedan grados de libertad suficientes para estimar adecuadamente una interacción independiente. Para el DBCA clásico se utiliza el modelo aditivo:

aov(respuesta ~ tratamiento + bloque, data = datos)

8.2. Tabla ANOVA

library(openxlsx)

tabla_anova <- anova(modelo_dbca)

# Convertir la tabla a data frame
tabla_anova_exportar <- as.data.frame(tabla_anova)

# Exportar a Excel con nombres de fila
write.xlsx(tabla_anova_exportar,
           file = "tabla_ANOVA_DBCA_vitamina_c.xlsx",
           sheetName = "ANOVA",
           rowNames = TRUE)

La tabla ANOVA tendrá, conceptualmente, la siguiente estructura:

Fuente de variación Grados de libertad
Tratamiento \(t-1=2\)
Bloque \(b-1=7\)
Error \((t-1)(b-1)=14\)
Total \(tb-1=23\)

El estadístico F para tratamientos evalúa si existen diferencias en la media de vitamina C después de descontar la variabilidad atribuida a los bloques.


9. Verificación de supuestos

9.1. Normalidad de los residuos

# ============================================================
# NORMALIDAD DE LOS RESIDUOS
# ============================================================

residuos <- residuals(modelo_dbca)

shapiro_resultado <- shapiro.test(residuos)

print(shapiro_resultado)

qqnorm(
  residuos,
  main = "Gráfico Q-Q de residuos del DBCA"
)

qqline(
  residuos,
  col = "red",
  lwd = 2
)

Interpretación

  • Si \(p > 0.05\), no se rechaza la normalidad de los residuos.
  • Si \(p \leq 0.05\), existe evidencia de desviación respecto de la normalidad.

La prueba debe complementarse con el gráfico Q-Q.


9.2. Homogeneidad de varianzas

# ============================================================
# HOMOCEDASTICIDAD
# ============================================================

levene_resultado <- leveneTest(
  vitamina_c ~ tratamiento,
  data = datos
)

print(levene_resultado)

plot(
  modelo_dbca,
  which = 1,
  main = "Residuos vs. valores ajustados"
)

Interpretación

  • Si \(p > 0.05\), no hay evidencia suficiente de varianzas diferentes.
  • Si \(p \leq 0.05\), se debe evaluar una transformación o una alternativa robusta.

También debe observarse el gráfico de residuos:

  • dispersión aleatoria alrededor de cero;
  • ausencia de forma de embudo;
  • ausencia de patrones sistemáticos.

9.3. Independencia

La independencia no se verifica solamente con una prueba estadística. Se garantiza principalmente mediante:

  • asignación aleatoria de tratamientos dentro de cada bloque;
  • unidades experimentales diferentes;
  • registro correcto del orden de medición;
  • ausencia de pseudorreplicación;
  • no reutilización del mismo envase como si fueran varias unidades.

9.4. Gráficos diagnósticos integrados

par(mfrow = c(2, 2))
plot(modelo_dbca)
par(mfrow = c(1, 1))

Los cuatro gráficos habituales son:

  1. residuos vs. valores ajustados;
  2. Q-Q de residuos;
  3. escala-localización;
  4. residuos vs. leverage.

10. Comparación de medias con Tukey

La prueba de Tukey se aplica para determinar qué pares de tratamientos difieren cuando el ANOVA para tratamientos resulta significativo. Controla el error familiar asociado a las comparaciones múltiples.56

10.1. Tukey con TukeyHSD()

# ============================================================
# PRUEBA DE TUKEY
# ============================================================

tukey_dbca <- TukeyHSD(
  modelo_dbca,
  which = "tratamiento",
  conf.level = 0.95
)

print(tukey_dbca)

plot(
  tukey_dbca,
  las = 1,
  col = "steelblue"
)

El resultado contiene:

  • diferencia de medias;
  • límite inferior del intervalo de confianza;
  • límite superior;
  • p-valor ajustado.

Regla de decisión

  • Si el intervalo de confianza no contiene cero, la diferencia es significativa.
  • Si el p-valor ajustado es menor que 0.05, la diferencia es significativa.
  • Si el p-valor ajustado es mayor o igual a 0.05, no se evidencia diferencia significativa.

10.2. Tukey con medias ajustadas

En un DBCA, las medias ajustadas pueden obtenerse con el paquete emmeans. Esta opción es especialmente clara para comunicar resultados.

# ============================================================
# MEDIAS AJUSTADAS Y TUKEY CON EMMEANS
# ============================================================

medias_ajustadas <- emmeans(
  modelo_dbca,
  ~ tratamiento
)

print(medias_ajustadas)

comparaciones_tukey <- pairs(
  medias_ajustadas,
  adjust = "tukey"
)

print(comparaciones_tukey)

intervalos_tukey <- confint(
  comparaciones_tukey
)

print(intervalos_tukey)

10.3. Letras de agrupamiento

# Obtener letras de agrupamiento
grupos_tukey <- cld(
  medias_ajustadas,
  adjust = "tukey",
  Letters = letters
)

print(grupos_tukey)

Según la versión instalada de emmeans, puede ser necesario cargar:

library(multcomp)
library(multcompView)

La tabla de letras permite interpretar los resultados:

Tratamiento Media ajustada Grupo
T3 53.2 a
T2 49.9 ab
T1 44.3 b

La interpretación sería:

  • tratamientos que comparten una letra no difieren significativamente;
  • tratamientos que no comparten letras presentan diferencias significativas.

10.4. Gráfico de medias ajustadas

grafico_emmeans <- plot(
  medias_ajustadas,
  comparisons = TRUE
) +
  labs(
    title = "Medias ajustadas de vitamina C",
    x = "Vitamina C (mg/100 mL)",
    y = "Tratamiento"
  ) +
  theme_minimal()

print(grafico_emmeans)

También puede realizarse un gráfico personalizado:

medias_ajustadas_df <- as.data.frame(medias_ajustadas)

ggplot(
  medias_ajustadas_df,
  aes(x = tratamiento, y = emmean)
) +
  geom_point(size = 4, color = "steelblue") +
  geom_errorbar(
    aes(ymin = lower.CL, ymax = upper.CL),
    width = 0.15,
    linewidth = 0.9
  ) +
  labs(
    title = "Medias ajustadas e intervalos de confianza",
    x = "Tratamiento",
    y = "Vitamina C (mg/100 mL)"
  ) +
  theme_minimal()

11. Tamaño del efecto y eficiencia del bloqueo

11.1. Comparación de variabilidad residual

Puede compararse la variabilidad residual del DBCA con la de un DCA:

# Modelo como diseño completamente aleatorizado
modelo_dca <- aov(
  vitamina_c ~ tratamiento,
  data = datos
)

# Modelo como DBCA
modelo_dbca <- aov(
  vitamina_c ~ tratamiento + bloque,
  data = datos
)

# Cuadrados medios del error
mse_dca <- deviance(modelo_dca) /
  df.residual(modelo_dca)

mse_dbca <- deviance(modelo_dbca) /
  df.residual(modelo_dbca)

cat("MSE del DCA:", mse_dca, "\n")
cat("MSE del DBCA:", mse_dbca, "\n")

# Porcentaje de reducción del error
reduccion_error <- (mse_dca - mse_dbca) / mse_dca * 100

cat(
  "Reduccion porcentual del error:",
  round(reduccion_error, 2),
  "%\n"
)

Si el MSE del DBCA es menor que el MSE del DCA, el bloqueo logró explicar parte de la variabilidad no deseada.

11.2. Interpretación didáctica

Un bloqueo es útil cuando:

  • los bloques son internamente homogéneos;
  • existe variabilidad entre bloques;
  • cada bloque contiene todos los tratamientos;
  • la fuente de bloqueo no es el factor de interés principal.

Si todos los bloques son prácticamente iguales, el bloqueo puede no aportar ventajas. Si los bloques son demasiado heterogéneos internamente, el diseño tampoco será eficiente.


12. Script compacto completo

El siguiente script resume todo el análisis:

# ============================================================
# SCRIPT COMPLETO: DBCA VITAMINA C
# ============================================================

# ============================================================
# ANÁLISIS ESTADÍSTICO DE UN DBCA
# Vitamina C en jugo de naranja
# ============================================================

# Instalar una sola vez, si fuera necesario
# install.packages(c(
#   "readxl", "openxlsx", tidyverse", "janitor", "car",
#   "emmeans", "agricolae", "writexl", "broom", "multcomp", "multcompView"
# ))

library(readxl)
library(tidyverse)
library(janitor)
library(car)
library(emmeans)
library(agricolae)
library(writexl)
library(broom)
library(openxlsx)
library(multcomp)
library(multcompView)

# 1. Importar datos desde Excel
datos_raw <- read_excel(
  "datos_vitamina_c_DBCA.xlsx",
  sheet = "Datos_Raw"
)

# Limpiar nombres de columnas
datos <- datos_raw %>%
  clean_names()

# Revisar nombres originales después de clean_names()
names(datos)

# Adaptar estos nombres si la planilla fue creada con nombres diferentes
datos <- datos %>%
  rename(
    ue = ue,
    bloque = bloque,
    orden_analisis = orden_analisis,
    tratamiento = tratamiento,
    temp_conservacion = temp_conservacion_c,
    volumen_dcpip = vol_dcpip_m_l,
    vitamina_c = vitamina_c_mg100m_l
  )

# Convertir variables categóricas a factores
datos <- datos %>%
  mutate(
    ue = factor(ue),
    bloque = factor(bloque),
    tratamiento = factor(
      tratamiento,
      levels = c("T1_25C", "T2_4C", "T3_menos5C")
    ),
    orden_analisis = as.numeric(orden_analisis),
    vitamina_c = as.numeric(vitamina_c)
  )

# 2. Revisar estructura
str(datos)
summary(datos)

# Comprobar valores faltantes
colSums(is.na(datos))

# Comprobar cantidad de unidades
nrow(datos)

# Comprobar balance del DBCA
with(datos, table(bloque, tratamiento))


# ============================================================
# ESTADÍSTICA DESCRIPTIVA
# ============================================================

# 3. Estadística descriptiva
descriptivos_tratamiento <- 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),
    coeficiente_variacion =
      desviacion_estandar / media * 100,
    minimo = min(vitamina_c),
    maximo = max(vitamina_c),
    cuartil_1 = quantile(vitamina_c, 0.25),
    cuartil_3 = quantile(vitamina_c, 0.75)
  )

print(descriptivos_tratamiento)

descriptivos_bloque <- datos %>%
  group_by(bloque) %>%
  summarise(
    n = n(),
    media = mean(vitamina_c),
    desviacion_estandar = sd(vitamina_c)
  )

print(descriptivos_bloque)

# Exportar descriptivos
write_xlsx(
  list(
    Descriptivos_Tratamiento = descriptivos_tratamiento,
    Descriptivos_Bloque = descriptivos_bloque
  ),
  "descriptivos_DBCA_vitamina_c.xlsx"
)


# 4. Graficos exploratorios

# Boxplot por tratamiento
grafico_boxplot <- ggplot(
  datos,
  aes(x = tratamiento, y = vitamina_c, fill = tratamiento)
) +
  geom_boxplot(alpha = 0.65, width = 0.6) +
  geom_jitter(
    width = 0.12,
    size = 2.4,
    color = "black",
    alpha = 0.75
  ) +
  stat_summary(
    fun = mean,
    geom = "point",
    shape = 23,
    size = 4,
    fill = "white"
  ) +
  labs(
    title = "Contenido de vitamina C por tratamiento",
    x = "Metodo de conservacion",
    y = "Vitamina C (mg/100 mL)"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

print(grafico_boxplot)


ggsave(
  "boxplot_DBCA_vitamina_c.png",
  grafico_boxplot,
  width = 8,
  height = 6,
  dpi = 300
)

# grafico de medias por tratamiento
grafico_medias <- ggplot(
  descriptivos_tratamiento,
  aes(x = tratamiento, y = media, fill = tratamiento)
) +
  geom_col(width = 0.6, alpha = 0.7) +
  geom_errorbar(
    aes(
      ymin = media - error_estandar,
      ymax = media + error_estandar
    ),
    width = 0.2
  ) +
  labs(
    title = "Media de vitamina C por tratamiento",
    subtitle = "Barras de error: ± error estandar",
    x = "Tratamiento",
    y = "Vitamina C (mg/100 mL)"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

print(grafico_medias)

ggsave(
  "medias_DBCA_vitamina_c.png",
  grafico_medias,
  width = 8,
  height = 6,
  dpi = 300
)

# visualizacion por bloque
grafico_bloques <- ggplot(
  datos,
  aes(
    x = tratamiento,
    y = vitamina_c,
    group = bloque,
    color = bloque
  )
) +
  geom_line(alpha = 0.65) +
  geom_point(size = 2.5) +
  labs(
    title = "Variacion de la respuesta dentro de cada bloque",
    x = "Tratamiento",
    y = "Vitamina C (mg/100 mL)",
    color = "Bloque"
  ) +
  theme_minimal()

print(grafico_bloques)

ggsave(
  "perfil_bloques_DBCA.png",
  grafico_bloques,
  width = 8,
  height = 6,
  dpi = 300
)

# ============================================================
# MODELO DEL DISEÑO EN BLOQUES COMPLETOS AL AZAR
# ============================================================

# 5. Modelo DBCA

modelo_dbca <- aov(
  vitamina_c ~ tratamiento + bloque,
  data = datos
)

summary(modelo_dbca)

# 6. ANOVA
library(openxlsx)
tabla_anova <- anova(modelo_dbca)

# Convertir la tabla a data frame
tabla_anova_exportar <- as.data.frame(tabla_anova)

# Exportar a Excel con nombres de fila
write.xlsx(tabla_anova_exportar,
           file = "tabla_ANOVA_DBCA_vitamina_c.xlsx",
           sheetName = "ANOVA",
           rowNames = TRUE)

# ============================================================
# NORMALIDAD DE LOS RESIDUOS
# ============================================================

# 7. Residuos
residuos <- residuals(modelo_dbca)

# 8. Normalidad
shapiro_resultado <- shapiro.test(residuos)

print(shapiro_resultado)

qqnorm(
  residuos,
  main = "Gráfico Q-Q de residuos del DBCA"
)

qqline(
  residuos,
  col = "red",
  lwd = 2
)

# ============================================================
# HOMOCEDASTICIDAD
# ============================================================

# 9. Homogeneidad de varianzas
levene_resultado <- leveneTest(
  vitamina_c ~ tratamiento,
  data = datos
)

print(levene_resultado)

plot(
  modelo_dbca,
  which = 1,
  main = "Residuos vs. valores ajustados"
)


# 10. grafico diagnosticos integrados
par(mfrow = c(2, 2))
plot(modelo_dbca)
par(mfrow = c(1, 1))

# ============================================================
# PRUEBA DE TUKEY
# ============================================================

# 11. Tukey
tukey_dbca <- TukeyHSD(
  modelo_dbca,
  which = "tratamiento",
  conf.level = 0.95
)

print(tukey_dbca)

plot(
  tukey_dbca,
  las = 1,
  col = "steelblue"
)

# ============================================================
# MEDIAS AJUSTADAS Y TUKEY CON EMMEANS
# ============================================================

# 12. Medias ajustadas
medias_ajustadas <- emmeans(
  modelo_dbca,
  ~ tratamiento
)

print(medias_ajustadas)

# 13. Comparaciones de Tukey 
comparaciones_tukey <- pairs(
  medias_ajustadas,
  adjust = "tukey"
)

print(comparaciones_tukey)

intervalos_tukey <- confint(
  comparaciones_tukey
)

print(intervalos_tukey)

# 14. Obtener letras de agrupamiento
library(multcomp)
library(multcompView)

grupos_tukey <- cld(
  medias_ajustadas,
  adjust = "tukey",
  Letters = letters
)

print(grupos_tukey)

# 15. grafico de medias ajustadas
grafico_emmeans <- plot(
  medias_ajustadas,
  comparisons = TRUE
) +
  labs(
    title = "Medias ajustadas de vitamina C",
    x = "Vitamina C (mg/100 mL)",
    y = "Tratamiento"
  ) +
  theme_minimal()

print(grafico_emmeans)


# grafico personalizado
medias_ajustadas_df <- as.data.frame(medias_ajustadas)

ggplot(
  medias_ajustadas_df,
  aes(x = tratamiento, y = emmean)
) +
  geom_point(size = 4, color = "steelblue") +
  geom_errorbar(
    aes(ymin = lower.CL, ymax = upper.CL),
    width = 0.15,
    linewidth = 0.9
  ) +
  labs(
    title = "Medias ajustadas e intervalos de confianza",
    x = "Tratamiento",
    y = "Vitamina C (mg/100 mL)"
  ) +
  theme_minimal()


# 16. Eficiencia del bloqueo
# Modelo como diseño completamente aleatorizado
modelo_dca <- aov(
  vitamina_c ~ tratamiento,
  data = datos
)

# Modelo como DBCA
modelo_dbca <- aov(
  vitamina_c ~ tratamiento + bloque,
  data = datos
)

# Cuadrados medios del error
mse_dca <- deviance(modelo_dca) /
  df.residual(modelo_dca)

mse_dbca <- deviance(modelo_dbca) /
  df.residual(modelo_dbca)

cat("MSE del DCA:", mse_dca, "\n")
cat("MSE del DBCA:", mse_dbca, "\n")

# Porcentaje de reducción del error
reduccion_error <- (mse_dca - mse_dbca) / mse_dca * 100

cat(
  "Reduccion porcentual del error:",
  round(reduccion_error, 2),
  "%\n"
)


Idea central de la clase

En un DBCA, la pregunta no es únicamente:

“¿Qué tratamiento tiene la media más alta?”

La pregunta correcta es:

“¿Existen diferencias entre los métodos de conservación una vez que se ha controlado la variabilidad producida por los días o bloques de análisis?”

Esa es la principal ventaja del diseño: separar, en la medida de lo posible, la variación atribuible al tratamiento de la variación producida por una fuente conocida de heterogeneidad. 7891011121314151617

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 en Bloques Completos al Azar (DBCA). Universidad Nacional de Jujuy. Material docente elaborado con apoyo de inteligencia artificial.


  1. https://r-statistics.co/Randomized-Complete-Block-Design-in-R.html↩︎

  2. https://metricgate.com/docs/randomized-block-design/↩︎

  3. https://www.rdocumentation.org/packages/randomizr/versions/1.0.1/topics/block_ra↩︎

  4. https://r-statistics.co/Experimental-Design-Exercises-in-R.html↩︎

  5. https://wpd.ugr.es/~bioestad/diseno-estadistico-de-experimentos/tema-2/↩︎

  6. https://r-statistics.co/Randomized-Complete-Block-Design-in-R.html↩︎

  7. https://es.scribd.com/document/900367246/Diseno-de-bloques-completos-al-azar-con-arreglo-factorial-Kempthorne-1952↩︎

  8. https://es.scribd.com/document/974168468/Unidad-IV↩︎

  9. https://samuelbfernandes.github.io/agst50104-lectures/lecture06_week04.html↩︎

  10. https://r-statistics.co/Clinical-Trials-Design-in-R.html↩︎

  11. https://www.slideshare.net/slideshow/comprehensive-guide-to-randomized-complete-block-design-rcbd-in-experimental-statistics/286903907↩︎

  12. https://pt.scribd.com/document/801151228/karen-colaborativo-fase-2↩︎

  13. https://www.scribd.com/document/961373343/randomizeR↩︎

  14. https://cran.r-project.org/web/packages/randotools/refman/randotools.html↩︎

  15. https://cran.r-project.org/web/packages/TukeyC/TukeyC.pdf↩︎

  16. https://www.rdocumentation.org/packages/psych/versions/2.6.1/topics/block.random↩︎

  17. https://www.rdocumentation.org/packages/pwr4exp/versions/1.0.1/topics/df.rcbd↩︎