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 Completamente Aleatorizado (DCA)


🎯 Objetivos de la clase

Al finalizar esta clase, los estudiantes serán capaces de:

  1. Calcular el tamaño muestral necesario por tratamiento usando análisis de potencia estadística en R
  2. Planificar y ejecutar un diseño completamente aleatorizado
  3. Registrar datos en planillas de campo y digitales
  4. Importar datos desde Excel a RStudio
  5. Realizar análisis estadístico completo: descriptivo, verificación de supuestos, ANOVA y pruebas post-hoc
  6. Interpretar y comunicar resultados científicamente

📋 Parte 1: Planificación del Diseño Experimental

Contexto del problema

Somos un laboratorio de control de calidad de una empresa de jugos y queremos evaluar cómo diferentes métodos de conservación afectan el contenido de vitamina C (ácido ascórbico) en jugo de naranja comercial durante 7 días de almacenamiento.

Paso 1.1: Definición de elementos del diseño

Población: Todos los jugos de naranja pasteurizados comercializados en la empresa

Muestra: Envases de jugo de naranja de una marca específica, mismo lote de producción

Unidad experimental: Cada envase individual de 200 mL de jugo de naranja

Unidad de observación: La medición del contenido de vitamina C (mg/100 mL) en cada envase

Tratamientos (factor: método de conservación, 3 niveles):

  • T1: Temperatura ambiente (25°C)
  • T2: Refrigeración (4°C)
  • T3: Congelación (-5°C)

Variable dependiente: Contenido de vitamina C en mg/100 mL (cuantitativa continua)

Variables de control:

  • Marca y lote del jugo
  • Volumen del envase (200 mL)
  • Tiempo de almacenamiento (7 días)
  • Método de análisis (titulación con 2,6-diclorofenolindofenol)
  • Persona que realiza las mediciones

Paso 1.2: Cálculo del tamaño muestral con análisis de potencia en R

Antes de comenzar cualquier experimento, debemos determinar cuántas repeticiones necesitamos por tratamiento para tener suficiente poder estadístico para detectar diferencias si existen.

Conceptos clave de potencia estadística

  • Potencia estadística (1-β): Probabilidad de detectar un efecto real cuando existe (rechazar correctamente H₀). Convención: 0.80 (80%) mínimo.
  • Nivel de significación (α): Probabilidad de error Tipo I (falso positivo). Convención: 0.05 (5%)
  • Tamaño del efecto (f de Cohen): Magnitud estandarizada del efecto que esperamos detectar. Para ANOVA:
    • f = 0.10 → efecto pequeño
    • f = 0.25 → efecto mediano
    • f = 0.40 → efecto grande
  • k: Número de tratamientos/grupos

¿Cómo estimamos el tamaño del efecto?

Opción A - Basado en literatura: Buscamos estudios similares y calculamos f a partir de las medias y desviaciones reportadas.

Opción B - Estudio piloto: Realizamos un pequeño ensayo con 3-5 repeticiones por tratamiento y estimamos f.

Opción C - Convención de Cohen: Si no tenemos información previa, usamos f = 0.25 (efecto mediano) como punto de partida conservador.

Opción D - Cálculo a partir de diferencias esperadas: Si esperamos que T1 tenga media 50 mg/100mL, T2 tenga 45 mg/100mL, T3 tenga 40 mg/100mL, con desviación estándar esperada de 5 mg/100mL, podemos calcular f.

Fórmula para calcular f (tamaño del efecto para ANOVA):

\[ f = \sqrt{\frac{\sum_{i=1}^{k}(\mu_i - \mu)^2 / k}{\sigma^2}} \]

Donde:

  • \(\mu_i\) = media esperada del tratamiento i
  • \(\mu\) = media general
  • \(\sigma\) = desviación estándar dentro de los grupos
  • \(k\) = número de tratamientos

Paso 1.3: Script R para cálculo de tamaño muestral

Abrimos RStudio y creamos un nuevo script llamado 01_calculo_poder.R:

# ============================================================================
# CÁLCULO DE TAMAÑO MUESTRAL CON ANÁLISIS DE POTENCIA
# Diseño: Completamente Aleatorizado (DCA)
# Experimento: Efecto de conservación en vitamina C de jugo de naranja
# ============================================================================

# Instalar y cargar paquete pwr (solo la primera vez)
# install.packages("pwr")
library(pwr)

# ----------------------------------------------------------------------------
# OPCIÓN 1: Cálculo basado en convención de Cohen (efecto mediano)
# ----------------------------------------------------------------------------

# Parámetros
k <- 3  # Número de tratamientos (T1, T2, T3)
f <- 0.25  # Tamaño del efecto mediano (convención de Cohen para ANOVA)
sig.level <- 0.05  # Nivel de significación (5%)
power <- 0.80  # Potencia deseada (80%)

# Calcular tamaño muestral por grupo
resultado <- pwr.anova.test(k = k, f = f, sig.level = sig.level, power = power)

# Mostrar resultados
print("=== ANÁLISIS DE POTENCIA - EFECTO MEDIANO ===")
print(resultado)
print(paste("Repeticiones por tratamiento (redondeado hacia arriba):", 
            ceiling(resultado$n)))
print(paste("Total de unidades experimentales:", 
            ceiling(resultado$n) * k))

# ----------------------------------------------------------------------------
# OPCIÓN 2: Cálculo basado en diferencias esperadas (más preciso)
# ----------------------------------------------------------------------------

# Supongamos que, basado en literatura o estudio piloto, esperamos:
# T1 (25°C): media = 45 mg/100mL
# T2 (4°C):  media = 50 mg/100mL
# T3 (-5°C): media = 52 mg/100mL
# Desviación estándar dentro de grupos: σ = 4 mg/100mL

