Asignatura: Estadística Aplicada con Python y R — Semana 5 (Probabilidad Condicional y Tablas de Contingencia)
Modalidad: Consola de R en vivo (Posit Cloud), individual o en parejas
Dataset: yates.oats, paquete
agridat — experimento real de parcelas divididas
(Rothamsted, 1931): 3 variedades de avena × 4 dosis de nitrógeno × 6
bloques = 72 observaciones
Entregable: Historial de comandos de R para el RMarkdown/RPubs
En 1931, en la Estación Experimental de Rothamsted (Inglaterra), se sembraron 3 variedades de avena (Golden Rain, Marvellous, Victory) en 6 bloques. Dentro de cada bloque, cada variedad se dividió en 4 subparcelas, y a cada subparcela se le asignó al azar una dosis de nitrógeno: 0, 0.2, 0.4 o 0.6 cwt/acre (un diseño de “parcela dividida” o split-plot). Se midió el rendimiento de grano de cada subparcela. Es uno de los conjuntos de datos más citados en el diseño de experimentos agrícolas — lo volverán a ver, con ANOVA de parcelas divididas, en tu curso de Diseño Experimental.
chisq.test() — con y sin corrección de Yates,
porque ahora sí es una tabla 2×2 — e interpretar correctamente el
resultado.Soils.install.packages("agridat")
library(agridat)
data(yates.oats)
str(yates.oats)
head(yates.oats)
nrow(yates.oats)
table(yates.oats$nitro) # las 4 dosis, 18 observaciones cada una
table(yates.oats$gen) # las 3 variedades, 24 observaciones cada una
Si los nombres de columna difieren levemente en tu versión del paquete (
names(yates.oats)), ajusta el resto del código con esos nombres — la lógica no cambia.
nitro — aquí SÍ hay un criterio establecido (no
estadístico): lo fijó el experimentoA diferencia del pH (donde el criterio lo da la agronomía), aquí el criterio lo da el propio diseño experimental: una subparcela recibió nitrógeno o no lo recibió. No hace falta inventar un punto de corte:
yates.oats$nitro_nivel <- ifelse(yates.oats$nitro == 0, "Sin_N", "Con_N")
yates.oats$nitro_nivel <- factor(yates.oats$nitro_nivel, levels = c("Sin_N", "Con_N"))
table(yates.oats$nitro_nivel)
yield (rendimiento) — aquí NO hay un umbral
agronómico universal → tercer cuartilNo existe un estándar único de “rendimiento alto/bajo” en avena (depende de variedad, época, unidades). Se sigue tu regla: todo lo que supere Q3 se clasifica como Alto.
q3_yield <- quantile(yates.oats$yield, probs = 0.75)
q3_yield
yates.oats$yield_nivel <- ifelse(yates.oats$yield > q3_yield, "Alto", "Bajo")
yates.oats$yield_nivel <- factor(yates.oats$yield_nivel, levels = c("Bajo", "Alto"))
table(yates.oats$yield_nivel)
Referencia: Q3 ≈ 121.25; esto deja 18 observaciones en “Alto” y 54 en “Bajo” (exactamente 25%/75%, por definición de cuartil).
tabla <- table(yates.oats$nitro_nivel, yates.oats$yield_nivel)
tabla
addmargins(tabla)
Salida de referencia (verificada):
Bajo Alto Sin_N 18 0 Con_N 36 18Totales de fila: Sin_N = 18, Con_N = 54. Totales de columna: Bajo = 54, Alto = 18. Gran total = 72.
# Condicional por fila: dado el nivel de nitrógeno, ¿qué tan probable es cada nivel de rendimiento?
prop.table(tabla, margin = 1)
# Condicional por columna: dado el nivel de rendimiento, ¿qué tan probable es cada nivel de nitrógeno?
prop.table(tabla, margin = 2)
# Conjunta
prop.table(tabla)
Referencia: - \(P(\text{Alto} \mid \text{Sin\_N}) = 0.000\) — ninguna subparcela sin nitrógeno alcanzó rendimiento alto. - \(P(\text{Alto} \mid \text{Con\_N}) = 0.333\) — una de cada tres subparcelas fertilizadas sí lo alcanzó. - \(P(\text{Con\_N} \mid \text{Alto}) = 1.000\) — el 100% de las subparcelas de rendimiento alto habían recibido nitrógeno. - \(P(\text{Sin\_N} \mid \text{Bajo}) = 0.333\).
Pregunta para la clase: \(P(\text{Alto}\mid\text{Con\_N})=0.333\) y \(P(\text{Con\_N}\mid\text{Alto})=1.000\) — ¿por qué son tan distintas si ambas “involucran” a Con_N y a Alto? (Dividen entre denominadores distintos: la primera entre el total de subparcelas fertilizadas [54], la segunda entre el total de subparcelas con rendimiento alto [18].)
chisq.test(tabla, correct = TRUE) # con corrección de Yates (default, tabla 2x2)
chisq.test(tabla, correct = FALSE) # sin corrección
Referencia: χ² = 8.00 (sin corrección) vs. χ² = 6.32 (con corrección de Yates), gl = 1, p = 0.0047 y p = 0.0119 respectivamente — ambos significativos a 0.05, pero nótese cuánto cambia el valor exacto: aquí, a diferencia de las tablas 3×3 de la sesión anterior, la corrección sí importa, porque solo aplica a tablas 2×2. Una celda tiene frecuencia esperada de 4.5 (ligeramente bajo el criterio informal de 5); como verificación adicional,
fisher.test(tabla)da p ≈ 0.0036, confirmando la conclusión.
SoilsAquí el argumento causal es más fuerte que en el ejercicio anterior, por una razón concreta: la dosis de nitrógeno fue asignada al azar a cada subparcela por el experimentador (no la eligió el suelo ni el agricultor). Eso es justamente lo que permite, en principio, interpretar una asociación como evidencia de causalidad — es la lógica central de tu curso de Diseño Experimental.
Pero hay que ser precisos:
aov(yield ~ block + gen*nitro, ...)) que se cubre en
Diseño Experimental.Pregunta de cierre: ¿qué le da más fuerza causal a
este experimento frente a Soils: el valor del p-valor, o el
hecho de que el nitrógeno se asignó al azar? (La aleatorización — un
p-valor pequeño en un estudio observacional como Soils
nunca deja de ser observacional.)
tabla_gen <- table(yates.oats$gen, yates.oats$yield_nivel)
tabla_gen
chisq.test(tabla_gen)
prop.table(tabla_gen, margin = 1)
Referencia: χ² ≈ 1.33, gl = 2, p ≈ 0.513 — no hay evidencia de asociación entre variedad y nivel de rendimiento. Buen contraste para la clase: no toda variable produce una tabla significativa; aquí el nitrógeno sí importa, la variedad (en este análisis simplificado) no.
history(max.show = Inf)
savehistory(file = "Semana5_YatesOats_Consola.Rhistory")
O en RStudio/Posit Cloud: pestaña History →
seleccionar todo → To Source. Ese bloque limpio se pega
como chunk de R en el .Rmd para Knit →
Publish a RPubs.
Te recomiendo correr esto una vez antes de clase: aunque verifiqué
los 72 valores contra el dataset original publicado (Yates 1935 /
Rothamsted Report), la forma exacta en que agridat etiqueta
gen (nombres completos vs. abreviados) puede variar
levemente entre versiones del paquete — un detalle menor que
str() resuelve al instante.