Vamos a usar el conjunto de datos correspondiente al número de muertes por cáncer de pulmón (cander.dat) el cual puede ser descargado de la siguiente dirección: http://stat.ufl.edu/~aa/glm/data/ del autor [@agresti2015foundations].
La base de datos contiene 3 filas y 5 columnas(variables):
count) del número de pacientes que murieron clasificados por el estado de la enfermedad (stage)time). histology), es el tipo de cancer que padece el paciente.stage) en la que se encuentra la enfermedad del paciente.risktime) corresponde al número de pacientes en riesgo en el período de seguimiento.# Lee base de datos del sitio web
library(readr)
cancer <- read_csv("~/Desktop/libro_glm/datos/cancer.csv")
head(cancer)
# A tibble: 6 x 5
time histology stage count risktime
<int> <int> <int> <int> <int>
1 1 1 1 9 157
2 1 2 1 5 77
3 1 3 1 1 21
4 2 1 1 2 139
5 2 2 1 2 68
6 2 3 1 1 17
Veamos la distribución de los conteos por estadío (stage) y la media y desviación estándar de los conteos
en cada estadío.
# Histograma de conteos por stage
library(ggplot2)
ggplot(cancer, aes(count, fill = stage)) +
geom_histogram(binwidth = 1) +
facet_grid(stage ~., margins = TRUE, scales = "free")+
theme(text=element_text(size = 20), strip.text.y = element_blank())
Veamos un modelo para el número de pacientes que murieron sin tener en cuenta el número de pacientes en riesgo. Asumamos que \( Y_i \sim Poisson(\mu_i) \) donde
\[ \log(\mu_i) = \beta_0 + \beta_j^H + \beta_k^S + \beta_l^T \]
\[ \mu_i = e^{\beta_0 + \beta_j^H + \beta_k^S + \beta_l^T}=e^{\beta_0} e^{\beta_j^H} e^{\beta_k^S} e^{\beta_l^T} \]
Note que todas las variables explicativas son factores. Por ejemplo, para histología hay tres coeficientes \( \beta_j^H \), \( \beta_k^S \) y \( \beta_l^T \) pero como es costumbre en R el primer coeficiente es igual a 0 (primer nivel de referencia).
# Media and Des.est por stage
d <- with(cancer, tapply(count, stage, function(x) {
data.frame(Media=mean(x), SD =sd(x))}))
unlist(d)
1.Media 1.SD 2.Media 2.SD 3.Media 3.SD
2.76 2.96 3.62 3.06 10.43 10.77
# MLG para conteo de muertes de cáncer
fit.cancer = glm(count ~ factor(histology)+factor(stage)+factor(time),
family = poisson(link = log), data = cancer)
summary(fit.cancer)
Call:
glm(formula = count ~ factor(histology) + factor(stage) + factor(time),
family = poisson(link = log), data = cancer)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.540 -0.927 -0.289 0.725 2.453
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 2.316 0.159 14.53 < 2e-16 ***
factor(histology)2 -0.511 0.122 -4.20 0.000027063984741 ***
factor(histology)3 -1.019 0.145 -7.04 0.000000000001939 ***
factor(stage)2 0.270 0.174 1.55 0.12108
factor(stage)3 1.329 0.148 9.00 < 2e-16 ***
factor(time)2 -0.519 0.149 -3.49 0.00049 ***
factor(time)3 -0.788 0.163 -4.85 0.000001244789911 ***
factor(time)4 -0.904 0.169 -5.34 0.000000093711368 ***
factor(time)5 -1.963 0.259 -7.58 0.000000000000035 ***
factor(time)6 -1.800 0.241 -7.46 0.000000000000088 ***
factor(time)7 -1.851 0.247 -7.50 0.000000000000063 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for poisson family taken to be 1)
Null deviance: 419.708 on 62 degrees of freedom
Residual deviance: 79.989 on 52 degrees of freedom
AIC: 287.8
Number of Fisher Scoring iterations: 5
# MLG para conteo de muertes de cáncer
library(car)
Anova(fit.cancer, type=3)
Analysis of Deviance Table (Type III tests)
Response: count
LR Chisq Df Pr(>Chisq)
factor(histology) 57.4 2 0.00000000000035 ***
factor(stage) 123.6 2 < 2e-16 ***
factor(time) 158.8 6 < 2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
ic.fit.cancer = exp(confint(fit.cancer)) # intervalo confianza razón
ic.fit.cancer
2.5 % 97.5 %
(Intercept) 7.3448 13.726
factor(histology)2 0.4714 0.760
factor(histology)3 0.2701 0.477
factor(stage)2 0.9327 1.851
factor(stage)3 2.8484 5.087
factor(time)2 0.4426 0.794
factor(time)3 0.3282 0.622
factor(time)4 0.2881 0.560
factor(time)5 0.0816 0.227
factor(time)6 0.1000 0.259
factor(time)7 0.0938 0.248
\[ R^2_{pseudo}=\frac{Null\ deviance-Residual\ deviance}{Null\ deviance} \]
como una medida de ajuste similar al coeficiente de determinación en modelos lineales.
Esta cantidad se conoce como el pseudo \( R^2 \). En este caso \( R^2_{pseudo} = 0.81 \), lo cual indicaría que las variables explican aproximadamente el 82\% de la variabilidad del número de muertes.
En términos de interpretación de los coeficientes podemos decir, por ejemplo, que el número promedio de muertes en la etapa 3 es aproximadamente \( \exp(1.3286) = 3.776 \) veces el número promedio de muertes de la etapa 1, después de ajustar por tiempo de seguimiento y histología (intervalo del 95\% de confianza (2.848, 5.087)).
Según la salida, todas las variables son significativas para explicar el número promedio de muertes por cáncer. Este resultado se debe revisar ya que estamos ignorando el número de pacientes en riesgo.
Si queremos determinar si hay diferencia significativa entre el número promedio de muertes entre la etapa 2 y la etapa 1 (referencia) es suficiente con llevar a cabo una prueba de hipótesis para el coeficiente de la etapa 2.
Como el \( p-valor \) es menor que 0.05 (\( p = 0.121084 \)) entonces no rechazamos \( H_0: \beta_2^S = 0 \).
Es decir, podemos concluir que el número promedio de muertes en la etapa 2 y 1 no son estadísticamente diferentes.
Note que la estimación puntual de esta razón es igual a \( \exp(0.2703) = 1.31 \) con un intervalo de 95\% de confianza (0.933, 1.851).
El hecho que el intervalo incluya el 1 respalda el resultado de la prueba de hipótesis (razón de promedio de muertes se puede considerar 1:1).
Si el investigador está interesado en estimar la razón del promedio de muertes entre la etapa 2 y 3 entonces se puede recurrir a dos estrategias.
La primera consiste en ajustar nuevamente el modelo pero considerando el tercer nivel de la variable stage como referencia.
La seguna estrategia es escribir la razón del promedio de muertes entre la etapa 2 y 3 en términos del modelo original.
# Modelo con stage=3 como nivel de referencia (contr.SAS)
cancer$f.stage <- factor(cancer$stage) #convertir en factor stage
contrasts(cancer$f.stage) <- contr.treatment(3, base = 3) # creamos el contraste
fit.cancer2 = glm( count ~ factor(histology) + f.stage + factor(time),
family = poisson(link = log), data = cancer)
coef(fit.cancer2)
(Intercept) factor(histology)2 factor(histology)3
3.645 -0.511 -1.019
f.stage1 f.stage2 factor(time)2
-1.329 -1.058 -0.519
factor(time)3 factor(time)4 factor(time)5
-0.788 -0.904 -1.963
factor(time)6 factor(time)7
-1.800 -1.851
ic.fit.cancer2 = exp(confint(fit.cancer2))
ic.fit.cancer2
2.5 % 97.5 %
(Intercept) 30.5233 47.503
factor(histology)2 0.4714 0.760
factor(histology)3 0.2701 0.477
f.stage1 0.1966 0.351
f.stage2 0.2658 0.448
factor(time)2 0.4426 0.794
factor(time)3 0.3282 0.622
factor(time)4 0.2881 0.560
factor(time)5 0.0816 0.227
factor(time)6 0.1000 0.259
factor(time)7 0.0938 0.248
estimable de la librería gmodels con el modelo original que tiene el primer nivel de la etapa como referencia. Antes de usar el programa veamos como escribimos la razón promedio de muertes entre la etapa 2 y 3 en términos del modelo. Se deja para el lector. # Usando la combinación lineal de coeficientes
fit.cancer = glm( count ~ factor(histology) + factor(stage) + factor(time),
family = poisson(link = log), data = cancer)
library(gmodels)
contrast = estimable(fit.cancer, c("factor(stage)2"=1, "factor(stage)3"=-1),
conf.int=.95)
contrast
Estimate Std. Error X^2 value DF Pr(>|X^2|)
(0 0 0 1 -1 0 0 0 0 0 0) -1.06 0.133 63.2 1 1.89e-15
Lower.CI Upper.CI
(0 0 0 1 -1 0 0 0 0 0 0) -1.32 -0.794
exp(contrast$Estimate) # estimación puntual
[1] 0.347
# Intervalo de confianza - dos formas de calcularlo
exp(contrast$Lower.CI) # límite inferior 95% CI
[1] 0.266
exp(contrast$Estimate-1.96*contrast$Std.) # límite inferior 95% CI
[1] 0.267
exp(contrast$Upper.CI) # límite superior 95% CI
[1] 0.452
exp(contrast$Estimate+1.96*contrast$Std.) # límite superior 95% CI
[1] 0.45
stage.1 <- function(coun) exp(fit.cancer2$coef[1] +
fit.cancer2$coef[2] * coun)
stage.2 <- function(coun) exp(fit.cancer2$coef[1] +
fit.cancer2$coef[2] * coun +
fit.cancer2$coef[3])
stage.3 <- function(coun) exp(fit.cancer2$coef[1] +
fit.cancer2$coef[2] * coun +
fit.cancer2$coef[4])
p1<- ggplot(cancer, aes(x=time, y= count, col = factor(stage))) +
geom_point(size=3) +
stat_function(fun = stage.1, col = "blue",size=2) +
stat_function(fun = stage.2, col = "green",size=2) +
stat_function(fun = stage.3, col = "red",size=2) +
labs(x = "Time", y = "Count")+
theme(text=element_text(size = 20))
p1
Ejemplo 1. Los administradores escolares estudian el comportamiento de ausencia de los estudiantes de tercer año de secundaria en dos escuelas. Los predictores de la cantidad de días de ausencia incluyen el tipo de programa en el que se inscribe el alumno y una prueba estandarizada en matemáticas.
Ejemplo 2. Un investigador relacionado con la salud está estudiando el número de visitas hospitalarias realizadas en los últimos 12 meses por personas de la tercera edad en una comunidad según las características de las personas y los tipos de planes de salud según cada uno de ellos.
Tenemos datos de ausencia de 314 estudiantes de secundaria de dos escuelas secundarias urbanas en el archivo ausencia. La variable respuesta de interés es días ausentes, daysabs. La variable math brinda el puntaje matemático estandarizado para cada alumno. La variable prog es una variable nominal de tres niveles que indica el tipo de programa de instrucción en el que se inscribe el alumno y la variable gender es el sexo del individuo.
library("readr")
ausencia <- read_csv("~/Desktop/libro_glm/datos/ausencia.csv")
ausencia <- within(ausencia, {
prog <- factor(prog, levels=1:3, labels=c("General", "Academic","Vocational"))
id <- factor(id)
})
#leyendo los datos auto
head(ausencia)
# A tibble: 6 x 5
id gender math daysabs prog
<fct> <chr> <int> <int> <fct>
1 1001 male 63 4 Academic
2 1002 male 27 4 Academic
3 1003 female 20 2 Academic
4 1004 female 16 3 Academic
5 1005 female 2 3 Academic
6 1006 female 71 13 Academic
summary(ausencia)
id gender math daysabs
1001 : 1 Length:314 Min. : 1.0 Min. : 0
1002 : 1 Class :character 1st Qu.:28.0 1st Qu.: 1
1003 : 1 Mode :character Median :48.0 Median : 4
1004 : 1 Mean :48.3 Mean : 6
1005 : 1 3rd Qu.:70.0 3rd Qu.: 8
1006 : 1 Max. :99.0 Max. :35
(Other):308
prog
General : 40
Academic :167
Vocational:107
d <- with(cancer, tapply(count, stage, function(x) {
data.frame(Media = mean(x), SD = sd(x))}))
unlist(d)
1.Media 1.SD 2.Media 2.SD 3.Media 3.SD
2.76 2.96 3.62 3.06 10.43 10.77
A continuación utilizamos la función glm.nb del paquete MASS para estimar una regresión binomial negativa.
library("MASS")
mod.nb <- glm.nb(daysabs ~ math + prog, data = ausencia)
summary(mod.nb)
Call:
glm.nb(formula = daysabs ~ math + prog, data = ausencia, init.theta = 1.032713156,
link = log)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.155 -1.019 -0.369 0.229 2.527
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 2.61527 0.19746 13.24 < 2e-16 ***
math -0.00599 0.00251 -2.39 0.017 *
progAcademic -0.44076 0.18261 -2.41 0.016 *
progVocational -1.27865 0.20072 -6.37 0.00000000019 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for Negative Binomial(1.03) family taken to be 1)
Null deviance: 427.54 on 313 degrees of freedom
Residual deviance: 358.52 on 310 degrees of freedom
AIC: 1741
Number of Fisher Scoring iterations: 1
Theta: 1.033
Std. Err.: 0.106
2 x log-likelihood: -1731.258
A continuación una regresión binomial negativa sin la variable prog.
library("MASS")
mod.nb_sin_prog <- glm.nb(daysabs ~ math, data = ausencia)
summary(mod.nb_sin_prog)
Call:
glm.nb(formula = daysabs ~ math, data = ausencia, init.theta = 0.8558564931,
link = log)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.060 -1.114 -0.345 0.250 2.307
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 2.24663 0.13916 16.14 < 2e-16 ***
math -0.01034 0.00259 -3.99 0.000066 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for Negative Binomial(0.856) family taken to be 1)
Null deviance: 375.05 on 313 degrees of freedom
Residual deviance: 357.90 on 312 degrees of freedom
AIC: 1782
Number of Fisher Scoring iterations: 1
Theta: 0.8559
Std. Err.: 0.0829
2 x log-likelihood: -1776.3060
Comparemos los modelos mod.nb y mod.nb_sin_prog con la proeba LRT (anova)
anova(mod.nb, mod.nb_sin_prog)
Likelihood ratio tests of Negative Binomial Models
Response: daysabs
Model theta Resid. df 2 x log-lik. Test df LR stat.
1 math 0.856 312 -1776
2 math + prog 1.033 310 -1731 1 vs 2 2 45
Pr(Chi)
1
2 0.000000000165
La prueba de chi-cuadrado con dos grados de libertad indica que el progreso es un predictor estadísticamente significativo de daysabs.
La desviación nula se calcula a partir de un modelo de solo interceptación con 313 grados de libertad. Luego vemos la desviación residual, la desviación del modelo completo. También se nos muestra el AIC y la probabilidad de \( 2*log \).
mod.p <- glm(daysabs ~ math + prog, family = "poisson", data = ausencia)
pchisq(2 * (logLik(mod.nb) - logLik(mod.p)), df = 1, lower.tail = FALSE)
'log Lik.' 2.16e-203 (df=5)
AIC(mod.nb)
[1] 1741
AIC(mod.p)
[1] 2665
Podemos obtener los intervalos de confianza para los coeficientes mediante el perfil de la función de verosimilitud.
est <- cbind(Estimate = coef(mod.nb), confint(mod.nb))
est
Estimate 2.5 % 97.5 %
(Intercept) 2.61527 2.2421 3.01294
math -0.00599 -0.0109 -0.00107
progAcademic -0.44076 -0.8101 -0.09264
progVocational -1.27865 -1.6835 -0.89008
exp(est)
Estimate 2.5 % 97.5 %
(Intercept) 13.671 9.413 20.347
math 0.994 0.989 0.999
progAcademic 0.644 0.445 0.912
progVocational 0.278 0.186 0.411
La forma de la ecuación modelo para la regresión binomial negativa es la misma que para la regresión de Poisson. El registro del resultado se predice con una combinación lineal de los predictores:
\[ ln(\widehat{daysabs_i}) = \hat{\beta}_0 + \hat{\beta}_1(prog_i = 2) + \hat{\beta}(prog_i = 3) + \hat{\beta}math_i \]
\[ \begin{align*} \widehat{daysabs_i} &= e^{\hat{\beta}_0 + \hat{\beta}_1(prog_i = 2) + \hat{\beta}(prog_i = 3) + \hat{\beta}math_i} \\ &= e^{\hat{\beta}_0}e^{\hat{\beta}_1(prog_i = 2)}e^{b_2(prog_i = 3)}e^{\hat{\beta}math_i} \end{align*} \]
Para obtener ayuda en la comprensión del modelo, podemos ver los conteos predichos para varios niveles de nuestros predictores. A continuación, creamos nuevos conjuntos de datos con valores de math y prog y luego usamos el comando de predict para calcular el número predicho de eventos.
Primero, podemos ver los conteos predichos para cada valor de prog mientras mantenemos math en su valor medio. Para hacer esto, creamos un nuevo conjunto de datos con las combinaciones de prog y math para los cuales nos gustaría encontrar los valores predichos, luego usamos el comando de predicción.
newdata1 <- data.frame(math = mean(ausencia$math), prog = factor(1:3, levels = 1:3,
labels = levels(ausencia$prog)))
newdata1$phat <- predict(mod.nb, newdata1, type = "response")
newdata1
math prog phat
1 48.3 General 10.24
2 48.3 Academic 6.59
3 48.3 Vocational 2.85
newdata2 <- data.frame(
math = rep(seq(from = min(ausencia$math), to = max(ausencia$math), length.out = 100), 3),
prog = factor(rep(1:3, each = 100), levels = 1:3, labels =
levels(ausencia$prog)))
newdata2 <- cbind(newdata2, predict(mod.nb, newdata2, type = "link", se.fit=TRUE))
newdata2 <- within(newdata2, {
DaysAbsent <- exp(fit)
LL <- exp(fit - 1.96 * se.fit)
UL <- exp(fit + 1.96 * se.fit)
})
p2 <- ggplot(newdata2, aes(math, DaysAbsent)) +
geom_ribbon(aes(ymin = LL, ymax = UL, fill = prog), alpha = .25) +
geom_line(aes(colour = prog), size = 2) +
labs(x = "Math", y = "Predichos: cantidad de días de ausencia")+
theme(text=element_text(size = 20))
p2