# Calcular medias
mu1 <- 45
mu2 <- 50
mu3 <- 52
mu_general <- mean(c(mu1, mu2, mu3))  # Media general
sigma <- 4  # Desviación estándar esperada

# Calcular tamaño del efecto f
varianza_entre <- sum((c(mu1, mu2, mu3) - mu_general)^2) / k
f_calculado <- sqrt(varianza_entre / sigma^2)

print("=== TAMAÑO DEL EFECTO CALCULADO ===")
print(paste("Media general:", round(mu_general, 2), "mg/100mL"))
print(paste("Desviación estándar esperada:", sigma, "mg/100mL"))
print(paste("Tamaño del efecto f calculado:", round(f_calculado, 3)))

# Recalcular tamaño muestral con f calculado
resultado_realista <- pwr.anova.test(k = k, f = f_calculado, 
                                      sig.level = sig.level, power = power)

print("=== ANÁLISIS DE POTENCIA - BASADO EN DIFERENCIAS ESPERADAS ===")
print(resultado_realista)
print(paste("Repeticiones por tratamiento (redondeado hacia arriba):", 
            ceiling(resultado_realista$n)))
print(paste("Total de unidades experimentales:", 
            ceiling(resultado_realista$n) * k))

# ----------------------------------------------------------------------------
# OPCIÓN 3: Análisis de sensibilidad - ¿Qué pasa si cambiamos la potencia?
# ----------------------------------------------------------------------------

# Crear secuencia de potencias desde 0.70 hasta 0.95
potencias <- seq(0.70, 0.95, by = 0.05)
n_por_potencia <- numeric(length(potencias))

for(i in 1:length(potencias)){
  n_por_potencia[i] <- pwr.anova.test(k = k, f = f_calculado, 
                                       sig.level = sig.level, 
                                       power = potencias[i])$n
}

# Crear tabla resumen
tabla_sensibilidad <- data.frame(
  Potencia = potencias,
  n_por_tratamiento = round(n_por_potencia, 1),
  Total_unidades = round(n_por_potencia * k, 1)
)

print("=== ANÁLISIS DE SENSIBILIDAD ===")
print(tabla_sensibilidad)

# Gráfico de sensibilidad
library(ggplot2)

ggplot(tabla_sensibilidad, aes(x = Potencia, y = Total_unidades)) +
  geom_line(color = "steelblue", linewidth = 1.5) +
  geom_point(color = "steelblue", size = 3) +
  geom_hline(yintercept = ceiling(resultado_realista$n) * k, 
             linetype = "dashed", color = "red") +
  annotate("text", x = 0.85, y = ceiling(resultado_realista$n) * k + 2,
           label = paste("Punto elegido:\nTotal =", 
                        ceiling(resultado_realista$n) * k, "unidades"),
           color = "red", hjust = 0) +
  labs(title = "Relación entre Potencia Estadística y Tamaño Muestral Total",
       subtitle = "DCA con 3 tratamientos, f = 0.391",
       x = "Potencia Estadística (1 - β)",
       y = "Total de Unidades Experimentales",
       caption = "Línea roja punteada: punto seleccionado (potencia = 0.80)") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 14),
        plot.subtitle = element_text(size = 11))

# Guardar gráfico
ggsave("grafico_potencia_vs_n.png", width = 8, height = 5, dpi = 300)

# ----------------------------------------------------------------------------
# DECISIÓN FINAL
# ----------------------------------------------------------------------------

n_final <- ceiling(resultado_realista$n)  # Redondear hacia arriba siempre
total_unidades <- n_final * k

print("=== DECISIÓN DE DISEÑO ===")
print(paste("Número de tratamientos (k):", k))
print(paste("Repeticiones por tratamiento (n):", n_final))
print(paste("Total de unidades experimentales (N):", total_unidades))
print(paste("Potencia estadística alcanzada:", 
            round(resultado_realista$power, 3)))
print(paste("Nivel de significación:", sig.level))
print(paste("Tamaño del efecto detectable (f):", round(f_calculado, 3)))

# Guardar parámetros para uso posterior
parametros <- list(
  k = k,
  n_por_tratamiento = n_final,
  total_unidades = total_unidades,
  f = f_calculado,
  sig.level = sig.level,
  power = resultado_realista$power
)

save(parametros, file = "parametros_diseno.RData")
print("Parámetros guardados en 'parametros_diseno.RData'")

Paso 1.4: Interpretación de resultados del análisis de potencia

Al ejecutar el script anterior, obtendremos resultados como:

=== ANÁLISIS DE POTENCIA - BASADO EN DIFERENCIAS ESPERADAS ===

     Balanced one-way analysis of variance power calculation 

              k = 3
              n = 7.672891    ← ¡IMPORTANTE! Necesitamos 7.67 por grupo
              f = 0.390625    ← Tamaño del efecto calculado
      sig.level = 0.05
          power = 0.8         ← Potencia deseada

NOTE: n is number in each group

Repeticiones por tratamiento (redondeado hacia arriba): 8
Total de unidades experimentales: 24

Interpretación:

  • El cálculo nos indica que necesitamos n = 7.67 observaciones por tratamiento
  • Como no podemos tener fracciones de unidades experimentales, redondeamos SIEMPRE hacia arriba
  • Decisión final: 8 repeticiones por tratamiento × 3 tratamientos = 24 unidades experimentales totales
  • Con este diseño, tenemos 80% de potencia para detectar un efecto de tamaño f = 0.39 si existe realmente
  • El nivel de significación es 5% (probabilidad de falso positivo)

