La tabla 1 resume las resultados de un estudio realizado en Pereira, dónde se observó la presencia o ausencia de malezas, patógenos y enfermedades en los culivos de café.
knitr::include_graphics("/cloud/project/tabla2.PNG")
Tabla 1 Tabla con los resultados del estudio.
Interesa comprender la relación entre las tres variables sin que una sea necesariamente la “respuesta”, de este modo se usa un modelo loglineal.
data <- array (data = c (911, 44, 538, 456, 3, 2, 43, 279),
dim = c (2,2,2),
dimnames = list ("Malezas" = c ("Sí", "No"),
"Patogenos" = c ("Sí", "No"),
"Enfermedades" = c ("Sí", "No")))
# array: Función para crear una tabla con más de dos dimensiones. En esta ocasión el argumento dim dice que queremos crear una tabla con 2 filas, 2 columnas y 2 capas.
# dimnames, es un argumento que proporciona nombres para las dimensiones. Requiere un objeto de lista, por lo que la entrada del argumento en la función list.
data
## , , Enfermedades = Sí
##
## Patogenos
## Malezas Sí No
## Sí 911 538
## No 44 456
##
## , , Enfermedades = No
##
## Patogenos
## Malezas Sí No
## Sí 3 43
## No 2 279
Al imprimir se obtienen dos tablas de 2x2.
ftable (data, row.vars = c ("Malezas", "Patogenos"))
## Enfermedades Sí No
## Malezas Patogenos
## Sí Sí 911 3
## No 538 43
## No Sí 44 2
## No 456 279
# Para aplanar la tabla se usa ftable, el argumento row.vars especifica qué variables queremos en las filas y su respectivo orden.
addmargins (data)
## , , Enfermedades = Sí
##
## Patogenos
## Malezas Sí No Sum
## Sí 911 538 1449
## No 44 456 500
## Sum 955 994 1949
##
## , , Enfermedades = No
##
## Patogenos
## Malezas Sí No Sum
## Sí 3 43 46
## No 2 279 281
## Sum 5 322 327
##
## , , Enfermedades = Sum
##
## Patogenos
## Malezas Sí No Sum
## Sí 914 581 1495
## No 46 735 781
## Sum 960 1316 2276
# Antes de continuar con el modelado, se pueden explorar los datos. La función addmargins proporciona totales marginales.
Se observa que se realizarón 2276 observaciones en el estudio de la región y la mayoría de los resultados muestran presencia de malezas en los cultivos de café. La relación de presencia de enfermedades respecto a la ausencia es de 1949:327.
prop.table(data, margin = c(1,3))
## , , Enfermedades = Sí
##
## Patogenos
## Malezas Sí No
## Sí 0.6287095 0.3712905
## No 0.0880000 0.9120000
##
## , , Enfermedades = No
##
## Patogenos
## Malezas Sí No
## Sí 0.065217391 0.9347826
## No 0.007117438 0.9928826
# La función prop.table permite calcular proporciones de celda
En el estudio aquellos cultivos con presencia de malezas y patogenos, el 62% también tenia presencia de enfermedades. Asimismo, de aquellos que no tenian malezas ni patogenos, el 99% tampoco tenia enfermedades. Definitivamente parece haber algún tipo de relación aquí.
prop.table(data, margin = c(1,3))
## , , Enfermedades = Sí
##
## Patogenos
## Malezas Sí No
## Sí 0.6287095 0.3712905
## No 0.0880000 0.9120000
##
## , , Enfermedades = No
##
## Patogenos
## Malezas Sí No
## Sí 0.065217391 0.9347826
## No 0.007117438 0.9928826
# La función prop.table permite calcular proporciones de celda
data.df <- as.data.frame(as.table(data))
data.df[,-4] <- lapply(data.df[,-4], relevel, ref = "No")
data.df
## Malezas Patogenos Enfermedades Freq
## 1 Sí Sí Sí 911
## 2 No Sí Sí 44
## 3 Sí No Sí 538
## 4 No No Sí 456
## 5 Sí Sí No 3
## 6 No Sí No 2
## 7 Sí No No 43
## 8 No No No 279
# as.data.frame vuelve un objeto de tabla en R a un marco de datos con una columna para frecuencias de celda, donde cada fila representa una combinación única de variables.
# as.table permite convertir la matriz en una tabla.
# Los coeficientes del modelo se expresarán en términos de respuestas “sí”.
Supone que las tres variables son independientes entre sí, lo que parece muy poco probable.
mod0 <- glm(Freq ~ Patogenos + Enfermedades + Malezas,
data = data.df, family = poisson)
summary(mod0)
##
## Call:
## glm(formula = Freq ~ Patogenos + Enfermedades + Malezas, family = poisson,
## data = data.df)
##
## Deviance Residuals:
## 1 2 3 4 5 6 7 8
## 14.522 -17.683 -7.817 3.426 -12.440 -8.832 -8.436 19.639
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 4.17254 0.06496 64.234 < 2e-16 ***
## PatogenosSí -0.31542 0.04244 -7.431 1.08e-13 ***
## EnfermedadesSí 1.78511 0.05976 29.872 < 2e-16 ***
## MalezasSí 0.64931 0.04415 14.707 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 2851.5 on 7 degrees of freedom
## Residual deviance: 1286.0 on 4 degrees of freedom
## AIC: 1343.1
##
## Number of Fisher Scoring iterations: 6
# La función glm se usa para trabajar con modelos loglineales. Se modela con Freq como una función de las tres variables usando glm.
# En family se establece el argumento en poisson, ya que estamos modelando recuentos.
Mirando el resumen, parece que este es un gran modelo. Vemos coeficientes altamente significativos y valores p cercanos a 0. Pero para los modelos loglineales se quiere verificar la desviación residual. Como regla general, nos gustaría que tuviera un valor cercano a los grados de libertad. Aquí tenemos 1286 en 4 grados de libertad.Esto indica un mal ajuste.
pchisq(deviance(mod0), df = df.residual (mod0), lower.tail = F)
## [1] 3.574437e-277
Este p.valor nos indica que el modelo no es bueno, por ende se procede a realizarlo como un modelo de valores estimados.
Una forma más intuitiva de investigar el ajuste es comparar los valores ajustados con los valores observados.
cbind(mod0$data, fitted(mod0))
## Malezas Patogenos Enfermedades Freq fitted(mod0)
## 1 Sí Sí Sí 911 539.98258
## 2 No Sí Sí 44 282.09123
## 3 Sí No Sí 538 740.22612
## 4 No No Sí 456 386.70007
## 5 Sí Sí No 3 90.59739
## 6 No Sí No 2 47.32880
## 7 Sí No No 43 124.19392
## 8 No No No 279 64.87990
El modelo ajustado esta muy lejos de los valores observados. Por ejemplo, observamos que 3 resultados del estudio que tenian presencia de malezas y patogenos pero no de enfermedadades, y el modelo predice alrededor de 90 cultivos bajo estas condiciones.
margin.table(data, margin = 2)/sum(margin.table(data, margin = 2))
## Patogenos
## Sí No
## 0.4217926 0.5782074
0.4217926 / 0.5782074
## [1] 0.7294832
Según este modelo, las probabilidades de tener enfermedades son de aproximadamente 0,73 a 1, independientemente de si hay presencia de malezas o patogenos Sin embargo, sabemos que probablemente no sea una buena estimación.
Ajustemos un modelo más complejo que permite asociar variables entre sí, pero mantiene la misma asociación independientemente del nivel de la tercera variable. Esto quiere decir que por ejemplo, la presencia de patogenos y enfermedades tienen algún tipo de relación, pero esa relación es la misma independientemente de si hay presencia o no de malezas.
mod1 <- glm(Freq ~ (Patogenos + Enfermedades + Malezas)^2,
data = data.df, family = poisson)
summary(mod1)
##
## Call:
## glm(formula = Freq ~ (Patogenos + Enfermedades + Malezas)^2,
## family = poisson, data = data.df)
##
## Deviance Residuals:
## 1 2 3 4 5 6 7 8
## 0.02044 -0.09256 -0.02658 0.02890 -0.33428 0.49134 0.09452 -0.03690
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 5.63342 0.05970 94.361 < 2e-16 ***
## PatogenosSí -5.30904 0.47520 -11.172 < 2e-16 ***
## EnfermedadesSí 0.48772 0.07577 6.437 1.22e-10 ***
## MalezasSí -1.88667 0.16270 -11.596 < 2e-16 ***
## PatogenosSí:EnfermedadesSí 2.98601 0.46468 6.426 1.31e-10 ***
## PatogenosSí:MalezasSí 2.84789 0.16384 17.382 < 2e-16 ***
## EnfermedadesSí:MalezasSí 2.05453 0.17406 11.803 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 2851.46098 on 7 degrees of freedom
## Residual deviance: 0.37399 on 1 degrees of freedom
## AIC: 63.417
##
## Number of Fisher Scoring iterations: 4
Este modelo encaja mucho mejor. Observe la desviación residual (0.37399) en comparación con los grados de libertad (1).
pchisq(deviance(mod1), df = df.residual(mod1), lower.tail = F)
## [1] 0.5408396
El alto valor p dice que no tenemos pruebas suficientes para rechazar la hipótesis nula de que las frecuencias esperadas satisfacen nuestro modelo.
Una vez más, podemos comparar los valores ajustados y observados y ver qué tan bien coinciden:
cbind(mod1$data, fitted(mod1))
## Malezas Patogenos Enfermedades Freq fitted(mod1)
## 1 Sí Sí Sí 911 910.38317
## 2 No Sí Sí 44 44.61683
## 3 Sí No Sí 538 538.61683
## 4 No No Sí 456 455.38317
## 5 Sí Sí No 3 3.61683
## 6 No Sí No 2 1.38317
## 7 Sí No No 43 42.38317
## 8 No No No 279 279.61683
exp(coef(mod1)["EnfermedadesSí:MalezasSí"])
## EnfermedadesSí:MalezasSí
## 7.803201
Los cultivos con presencia de enfermedades tienen probabilidades estimadas de tener presencia de malezas que son 7 veces mayores que las probabilidades estimadas de los cultivos que no tienen enfermedades. Debido a que ajustamos un modelo de asociación homogéneo, la razón de posibilidades es la misma independientemente de si hay presnecia de patógenos o no.
Es una buena idea calcular un intervalo de confianza para estas estimaciones de razón de posibilidades. Podemos hacer eso con la función confint:
exp(confint(mod1, parm = c("PatogenosSí:EnfermedadesSí",
"PatogenosSí:MalezasSí",
"EnfermedadesSí:MalezasSí")))
## Waiting for profiling to be done...
## 2.5 % 97.5 %
## PatogenosSí:EnfermedadesSí 8.814046 56.64360
## PatogenosSí:MalezasSí 12.645760 24.06925
## EnfermedadesSí:MalezasSí 5.601452 11.09715
Preguntas
1. Cree una tabla que rompa por presencia de patógenos y que se vean las tablas 2*2 para las otras dos variables. ¿precibe alguna relación? ¿Aquellos cultivos con presencia de enfermedades son más propensos a tener patógenos? ¿Aquellos cultivos con presencia de malezas son más propensos a tener patogenos?
data1 <- array (data = c (911, 44, 538, 456, 3, 2, 43, 279),
dim = c (2,2,2),
dimnames = list ("Malezas" = c ("Sí", "No"),
"Enfermedades" = c ("Sí", "No"),
"Patógenos" = c ("Sí", "No")))
data1
## , , Patógenos = Sí
##
## Enfermedades
## Malezas Sí No
## Sí 911 538
## No 44 456
##
## , , Patógenos = No
##
## Enfermedades
## Malezas Sí No
## Sí 3 43
## No 2 279
prop.table(data1, margin = c(1,3))
## , , Patógenos = Sí
##
## Enfermedades
## Malezas Sí No
## Sí 0.6287095 0.3712905
## No 0.0880000 0.9120000
##
## , , Patógenos = No
##
## Enfermedades
## Malezas Sí No
## Sí 0.065217391 0.9347826
## No 0.007117438 0.9928826
De la tabla se puede evidenciar que aquellos cultivos de café que tengan presencia de una enfermedad son mas propensos a tener malezas, donde el 62% de estos tendrían a su vez patógenos. Adémas se puede observar que un 6% de los cultivos que no tienen patógenos, cuentan con presencia de enfermedad y malezas, frente a un 99% que no tienen enfermedad ni malezas, y los patógenos estan ausentes. De estos análisis, podría decirse (por ahora) que se evidencia algún tipo de relación entre estas tres variables.
2. Elimine interacciones dobles innecesarias y repita el proceso. ¿Mejora el modelo? Estime todos los valores y use el AIC para seleccionar el mejor modelo. Interprete las relaciones encontradas.
En el modelo todas las interacciones dobles son significativas, debido a que el p.valor es inferior al 5%, por ende no se realizó este punto.
3.* ¿Qué sucede si ajustamos un modelo con una interacción de tres vías?
El modelo con interacción de tres vías permite que las asociaciones por pares cambien según el nivel de la tercera variable, en un modelo saturado.
mod2 <- glm(Freq ~ (Patogenos * Enfermedades * Malezas)^2,
data = data.df, family = poisson)
summary(mod2)
##
## Call:
## glm(formula = Freq ~ (Patogenos * Enfermedades * Malezas)^2,
## family = poisson, data = data.df)
##
## Deviance Residuals:
## [1] 0 0 0 0 0 0 0 0
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 5.63121 0.05987 94.060 < 2e-16 ***
## PatogenosSí -4.93806 0.70964 -6.959 3.44e-12 ***
## EnfermedadesSí 0.49128 0.07601 6.464 1.02e-10 ***
## MalezasSí -1.87001 0.16383 -11.414 < 2e-16 ***
## PatogenosSí:EnfermedadesSí 2.59976 0.72698 3.576 0.000349 ***
## PatogenosSí:MalezasSí 2.27548 0.92746 2.453 0.014149 *
## EnfermedadesSí:MalezasSí 2.03538 0.17576 11.580 < 2e-16 ***
## PatogenosSí:EnfermedadesSí:MalezasSí 0.58951 0.94236 0.626 0.531600
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 2.8515e+03 on 7 degrees of freedom
## Residual deviance: 1.5388e-13 on 0 degrees of freedom
## AIC: 65.043
##
## Number of Fisher Scoring iterations: 3
La desviación de este modelo es básicamente 0 en 0 grados de libertad. Los recuentos ajustados coinciden con los recuentos observados, como se observa a continuación:
deviance(mod2)
## [1] 1.538769e-13
cbind(mod2$data, fitted(mod2))
## Malezas Patogenos Enfermedades Freq fitted(mod2)
## 1 Sí Sí Sí 911 911
## 2 No Sí Sí 44 44
## 3 Sí No Sí 538 538
## 4 No No Sí 456 456
## 5 Sí Sí No 3 3
## 6 No Sí No 2 2
## 7 Sí No No 43 43
## 8 No No No 279 279
En igualdad de condiciones, preferimos un modelo más simple. Por lo general, no queremos terminar con un modelo saturado que se ajuste perfectamente a nuestros datos. Sin embargo, podemos verificar que el modelo de asociación homogéneo se ajusta tan bien como el modelo saturado realizando una prueba de razón de verosimilitud:
anova (mod1, mod2)
## Analysis of Deviance Table
##
## Model 1: Freq ~ (Patogenos + Enfermedades + Malezas)^2
## Model 2: Freq ~ (Patogenos * Enfermedades * Malezas)^2
## Resid. Df Resid. Dev Df Deviance
## 1 1 0.37399
## 2 0 0.00000 1 0.37399
pchisq(0.373, df = 1, lower.tail = F)
## [1] 0.5413735
Esto dice que no rechazamos la hipótesis nula de que mod1 se ajusta tan bien como mod2.
REFERENCIAS
-Universidad de Virginia. 2016. Introducción a los modelos loglineales. Disponible en: https://data.library.virginia.edu/an-introduction-to-loglinear-models/