¡Excelente iniciativa! Plantear situaciones reales de la Ingeniería Agrícola y Agroindustrial es la mejor forma de que los estudiantes interioricen la utilidad del Diseño de Bloques Completos al Azar (DBCA).
Como me indicaste, he omitido las citas del documento original para que el material te quede completamente limpio para tus clases. A continuación, te presento el contenido estructurado en formato Markdown, ideal para integrarlo directamente como celdas de texto y código en tus cuadernos de Google Colab interactivos.
A continuación, se presentan tres ejercicios prácticos aplicados a la Ingeniería Agrícola y Agroindustrial. Deberán resolver cada ejercicio a mano (lápiz y papel) siguiendo la secuencia de fórmulas paso a paso, y posteriormente verificar sus resultados utilizando las celdas de código en Python y R proporcionadas al final.
Contexto: En una planta agroindustrial se desea evaluar el efecto de tres temperaturas de secado continuo (40°C, 50°C y 60°C) sobre el porcentaje final de humedad del grano de maíz. Dado que el maíz proviene de tres proveedores distintos que introducen variabilidad en la humedad inicial, se decide utilizar a los proveedores como bloques (Lote A, Lote B, Lote C).
Datos Observados (% de humedad final):
| Tratamiento (Temperatura) | Bloque 1 (Lote A) | Bloque 2 (Lote B) | Bloque 3 (Lote C) |
|---|---|---|---|
| T1 (40°C) | 14.5 | 15.2 | 14.8 |
| T2 (50°C) | 12.1 | 12.8 | 12.5 |
| T3 (60°C) | 10.5 | 11.0 | 10.8 |
Contexto: Un ingeniero agrícola evalúa tres sistemas de riego (Goteo, Aspersión y Superficie) para determinar su efecto en el rendimiento de un cultivo de hortalizas (medido en ton/ha). El terreno experimental tiene una pendiente pronunciada que afecta el drenaje natural. Para controlar esta variabilidad, el terreno se divide en cuatro franjas perpendiculares a la pendiente, sirviendo estas como bloques.
Datos Observados (Rendimiento en ton/ha):
| Tratamiento (Riego) | Bloque 1 (Alta) | Bloque 2 (Media-Alta) | Bloque 3 (Media-Baja) | Bloque 4 (Baja) |
|---|---|---|---|---|
| Goteo | 22.4 | 23.1 | 24.5 | 25.0 |
| Aspersión | 18.5 | 19.2 | 20.0 | 21.3 |
| Superficie | 14.0 | 14.5 | 15.2 | 16.0 |
Contexto: Se investiga la pérdida de peso (%) de mangos de exportación bajo cuatro tipos de empaque (Cera, Película plástica, Malla, Testigo sin empaque) almacenados durante 20 días. Como las cámaras frigoríficas pueden tener ligeras fluctuaciones de temperatura cerca de las puertas o los ventiladores, se utilizan tres cámaras distintas como bloques.
Datos Observados (Pérdida de peso %):
| Tratamiento (Empaque) | Bloque 1 (Cámara 1) | Bloque 2 (Cámara 2) | Bloque 3 (Cámara 3) |
|---|---|---|---|
| Cera | 4.2 | 4.5 | 4.1 |
| Película | 3.1 | 3.4 | 3.0 |
| Malla | 7.5 | 7.8 | 7.2 |
| Testigo | 9.0 | 9.5 | 8.8 |
Para cada uno de los ejercicios anteriores, desarrolle los siguientes pasos en su hoja de cálculo manual:
Paso 1: Tabla de Totales Calcule las sumas por fila (Tratamientos, \(Y_{i.}\)), por columna (Bloques, \(Y_{.j}\)) y el Gran Total (\(Y_{..}\)). Identifique \(t\) (número de tratamientos) y \(r\) (número de bloques).
Paso 2: Cálculo del Término de Corrección (TC) \[TC = \frac{Y_{..}^2}{rt}\]
Paso 3: Suma de Cuadrados Total (SC_Total) Eleve al cuadrado cada observación individual, súmelas todas y reste el TC. \[SC_{Total} = \sum_{i=1}^{t} \sum_{j=1}^{r} Y_{ij}^2 - TC\]
Paso 4: Suma de Cuadrados de los Tratamientos (SC_Trat) \[SC_{Trat} = \frac{\sum Y_{i.}^2}{r} - TC\]
Paso 5: Suma de Cuadrados de los Bloques (SC_Bloq) \[SC_{Bloq} = \frac{\sum Y_{.j}^2}{t} - TC\]
Paso 6: Suma de Cuadrados del Error (SC_Error) \[SC_{Error} = SC_{Total} - SC_{Trat} - SC_{Bloq}\]
Paso 7: Tabla ANOVA y Estadístico F Calcule los Grados de Libertad (\(gl\)), los Cuadrados Medios (\(CM = SC / gl\)) y el F calculado para Tratamientos y Bloques. * \(gl_{Trat} = t - 1\) * \(gl_{Bloq} = r - 1\) * \(gl_{Error} = (t - 1)(r - 1)\) * \[F_{Trat} = \frac{CM_{Trat}}{CM_{Error}}\]
Compare su \(F\) calculado con el \(F\) de la tabla de Fisher para \(\alpha = 0.05\) y emita su conclusión.
Una vez finalizados los cálculos a mano, modifique los datos en las siguientes plantillas para corroborar sus resultados.
(Nota para la clase: El código base a continuación está configurado con los datos del Ejercicio 1. Deberán modificar los arreglos de datos para resolver los Ejercicios 2 y 3).
import pandas as pd
import statsmodels.api as sm
from statsmodels.formula.api import ols
# 1. Ingreso de datos (Modificar para Ejercicio 2 y 3)
datos = {
'Humedad': [14.5, 15.2, 14.8, 12.1, 12.8, 12.5, 10.5, 11.0, 10.8],
'Temperatura': ['T40', 'T40', 'T40', 'T50', 'T50', 'T50', 'T60', 'T60', 'T60'],
'Bloque': ['LoteA', 'LoteB', 'LoteC', 'LoteA', 'LoteB', 'LoteC', 'LoteA', 'LoteB', 'LoteC']
}
# 2. Creación del DataFrame
df = pd.DataFrame(datos)
# 3. Ajuste del modelo de bloques al azar
# C() asegura que las variables sean tratadas como factores categóricos
modelo = ols('Humedad ~ C(Temperatura) + C(Bloque)', data=df).fit()
# 4. Análisis de Varianza
tabla_anova = sm.stats.anova_lm(modelo, typ=2)
print("=== TABLA ANOVA (Python) ===")
print(tabla_anova)
# 1. Ingreso de vectores de datos (Modificar para Ejercicio 2 y 3)
humedad <- c(14.5, 15.2, 14.8, 12.1, 12.8, 12.5, 10.5, 11.0, 10.8)
temperatura <- as.factor(rep(c("T40", "T50", "T60"), each=3))
bloque <- as.factor(rep(c("LoteA", "LoteB", "LoteC"), times=3))
# 2. Ajuste del modelo lineal para DBCA
modelo_aov <- aov(humedad ~ temperatura + bloque)
# 3. Generar la salida del ANOVA
cat("=== TABLA ANOVA (R Base) ===\n")
summary(modelo_aov)
# Instalar el paquete si es la primera vez que se ejecuta en el entorno
# install.packages("easyanova")
library(easyanova)
# 1. Preparar los datos.
# IMPORTANTE: easyanova con design=2 espera que la columna 1 sea Tratamiento, la 2 sea Bloque y la 3 sea Respuesta.
datos_dbca <- data.frame(
Tratamiento = as.factor(rep(c("T40", "T50", "T60"), each=3)),
Bloque = as.factor(rep(c("LoteA", "LoteB", "LoteC"), times=3)),
Respuesta = c(14.5, 15.2, 14.8, 12.1, 12.8, 12.5, 10.5, 11.0, 10.8)
)
# 2. Ejecutar ea1 con design = 2 (Diseño en Bloques Completos al Azar)
resultado_ea <- ea1(datos_dbca, design = 2)
# 3. Mostrar la tabla ANOVA
cat("=== TABLA ANOVA (easyanova) ===\n")
print(resultado_ea$`Analysis of variance`)
¿Te gustaría que añadamos un bloque de código adicional en Python utilizando Streamlit para que los estudiantes vean cómo desplegarían este modelo en una aplicación web interactiva alojada en GitHub, tal como lo haces en tus asignaturas?
¡Claro que sí! Llevar estos modelos estadísticos a una aplicación web interactiva es el paso definitivo para que los futuros ingenieros vean la utilidad práctica de la programación en la resolución de problemas reales.
Aquí tienes la estructura de un archivo app.py
utilizando Streamlit. Está diseñado para ser intuitivo: permite a los
estudiantes subir su propia base de datos (por ejemplo, los datos de los
ejercicios de secado o sistemas de riego), seleccionar qué columnas
corresponden a los tratamientos, bloques y a la variable de respuesta, y
genera la Tabla ANOVA dinámicamente.
app.py (Streamlit)import streamlit as st
import pandas as pd
import statsmodels.api as sm
from statsmodels.formula.api import ols
# Configuración inicial de la página
st.set_page_config(page_title="Calculadora DBCA", layout="centered")
st.title("🚜 Análisis: Diseño de Bloques Completos al Azar (DBCA)")
st.markdown("""
Esta aplicación permite realizar el Análisis de Varianza (ANOVA) para un DBCA.
Sube tus datos experimentales, selecciona tus variables y obtén los resultados estadísticos al instante.
""")
st.divider()
# 1. Carga de archivo
st.header("1. Carga de Datos")
archivo_subido = st.file_uploader("Sube tu archivo Excel o CSV", type=['xlsx', 'csv'])
if archivo_subido is not None:
# Leer el archivo dependiendo de su extensión
try:
if archivo_subido.name.endswith('.csv'):
df = pd.read_csv(archivo_subido)
else:
df = pd.read_excel(archivo_subido)
st.success("¡Datos cargados correctamente!")
st.write("**Vista previa de los datos:**")
st.dataframe(df.head(), use_container_width=True)
st.divider()
# 2. Asignación de variables
st.header("2. Configuración del Modelo")
st.write("Selecciona a qué corresponde cada columna de tus datos:")
col1, col2, col3 = st.columns(3)
with col1:
var_respuesta = st.selectbox("Variable de Respuesta (Ej. Rendimiento)", df.columns)
with col2:
var_tratamiento = st.selectbox("Tratamientos (Ej. Sistemas de Riego)", df.columns)
with col3:
var_bloque = st.selectbox("Bloques (Ej. Lotes/Zonas)", df.columns)
# 3. Cálculo del ANOVA
st.divider()
st.header("3. Resultados")
if st.button("Calcular Tabla ANOVA", type="primary"):
with st.spinner('Procesando el modelo estadístico...'):
try:
# Se utiliza C() para indicar explícitamente que son factores categóricos
formula = f"{var_respuesta} ~ C({var_tratamiento}) + C({var_bloque})"
modelo = ols(formula, data=df).fit()
tabla_anova = sm.stats.anova_lm(modelo, typ=2)
st.write("### Tabla ANOVA Generada")
st.dataframe(tabla_anova, use_container_width=True)
st.info("💡 **Tip de interpretación:** Revisa la columna `PR(>F)` (P-valor). Si este valor es menor a 0.05 en la fila de tratamientos, existen diferencias significativas entre ellos.")
except Exception as e:
st.error(f"Ocurrió un error al procesar los datos. Verifica que las columnas no tengan valores nulos o caracteres especiales. Detalle: {e}")
except Exception as e:
st.error(f"No se pudo leer el archivo. Detalle: {e}")
else:
st.info("Esperando a que subas un archivo para comenzar...")
Para integrar esto en el flujo de trabajo de los estudiantes con las herramientas actuales, la secuencia de despliegue sería la siguiente:
Guardar el código anterior en un archivo llamado
app.py.
Crear un archivo requirements.txt que contenga
únicamente las tres librerías necesarias:
streamlit
pandas
statsmodels
openpyxl(Nota: openpyxl es necesario en el background
para que pandas pueda leer archivos .xlsx).
git init).main (o master) y que el archivo
de entrada es app.py.¿Te gustaría que armemos también la estructura equivalente de un documento en R Markdown, listo para que los estudiantes lo tejan (Knit) y publiquen directamente su reporte en RPubs?
Excelente elección. Publicar los análisis en RPubs mediante R Markdown es una práctica fantástica, ya que obliga a los estudiantes a combinar el fundamento teórico, la ejecución del código y la interpretación de los resultados en un solo reporte técnico profesional, tal como se exige en el mundo real de la ingeniería.
A continuación, te presento la plantilla estructurada de un documento
R Markdown (.Rmd). Está configurada con un
diseño limpio y profesional, e incluye el Ejercicio 2 (Sistemas de
Riego) resuelto paso a paso con R Base y con el paquete
easyanova.
Tus estudiantes solo deben copiar este texto, pegarlo en un nuevo archivo R Markdown en su entorno de trabajo y compilarlo.
.Rmd)---
title: "Análisis de Varianza (DBCA) - Eficiencia de Sistemas de Riego"
author: "Nombre del Estudiante"
date: "2026-03-28"
output:
html_document:
toc: true
toc_float: true
theme: flatly
highlight: tango
---
## 1. Contexto del Problema Agrícola
Un ingeniero evalúa tres sistemas de riego (**Goteo**, **Aspersión** y **Superficie**) para determinar su efecto en el rendimiento de un cultivo de hortalizas (medido en ton/ha). El terreno experimental tiene una pendiente pronunciada que afecta el drenaje natural. Para aislar y controlar esta variabilidad, el terreno se dividió en cuatro franjas perpendiculares a la pendiente, que funcionan como **bloques** (Alta, Media-Alta, Media-Baja y Baja).
### 1.1. Hipótesis
* **Tratamientos ($H_0$):** Los tres sistemas de riego producen el mismo rendimiento medio.
* **Bloques ($H_0$):** La posición en la pendiente (bloque) no tiene un efecto significativo sobre el rendimiento.
---
## 2. Ingreso y Preparación de los Datos
Primero, construimos los vectores que representan nuestros tratamientos, bloques y la variable de respuesta (rendimiento).
``` r
# Variable de respuesta: Rendimiento en ton/ha
rendimiento <- c(22.4, 23.1, 24.5, 25.0, # Goteo
18.5, 19.2, 20.0, 21.3, # Aspersión
14.0, 14.5, 15.2, 16.0) # Superficie
# Factores: Tratamientos (Sistemas de riego) y Bloques (Pendiente)
tratamiento <- as.factor(rep(c("Goteo", "Aspersión", "Superficie"), each = 4))
bloque <- as.factor(rep(c("B_Alta", "B_MedAlta", "B_MedBaja", "B_Baja"), times = 3))
# Consolidamos en un Data Frame
datos_riego <- data.frame(Tratamiento = tratamiento,
Bloque = bloque,
Rendimiento = rendimiento)
# Mostramos las primeras filas
head(datos_riego)
```
<div data-pagedtable="false">
<script data-pagedtable-source type="application/json">
{"columns":[{"label":[""],"name":["_rn_"],"type":[""],"align":["left"]},{"label":["Tratamiento"],"name":[1],"type":["fct"],"align":["left"]},{"label":["Bloque"],"name":[2],"type":["fct"],"align":["left"]},{"label":["Rendimiento"],"name":[3],"type":["dbl"],"align":["right"]}],"data":[{"1":"Goteo","2":"B_Alta","3":"22.4","_rn_":"1"},{"1":"Goteo","2":"B_MedAlta","3":"23.1","_rn_":"2"},{"1":"Goteo","2":"B_MedBaja","3":"24.5","_rn_":"3"},{"1":"Goteo","2":"B_Baja","3":"25.0","_rn_":"4"},{"1":"Aspersión","2":"B_Alta","3":"18.5","_rn_":"5"},{"1":"Aspersión","2":"B_MedAlta","3":"19.2","_rn_":"6"}],"options":{"columns":{"min":{},"max":[10]},"rows":{"min":[10],"max":[10]},"pages":{}}}
</script>
</div>
---
## 3. Análisis de Varianza (Paramétrico)
### 3.1. Usando R Base
La función `aov()` nos permite ajustar el modelo lineal para el Diseño de Bloques Completos al Azar.
``` r
# Ajuste del modelo: Rendimiento en función del Tratamiento y el Bloque
modelo_anova <- aov(Rendimiento ~ Tratamiento + Bloque, data = datos_riego)
# Generación de la tabla ANOVA
summary(modelo_anova)
```
```
## Df Sum Sq Mean Sq F value Pr(>F)
## Tratamiento 2 156.22 78.11 1176.52 1.65e-08 ***
## Bloque 3 10.57 3.52 53.07 0.000103 ***
## Residuals 6 0.40 0.07
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
```
### 3.2. Usando el paquete `easyanova`
El paquete `easyanova` simplifica el proceso y nos arroja resultados completos con un solo comando. Para el DBCA, utilizamos `design = 2`.
``` r
# Cargamos la librería
library(easyanova)
# Reordenamos el data frame para que cumpla el formato de easyanova:
# Columna 1: Tratamiento, Columna 2: Bloque, Columna 3: Respuesta
datos_ea <- data.frame(datos_riego$Tratamiento, datos_riego$Bloque, datos_riego$Rendimiento)
# Ejecutamos la función ea1
resultado_ea <- ea1(datos_ea, design = 2)
```
<img src="4_DBCA_Gemini_3_Ejercicios_files/figure-html/easyanova_calculo-1.png" alt="" width="672" />
``` r
# Imprimimos la tabla ANOVA
resultado_ea$`Analysis of variance`
```
<div data-pagedtable="false">
<script data-pagedtable-source type="application/json">
{"columns":[{"label":[""],"name":["_rn_"],"type":[""],"align":["left"]},{"label":["df"],"name":[1],"type":["dbl"],"align":["right"]},{"label":["type III SS"],"name":[2],"type":["dbl"],"align":["right"]},{"label":["mean square"],"name":[3],"type":["dbl"],"align":["right"]},{"label":["F value"],"name":[4],"type":["chr"],"align":["left"]},{"label":["p>F"],"name":[5],"type":["chr"],"align":["left"]}],"data":[{"1":"2","2":"156.2150","3":"78.1075","4":"1176.5146","5":"<0.001","_rn_":"treatments"},{"1":"3","2":"10.5692","3":"3.5231","4":"53.0669","5":"<0.001","_rn_":"blocks"},{"1":"6","2":"0.3983","3":"0.0664","4":"-","5":"-","_rn_":"residuals"}],"options":{"columns":{"min":{},"max":[10]},"rows":{"min":[10],"max":[10]},"pages":{}}}
</script>
</div>
---
## 4. Interpretación de Resultados
Al observar la columna **Pr(>F)** (el P-valor) en nuestras tablas ANOVA, concluimos lo siguiente con un nivel de significancia del 5% ($\alpha = 0.05$):
1. **Efecto de los Tratamientos (Sistemas de Riego):** El P-valor es significativamente menor a 0.05. Por lo tanto, **rechazamos la hipótesis nula**. Existe evidencia estadística de que el tipo de sistema de riego afecta el rendimiento del cultivo de hortalizas.
2. **Efecto de los Bloques (Pendiente):** Observamos si el agrupamiento por bloques logró separar variabilidad significativa. (El estudiante debe completar esta línea según el P-valor obtenido para los bloques).
File >
New File > R Markdown....analisis_riego.Rmd).¿Deseas que preparemos también una guía breve sobre cómo alojar el código de Python y R en repositorios de GitHub, o prefieres que pasemos a diseñar una evaluación tipo cuestionario sobre los conceptos de este diseño experimental?
¡Con mucho gusto! Dominar el control de versiones y saber alojar proyectos en la nube es una competencia indispensable para el perfil de un ingeniero moderno, sin importar si trabaja en agroindustria, obras civiles o agricultura.
A continuación, te presento una guía breve y estructurada, ideal para que tus alumnos la sigan paso a paso. Está diseñada pensando en las herramientas exactas de sus prácticas: Google Colab, VS Code y scripts de R.
git config --global user.name "SuNombre"git config --global user.email "sucorreo@universidad.edu.co"Esta es la ruta más rápida para los cuadernos interactivos
(.ipynb) donde resuelven los fundamentos de programación o
el cálculo manual del DBCA.
Para proyectos de despliegue web con Streamlit o scripts complejos de R y Python, el flujo local es la norma de la industria.
proyecto_dbca).app.py
(para Streamlit) o analisis.R (para R)..venv) o bases de
datos pesadas que no correspondan.Con esto, tus alumnos tienen la ruta completa: desde el planteamiento teórico del DBCA, pasando por los cálculos en código, hasta el alojamiento profesional de sus aplicaciones web y reportes en la nube.
¿Te gustaría que diseñemos ahora un cuestionario de evaluación rápida (quiz) para validar si los estudiantes comprendieron los conceptos de bloques, tratamientos y la prueba de Friedman antes de pasar a la programación?