¿Por qué es importante este cálculo?

  • Subdimensionar: Si usáramos solo 3-4 repeticiones, tendríamos baja potencia (~50-60%) y podríamos no detectar diferencias reales (error Tipo II)
  • Sobredimensionar: Si usáramos 20 repeticiones por tratamiento, desperdiciaríamos recursos (60 unidades totales) sin ganancia proporcional en información
  • Justificación científica: Este cálculo nos permite justificar el tamaño muestral en el informe y ante revisores

📋 Parte 2: Ejecución del ensayo experimental

Paso 2.1: Lista de materiales

Basado en el cálculo de potencia, necesitamos:

    • Ambiente: 25°C (mesada de laboratorio)
    • Refrigeración: 4°C (heladera)
    • Congelación: -5°C (freezer)
    • Ácido 2,6-diclorofenolindofenol (DCPIP)
    • Ácido oxálico 1%
    • Solución estándar de ácido ascórbico 0.1 mg/mL
    • Bureta de 25 mL
    • Erlenmeyers de 250 mL
    • Pipetas volumétricas
    • Vasos de precipitado

Paso 2.2: Protocolo de aleatorización

Importante: La aleatorización es importante para evitar sesgos y cumplir el supuesto de independencia.

Creamos un segundo script en RStudio: 02_aleatorizacion.R

# ============================================================================
# ALEATORIZACIÓN DEL DISEÑO COMPLETAMENTE ALEATORIZADO
# ============================================================================

# Cargar parámetros guardados
load("parametros_diseno.RData")

# Verificar parámetros
print(parametros)

# ----------------------------------------------------------------------------
# Crear lista de unidades experimentales
# ----------------------------------------------------------------------------

# Identificadores únicos para cada unidad experimental
unidades <- paste0("UE", sprintf("%02d", 1:parametros$total_unidades))

# Crear vector de tratamientos (8 de cada uno)
tratamientos <- rep(c("T1_25C", "T2_4C", "T3_menos5C"), 
                    each = parametros$n_por_tratamiento)

# Verificar balance
table(tratamientos)

# ----------------------------------------------------------------------------
# Aleatorizar asignación de tratamientos a unidades
# ----------------------------------------------------------------------------

# Fijar semilla para reproducibilidad
set.seed(2026)  # Cualquier número entero

# Aleatorizar el orden de los tratamientos
tratamientos_aleatorizados <- sample(tratamientos)

# Crear tabla de asignación
asignacion <- data.frame(
  Unidad_Experimental = unidades,
  Tratamiento_Asignado = tratamientos_aleatorizados,
  Orden_Ejecucion = 1:parametros$total_unidades
)

# Ver distribución después de aleatorizar
print("=== DISTRIPUCIÓN DE TRATAMIENTOS DESPUÉS DE ALEATORIZAR ===")
print(table(asignacion$Tratamiento_Asignado))

# ----------------------------------------------------------------------------
# Guardar planilla de aleatorización para imprimir y usar en campo
# ----------------------------------------------------------------------------

# Ordenar por unidad experimental para facilitar lectura
asignacion <- asignacion[order(asignacion$Unidad_Experimental), ]

# Agregar columnas para registro manual
asignacion$Fecha_Inicio <- ""
asignacion$Fecha_Fin <- ""
asignacion$Temperatura_Real <- ""
asignacion$Observaciones <- ""
asignacion$Responsable <- ""

# Exportar a Excel para imprimir y llevar al laboratorio
# install.packages("writexl")
library(writexl)

write_xlsx(asignacion, "planilla_aleatorizacion.xlsx")

print("Planilla de aleatorización guardada como 'planilla_aleatorizacion.xlsx'")
print("IMPRIMIR esta planilla y llevar al laboratorio")

# ----------------------------------------------------------------------------
# Visualizar aleatorización
# ----------------------------------------------------------------------------

library(ggplot2)

ggplot(asignacion, aes(x = Orden_Ejecucion, y = Unidad_Experimental, 
                       fill = Tratamiento_Asignado)) +
  geom_tile(color = "white", size = 0.5) +
  scale_fill_brewer(palette = "Set2", 
                    labels = c("T1: 25°C", "T2: 4°C", "T3: -18°C")) +
  labs(title = "Esquema de aleatorización - Diseño Completamente Aleatorizado",
       subtitle = paste("24 unidades experimentales, 8 repeticiones por tratamiento"),
       x = "Orden de Ejecución",
       y = "Unidad Experimental",
       fill = "Tratamiento") +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 8),
        plot.title = element_text(face = "bold", size = 14),
        legend.title = element_text(face = "bold"))

ggsave("esquema_aleatorizacion.png", width = 10, height = 6, dpi = 300)

# ----------------------------------------------------------------------------
# Generar lista de trabajo por tratamiento (para organizar el laboratorio)
# ----------------------------------------------------------------------------

# Lista por tratamiento
for(trat in unique(asignacion$Tratamiento_Asignado)){
  cat("\n=== ", trat, " ===\n")
  unidades_trat <- asignacion$Unidad_Experimental[asignacion$Tratamiento_Asignado == trat]
  cat("Unidades:", paste(unidades_trat, collapse = ", "), "\n")
  cat("Total:", length(unidades_trat), "unidades\n")
}

Paso 2.3: Planilla de campo para registro manual

Importante: Los datos deben registrarse inmediatamente durante la ejecución del experimento, no de memoria al final.

Planilla de Campo Impresa (llevar al laboratorio):

================================================================================
                    PLANILLA DE CAMPO - REGISTRO DE DATOS
                    Vitamina C en Jugo de Naranja
================================================================================

Fecha de inicio: _______________    Responsable: _________________________

Condiciones ambientales:
- Temperatura laboratorio: ______ °C
- Humedad relativa: ______ %

--------------------------------------------------------------------------------
UNIDAD | TRATAMIENTO | FECHA INI | FECHA FIN | VOL. MUESTRA | OBSERVACIONES
--------------------------------------------------------------------------------
UE01   |             |           |           |              |
UE02   |             |           |           |              |
UE03   |             |           |           |              |
... (continuar hasta UE24)
--------------------------------------------------------------------------------

================================================================================
                    REGISTRO DE MEDICIONES DE VITAMINA C
                    Método: Titulación con DCPIP
================================================================================

Fecha de análisis: _______________    Analista: _________________________

Solución estándar de ácido ascórbico: ______ mg/mL
Volumen de muestra titulado: ______ mL
Factor de la bureta: ______

--------------------------------------------------------------------------------
UE   | Trat. | Vol. DCPIP (mL) | Cálculo | Vit. C (mg/100mL) | Iniciales
--------------------------------------------------------------------------------
UE01 |       |                 |         |                   |
UE02 |       |                 |         |                   |
UE03 |       |                 |         |                   |
... (24 filas)
--------------------------------------------------------------------------------

Cálculo:
Vitamina C (mg/100mL) = (Vol. DCPIP × Factor × 100) / Vol. muestra

================================================================================

Paso 2.4: Protocolo experimental

Día 0 - Recepción y aleatorización:

  1. Verificar que los 24 envases sean del mismo lote (revisar fecha de vencimiento y código de lote)
  2. Rotular cada envase con el código de unidad experimental (UE01 a UE24)
  3. Usar la planilla de aleatorización generada en R para asignar tratamientos
  4. Colocar cada envase en su condición de conservación asignada
  5. Registrar fecha y hora de inicio
  6. Verificar temperaturas de las cámaras (termómetro calibrado)

Días 1-6 - Monitoreo:

  1. Verificar diariamente que las temperaturas se mantengan estables
  2. Registrar cualquier incidencia (cortes de energía, apertura de puertas, etc.)
  3. No abrir los envases hasta el día 7

Día 7 - Análisis de vitamina C:

  1. Preparar reactivos (solución de DCPIP, ácido oxálico 1%)
  2. Estandarizar solución de DCPIP con ácido ascórbico patrón
  3. Para cada unidad experimental (en orden aleatorio para evitar sesgo temporal):
    • Homogeneizar el jugo (invertir suavemente 5 veces)
    • Pipetear 10 mL de jugo
    • Diluir con 10 mL de ácido oxálico 1%
    • Titular con DCPIP hasta aparición de color rosa persistente (30 segundos)
    • Registrar volumen de DCPIP gastado
    • Calcular vitamina C usando la fórmula:

\[ \text{Vit. C (mg/100mL)} = \frac{V_{DCPIP} \times F \times 100}{V_{muestra}} \]

Donde:
- \(V_{DCPIP}\) = volumen de DCPIP gastado (mL)
- \(F\) = factor de la solución de DCPIP (mg ácido ascórbico/mL DCPIP)
- \(V_{muestra}\) = volumen de muestra (mL)
4. Registrar todos los valores en la planilla de campo con iniciales del analista


📋 Parte 3: Carga y organización de datos

Paso 3.1: Planilla Excel para carga de datos

Después de completar el ensayo, creamos una planilla Excel estructurada para importar a R.

Nombre del archivo: datos_vitamina_c.xlsx

Estructura de la hoja “Datos_Raw”:

UE Tratamiento Temp_Conservacion Vol_DCPIP_mL VitaminaC_mg100mL Fecha_Analisis Analista Observaciones
UE01 T1_25C 25 12.5 45.2 15/08/2026 AB Sin novedades
UE02 T2_4C 4 14.1 51.0 15/08/2026 AB Sin novedades
UE03 T3_menos18C -18 14.8 53.5 15/08/2026 AB Sin novedades

Reglas de oro para la carga de datos:

  1. Una fila = una unidad experimental (principio de “tidy data”)
  2. Una columna = una variable (no combinar variables en una celda)
  3. Sin celdas combinadas (R no las puede leer)
  4. Sin filas ni columnas vacías intermedias
  5. Nombres de columnas sin espacios (usar guiones bajos: VitaminaC_mg100mL)
  6. Nombres de columnas sin caracteres especiales (evitar ñ, acentos, símbolos)
  7. Datos numéricos sin unidades en la celda (la unidad va en el nombre de la columna)
  8. Una sola hoja para los datos principales (R lee mejor así)
  9. Guardar como .xlsx (no .xls antiguo)

Hoja adicional “Diccionario”:

Variable Tipo Descripción Unidad Rango válido
UE Caracter Identificador único de unidad experimental - UE01-UE24
Tratamiento Factor Método de conservación - T1_25C, T2_4C, T3_menos5C
Temp_Conservacion Numérica Temperatura de conservación °C -20 a 30
Vol_DCPIP_mL Numérica Volumen de DCPIP gastado en titulación mL 0-50
VitaminaC_mg100mL Numérica Contenido de vitamina C calculado mg/100mL 0-100
Fecha_Analisis Fecha Fecha de realización del análisis dd/mm/yyyy -
Analista Caracter Iniciales del analista - -
Observaciones Caracter Notas relevantes - -

Paso 3.2: Importar datos desde Excel a R

Creamos el script 03_importar_datos.R:

# ============================================================================
# IMPORTACIÓN DE DATOS
# ============================================================================

# Instalar paquetes necesarios (solo la primera vez)
# install.packages("readxl")
# install.packages("tidyverse")
# install.packages("janitor")

# Cargar librerías
library(readxl)
library(tidyverse)
library(janitor)

# ----------------------------------------------------------------------------
# Importar datos desde Excel
# ----------------------------------------------------------------------------

# Establecer directorio de trabajo (cambiar según tu ruta)
# setwd("C:/Users/TuUsuario/Documentos/Diseño_Experimental")

# Leer archivo Excel
datos_raw <- read_excel("datos_vitamina_c.xlsx", sheet = "Datos_Raw")

# Ver estructura inicial
str(datos_raw)
dim(datos_raw)
head(datos_raw)

# ----------------------------------------------------------------------------
# Limpieza de datos
# ----------------------------------------------------------------------------

# Renombrar columnas para mayor claridad
datos <- datos_raw %>%
  rename(
    ue = UE,
    tratamiento = Tratamiento,
    temp_Conservacion = Temp_Conservacion,
    vol_dcpip_ml = Vol_DCPIP_mL,
    vitamina_c = VitaminaC_mg100mL,
    fecha_analisis = Fecha_Analisis,
    analista = Analista,
    observaciones = Observaciones
  )


# ----------------------------------------------------------------------------
# Verificar tipos de variables
# ----------------------------------------------------------------------------

# Convertir tratamiento a factor (variable categórica)
datos$tratamiento <- as.factor(datos$tratamiento)

# Convertir ue a factor (identificador, no variable numérica)
datos$ue <- as.factor(datos$ue)

# Convertir analista a factor
datos$analista <- as.factor(datos$analista)

# Verificar niveles del factor tratamiento
levels(datos$tratamiento)

# ----------------------------------------------------------------------------
# Verificación de calidad de datos
# ----------------------------------------------------------------------------

# Verificar valores faltantes
print("=== VALORES FALTANTES POR COLUMNA ===")
colSums(is.na(datos))

# Verificar valores duplicados
print("=== ¿HAY UNIDADES EXPERIMENTALES DUPLICADAS? ===")
duplicados <- datos[duplicated(datos$ue), ]
if(nrow(duplicados) > 0){
  print("ALERTA: Hay unidades duplicadas:")
  print(duplicados)
} else {
  print("OK: No hay duplicados")
}

# Verificar rangos de valores (control de calidad)
summary(datos)

# Verificar que todas las unidades estén presentes
print(paste("Unidades esperadas:", 24))
print(paste("Unidades en datos:", nrow(datos)))
print(paste("Unidades únicas:", length(unique(datos$ue))))

# ----------------------------------------------------------------------------
# Guardar datos limpios para análisis posterior
# ----------------------------------------------------------------------------

# Guardar como archivo .RData (formato nativo de R)
save(datos, file = "datos_limpios.RData")

# Guardar como CSV (formato universal)
write.csv(datos, "datos_limpios.csv", row.names = FALSE)

# ----------------------------------------------------------------------------
# Resumen final
# ----------------------------------------------------------------------------

print("=== RESUMEN DE IMPORTACIÓN ===")
print(paste("Total de observaciones:", nrow(datos)))
print(paste("Total de variables:", ncol(datos)))
print("Variables:")
print(names(datos))
print("Estructura final:")
str(datos)

📋 Parte 4: Análisis estadístico

Paso 4.1: Script de análisis estadistico

Creamos el script principal 04_analisis_completo.R:

# ============================================================================
# ANÁLISIS ESTADÍSTICO - DISEÑO COMPLETAMENTE ALEATORIZADO
# Efecto de métodos de conservación en vitamina C de jugo de naranja
# ============================================================================

# Cargar librerías
# install.packages("tidyverse")
# install.packages("ggplot2")
# install.packages("car")
# install.packages("agricolae")
# install.packages("DescTools")
# install.packages("patchwork")
# install.packages("broom")

library(tidyverse)
library(ggplot2)
library(car)
library(agricolae)
library(DescTools)
library(patchwork)
library(broom)

# Cargar datos limpios
# load("datos_limpios.RData")

# O si prefieres desde CSV:
datos <- read.csv("datos_limpios.csv", header = TRUE)

# ============================================================================
# SECCIÓN 1: ESTADÍSTICA DESCRIPTIVA
# ============================================================================

# ----------------------------------------------------------------------------
# 1.1 Tabla de estadísticos descriptivos por tratamiento
# ----------------------------------------------------------------------------

desc_por_tratamiento <- datos %>%
  group_by(tratamiento) %>%
  summarise(
    n = n(),
    media = mean(vitamina_c, na.rm = TRUE),
    mediana = median(vitamina_c, na.rm = TRUE),
    sd = sd(vitamina_c, na.rm = TRUE),
    var = var(vitamina_c, na.rm = TRUE),
    se = sd / sqrt(n),  # Error estándar
    cv = (sd / media) * 100,  # Coeficiente de variación (%)
    min = min(vitamina_c, na.rm = TRUE),
    max = max(vitamina_c, na.rm = TRUE),
    q1 = quantile(vitamina_c, 0.25, na.rm = TRUE),
    q3 = quantile(vitamina_c, 0.75, na.rm = TRUE)
  ) %>%
  mutate(
    media = round(media, 2),
    mediana = round(mediana, 2),
    sd = round(sd, 2),
    var = round(var, 2),
    se = round(se, 2),
    cv = round(cv, 2),
    min = round(min, 2),
    max = round(max, 2),
    q1 = round(as.numeric(q1), 2),
    q3 = round(as.numeric(q3), 2)
  )

print("=== ESTADÍSTICOS DESCRIPTIVOS POR TRATAMIENTO ===")
print(desc_por_tratamiento)

# Guardar tabla descriptiva
library(writexl)
# write.csv(desc_por_tratamiento, "tabla_descriptiva.csv", row.names = FALSE)
write_xlsx(desc_por_tratamiento, "tabla_descriptiva.xlsx")

# ============================================================================
# SECCIÓN 2: GRÁFICOS EXPLORATORIOS
# ============================================================================


# ----------------------------------------------------------------------------
# 2.1 Boxplot con puntos individuales
# ----------------------------------------------------------------------------

p1 <- ggplot(datos, aes(x = tratamiento, y = vitamina_c, fill = tratamiento)) +
  geom_boxplot(alpha = 0.6, outlier.shape = NA, width = 0.6) +
  geom_jitter(width = 0.15, size = 2.5, alpha = 0.7, color = "black") +
  stat_summary(fun = "mean", geom = "point", shape = 23, size = 4, 
               fill = "white", color = "black", stroke = 1.5) +
  labs(title = "Contenido de Vitamina C por metodo de conservacion",
       subtitle = "Los diamantes blancos indican la media de cada tratamiento",
       x = "Tratamiento (Metodo de conservacion)",
       y = "Vitamina C (mg/100mL)",
       fill = "Tratamiento") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none",
        plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
        plot.subtitle = element_text(size = 11, hjust = 0.5, color = "gray40"))
print(p1)
ggsave("grafico_boxplot.png", p1, width = 8, height = 6, dpi = 300)


# ----------------------------------------------------------------------------
# 2.2 Gráfico de medias con barras de error (SE)
# ----------------------------------------------------------------------------

p2 <- ggplot(desc_por_tratamiento, 
             aes(x = tratamiento, y = media, fill = tratamiento)) +
  geom_bar(stat = "identity", width = 0.6, alpha = 0.7) +
  geom_errorbar(aes(ymin = media - se, ymax = media + se), 
                width = 0.2, size = 0.8, color = "black") +
  geom_text(aes(label = sprintf("%.2f \u00B1 %.2f", media, se)),
            vjust = -1.5, size = 4, fontface = "bold") +
  labs(title = "Medias y error estandar por tratamiento",
       subtitle = "Barras de error: ± 1 SE",
       x = "Tratamiento",
       y = "Vitamina C (mg/100mL)",
       fill = "Tratamiento") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none",
        plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
        plot.subtitle = element_text(size = 11, hjust = 0.5, color = "gray40"),
        axis.text.x = element_text(angle = 15, hjust = 1)) +
  ylim(0, max(desc_por_tratamiento$media + desc_por_tratamiento$se) * 1.2)

print(p2)
ggsave("grafico_medias_se.png", p2, width = 8, height = 6, dpi = 300)


# ============================================================================
# SECCIÓN 3: MODELO MATEMÁTICO
# ============================================================================

cat("=== MODELO ESTADÍSTICO PARA DISEÑO COMPLETAMENTE ALEATORIZADO ===\n\n")

cat("El modelo lineal para un DCA con un factor se expresa como:\n\n")

cat("Y_ij = μ + τ_i + ε_ij\n\n")

cat("Donde:\n")
cat("  Y_ij = Contenido de vitamina C en la repetición j del tratamiento i\n")
cat("  μ    = Media general del experimento\n")
cat("  τ_i  = Efecto del tratamiento i (método de conservación)\n")
cat("  ε_ij = Error experimental ~ N(0, σ²)\n\n")

cat("Índices:\n")
cat("  i = 1, 2, 3  (tratamientos: T1, T2, T3)\n")
cat("  j = 1, 2, ..., 8  (repeticiones por tratamiento)\n\n")

cat("Hipótesis:\n")
cat("  H₀: τ₁ = τ₂ = τ₃ = 0  (no hay efecto de los tratamientos)\n")
cat("  H₁: al menos un τ_i ≠ 0  (al menos un tratamiento difiere)\n\n")

cat("Supuestos del modelo:\n")
cat("  1. Independencia de las observaciones (garantizada por aleatorización)\n")
cat("  2. Normalidad de los errores (ε_ij ~ N(0, σ²))\n")
cat("  3. Homocedasticidad (varianza constante entre tratamientos)\n\n")

# ============================================================================
# SECCIÓN 4: VERIFICACIÓN DE SUPUESTOS
# ============================================================================

# ----------------------------------------------------------------------------
# Ajustar modelo ANOVA
# ----------------------------------------------------------------------------

modelo <- aov(vitamina_c ~ tratamiento, data = datos)

# Extraer residuos
residuos <- residuals(modelo)
valores_ajustados <- fitted(modelo)

# ----------------------------------------------------------------------------
# 4.1 Supuesto de Normalidad
# ----------------------------------------------------------------------------

cat("=== SUPUESTO 1: NORMALIDAD DE RESIDUOS ===\n\n")

# Prueba de Shapiro-Wilk
shapiro <- shapiro.test(residuos)
print(shapiro)

if(shapiro$p.value > 0.05){
  cat("✓ INTERPRETACIÓN: No hay evidencia para rechazar normalidad (p > 0.05)\n")
  cat("  Los residuos siguen una distribución normal.\n\n")
} else {
  cat("✗ INTERPRETACIÓN: Los residuos NO siguen distribución normal (p ≤ 0.05)\n")
  cat("  Considerar transformación de datos o prueba no paramétrica (Kruskal-Wallis).\n\n")
}

# Gráfico Q-Q
qq_plot <- ggplot(data.frame(residuos = residuos), aes(sample = residuos)) +
  stat_qq(size = 3, color = "steelblue") +
  stat_qq_line(color = "red", linewidth = 1.2) +
  labs(title = "Grafico Q-Q de Residuos",
       subtitle = paste("Shapiro-Wilk: p =", round(shapiro$p.value, 4)),
       x = "Cuantiles teoricos",
       y = "Cuantiles observados") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", size = 13),
        plot.subtitle = element_text(size = 11, color = "gray40"))

ggsave("grafico_qq.png", qq_plot, width = 7, height = 6, dpi = 300)
print(qq_plot)

# Histograma de residuos con curva normal
hist_plot <- ggplot(data.frame(residuos = residuos), aes(x = residuos)) +
  geom_histogram(aes(y = after_stat(density)), bins = 8, 
                 fill = "steelblue", alpha = 0.6, color = "black") +
  stat_function(fun = dnorm, args = list(mean = mean(residuos), sd = sd(residuos)),
                color = "red", linewidth = 1.5) +
  labs(title = "Histograma de residuos con curva normal superpuesta",
       x = "Residuos",
       y = "Densidad") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", size = 13))

ggsave("grafico_histograma_residuos.png", hist_plot, width = 7, height = 5, dpi = 300)
print(hist_plot)

# ----------------------------------------------------------------------------
# 4.2 Supuesto de Homocedasticidad (Homogeneidad de Varianzas)
# ----------------------------------------------------------------------------

# Prueba de Levene
levene <- leveneTest(vitamina_c ~ tratamiento, data = datos)
print(levene)


# Gráfico de residuos vs. valores ajustados
resid_plot <- ggplot(data.frame(ajustados = valores_ajustados, residuos = residuos),
                     aes(x = ajustados, y = residuos)) +
  geom_point(size = 3, color = "steelblue", alpha = 0.7) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "red", linewidth = 1.2) +
  geom_smooth(method = "lm", se = FALSE, color = "darkgreen", linewidth = 1) +
  labs(title = "Residuos vs. valores ajustados",
       subtitle = paste("Prueba de Levene: p =", round(levene[1, "Pr(>F)"], 4))) +
  theme_minimal(base_size = 12)

ggsave("grafico_residuos_ajustados.png", resid_plot, width = 7, height = 6, dpi = 300)
print(resid_plot)

# ----------------------------------------------------------------------------
# 4.3 Supuesto de Independencia
# ----------------------------------------------------------------------------

cat("El supuesto de independencia se garantiza mediante:\n")
cat("  ✓ Aleatorización en la asignación de tratamientos\n")
cat("  ✓ Unidades experimentales independientes (envases separados)\n")
cat("  ✓ Mediciones realizadas en orden aleatorio\n")
cat("  ✓ Sin relación entre observaciones (cada envase es único)\n\n")

cat("Verificación gráfica: Gráfico de residuos vs. orden de ejecución\n")

# Agregar orden de ejecución a los datos
datos$orden <- 1:nrow(datos)

orden_plot <- ggplot(datos, aes(x = orden, y = residuos)) +
  geom_point(size = 3, color = "steelblue", alpha = 0.7) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
  geom_smooth(method = "lm", se = TRUE, color = "darkgreen", alpha = 0.3) +
  labs(title = "Residuos vs. orden de ejecucion",
       subtitle = "Verificación de independencia temporal",
       x = "Orden de ejecucion",
       y = "Residuos") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", size = 13),
        plot.subtitle = element_text(size = 11, color = "gray40"))

ggsave("grafico_residuos_orden.png", orden_plot, width = 8, height = 5, dpi = 300)
print(orden_plot)

# ============================================================================
# SECCIÓN 5: ANÁLISIS DE VARIANZA (ANOVA)
# ============================================================================

# ----------------------------------------------------------------------------
# 5.1 Tabla ANOVA
# ----------------------------------------------------------------------------

tabla_anova <- anova(modelo)
print(tabla_anova)

# Guardar tabla ANOVA
write_xlsx(as.data.frame(tabla_anova), "tabla_anova.xlsx")

p_valor <- anova(modelo)[1, "Pr(>F)"]
if(p_valor < 0.05){
  cat("✓ CONCLUSION: Hay diferencias significativas entre tratamientos (p < 0.05)\n")
  cat("  Rechazamos H₀. Al menos un tratamiento difiere de los demas.\n")
  cat("  Procedemos a pruebas de comparacion multiple de medias.\n\n")
} else {
  cat("✗ CONCLUSION: No hay diferencias significativas entre tratamientos (p ≥ 0.05)\n")
  cat("  No rechazamos H₀. Los tratamientos no difieren estadisticamente.\n")
  cat("  Las pruebas post-hoc no son necesarias pero pueden realizarse de forma exploratoria.\n\n")
}


# ============================================================================
# SECCIÓN 6: PRUEBA DE COMPARACIÓN MÚLTIPLE DE MEDIAS
# ============================================================================


# ----------------------------------------------------------------------------
# 6.1 Prueba de Tukey (HSD - Honest Significant Difference)
# ----------------------------------------------------------------------------

cat("=== PRUEBA DE TUKEY (HSD) ===\n")
cat("Propósito: Comparaciones por pares entre TODOS los tratamientos\n")
cat("Controla la tasa de error familiar (FWER) para múltiples comparaciones\n\n")

tukey <- TukeyHSD(modelo, "tratamiento", conf.level = 0.95)
print(tukey)

# Interpretación
cat("\n=== INTERPRETACIÓN DE TUKEY ===\n\n")

tukey_df <- as.data.frame(tukey$tratamiento)
tukey_df$significativo <- ifelse(tukey_df$`p adj` < 0.05, "Sí *", "No")

print(tukey_df)

cat("\nRegla de decisión:\n")
cat("  - Si p-valor ajustado < 0.05 → Diferencia significativa\n")
cat("  - Si p-valor ajustado ≥ 0.05 → Diferencia no significativa\n\n")

📊 Resumen de archivos generados

Después de ejecutar todos los scripts, tendrás:

Scripts de R:

  1. 01_calculo_poder.R - Análisis de potencia y tamaño muestral
  2. 02_aleatorizacion.R - Aleatorización del diseño
  3. 03_importar_datos.R - Importación y limpieza de datos
  4. 04_analisis_completo.R - Análisis estadístico

Archivos de datos:

  • planilla_aleatorizacion.xlsx - Para imprimir y usar en campo
  • datos_vitamina_c.xlsx - Datos cargados desde Excel
  • datos_limpios.RData y datos_limpios.csv - Datos procesados
  • resultados_analisis.RData - Objetos de resultados
  • tabla_descriptiva.csv, tabla_anova.csv, etc.

Gráficos (PNG):

  • esquema_aleatorizacion.png - Esquema visual de asignación
  • grafico_boxplot.png - Boxplot con puntos
  • grafico_medias_se.png - Medias con error estándar
  • grafico_qq.png - Q-Q plot de normalidad
  • grafico_histograma_residuos.png - Histograma con curva normal
  • grafico_residuos_ajustados.png - Residuos vs. ajustados
  • grafico_residuos_orden.png - Residuos vs. orden

🎓 Puntos clave

Sobre el cálculo de potencia:

  1. NUNCA elijas el tamaño muestral “al ojo” o por conveniencia
  2. El análisis de potencia se hace ANTES de comenzar el experimento
  3. Tres parámetros clave: potencia (0.80), significación (0.05), tamaño del efecto (f)
  4. Si no tienes información previa, usa f = 0.25 (efecto mediano) como punto de partida conservador
  5. Siempre redondea hacia arriba el número de repeticiones
  6. Justifica el tamaño muestral citando el análisis de potencia

Sobre la aleatorización:

  1. La aleatorización garantiza independencia y evita sesgos
  2. Usa set.seed() para reproducibilidad
  3. Nunca asignes tratamientos en orden sistemático (T1, T1, T1… T2, T2, T2…)
  4. Imprime la planilla de aleatorización y llévala al laboratorio

Sobre la carga de datos:

  1. Una fila = una unidad experimental
  2. Una columna = una variable
  3. Nombres de columnas sin espacios ni caracteres especiales
  4. Datos numéricos sin unidades en las celdas
  5. Guarda siempre el raw data (sin modificar) y una versión limpia

Sobre la verificación de supuestos:

  1. Normalidad: Shapiro-Wilk + Q-Q plot + histograma
  2. Homocedasticidad: Levene + gráfico residuos vs. ajustados
  3. Independencia: Garantizada por diseño + gráfico residuos vs. orden
  4. Si los supuestos no se cumplen: transformar datos o usar pruebas no paramétricas

Sobre las pruebas Post-Hoc:

  1. Tukey: Comparaciones por pares entre todos (más conservador)
  2. Duncan: Agrupamiento en letras (menos conservador, más poder)
  3. Dunnett: Comparación contra control (cuando hay un tratamiento de referencia)
  4. Siempre interpreta en contexto biológico/bromatológico, no solo estadístico

💡 Reflexión sobre uso de IA

Durante esta clase, pueden usar IA para:

✅ Buscar fórmulas de cálculo de potencia ✅ Entender la interpretación de pruebas estadísticas ✅ Depurar errores en código R ✅ Mejorar redacción del informe

NO usar IA para:

  • Generar datos falsos
  • Copiar código sin entenderlo
  • Saltarse la verificación de supuestos
  • Interpretar resultados sin pensamiento crítico

Pregunta reflexiva para el informe: ¿Cómo validaron que el código generado o sugerido por IA era correcto? ¿Qué errores encontraron y cómo los resolvieron?


¡Éxitos en su análisis! Recuerden que la estadística es una herramienta para responder preguntas científicas, no un fin en sí misma. 📊🔬 123456789101112131415


  1. https://search.r-project.org/CRAN/refmans/pwr/html/pwr.anova.test.html↩︎

  2. http://rstudio-pubs-static.s3.amazonaws.com/235504_3b3b13081ea24c06ad7642f96dba5242.html↩︎

  3. https://stevenggoni.github.io/tutoriales_R/potencia_modelos.html↩︎

  4. https://jdleongomez.info/es/post/power/↩︎

  5. https://r-statistics.co/Sample-Size-Planning-in-R.html↩︎

  6. https://rguides.dev/guides/r-power-analysis/↩︎

  7. https://r-statistics.co/Statistical-Power-Analysis-in-R.html↩︎

  8. https://jdleongomez.info/en/publication/leongomez2020power/↩︎

  9. https://cran.r-project.org/web/packages/pwranova/pwranova.pdf↩︎

  10. https://cran.r-project.org/web/packages/pwr/vignettes/pwr-vignette.html↩︎

  11. https://cran.r-project.org/web/packages/powertools/powertools.pdf↩︎

  12. https://cran.rstudio.com/web/packages/pwrss/vignettes/examples.html↩︎

  13. https://zenodo.org/records/3988777/files/Análisis de Poder en R.pdf↩︎

  14. https://www.datacamp.com/es/doc/r/power↩︎

  15. https://www.datacamp.com/pt/doc/r/power↩︎