library(Hmisc); library(ggpubr)
Hmisc::getHdata(acath)
head(acath)
## sex age cad.dur choleste sigdz tvdlm
## 1 0 73 132 268 1 1
## 2 0 68 85 120 1 1
## 3 0 54 45 NA 1 0
## 4 1 58 86 245 0 0
## 5 1 56 7 269 0 0
## 6 0 64 0 NA 1 0
Este conjunto de dados e da Duke University Cardiovascular Disease Databank e consiste em 3504 pacientes e seis variáveis. Os pacientes foram encaminhados para a Duke University Medical Center com dor no peito.
Algumas análises interessantes incluem prever a probabilidade de doenca coronaria, ou seja, >= 75% de estreitamento do diametro em pelo menos uma arteria coronária importante e prever a probabilidade de doença coronária grave, uma vez que é uma doença significativa. A primeira análise usaria sigdz como variável de resposta e a segunda análise usaria tvdlm no subconjunto de pacientes com sigdz = 1.
Doença coronária grave é definida como três vasos doentes ou doença principal na esquerda e é denotada por tvdlm = 1. Temos como covariável o sexo do paciente, denotado como sex = 0 para o sexo masculino e sex = 1 para o sexo feminino.
Referência: http://biostat.mc.vanderbilt.edu/wiki/Main/DataSets
Sexo = factor(acath$sex, levels = c(0,1), labels = c("Masculino","Feminino"))
Idade = acath$age
dados = data.frame(Sexo,Idade)
Desta maneira transformamos a variável sex em um fator com dois níveis nominais e na nova variável Idade registramos a idade (age) do paciente.
library(ggplot2)
ggplot(dados, aes(Sexo)) + geom_bar() + ylab("Contagem")
Observamos que a maioria dos pacientes pertencem ao sexo masculino. Temos ainda em cad.dur a duração dos sintomas de doença arterial coronáriana e em choleste o nível de colesterol no sangue.
Prevendo a probabilidade de doença coronária utilizando como resposta sigdz
Resposta = factor(acath$sigdz, levels=c(0,1), labels=c('Não','Sim'))
Colesterol = acath$choleste
Cad.dur = acath$cad.dur
dados1 = data.frame(Resposta, Colesterol, Cad.dur, Sexo, Idade)
par(mfrow=c(1,1), mar=c(3,3,1,1), cex=1.0)
mosaicplot(table(Resposta,Sexo), xlab='Doença coronária', main='')
ggstripchart(dados1, y = "Colesterol", x = "Sexo",
color = "Resposta", palette = c("#00AFBB", "#FC4E07"))
ggboxplot(dados1, y = "Colesterol", x = "Sexo",
color = "Resposta", palette = c("#00AFBB", "#FC4E07"))
ggstripchart(dados1, x = "Idade", y = "Colesterol", font.tickslab = c(8, "bold", "black"),
color = "Resposta", palette = c("#00AFBB", "#FC4E07"))
ggstripchart(dados1, x = "Resposta", y = "Cad.dur", color = "Sexo", palette = c("#00AFBB", "#FC4E07"))
Observando as demais variáveis explicativas.
plot(Colesterol, Resposta, pch=19, ylab='Doença coronária', xlab='Colesterol')
plot(Idade, Resposta, pch=19, ylab='Doença coronária', xlab='Idade')
plot(Cad.dur, Resposta, pch=19, ylab='Doença coronária', xlab='Duração dos sintomas')
Percebemos que a doença coronária se manifesta mais no sexo masculino e está clara a influença da idade, mas não está clara a influença do nível de colesterol e nem da duração dos sintomas.
modelo00 = glm(Resposta ~ Idade + Sexo + Cad.dur + Colesterol, family=binomial(link='logit'), data = dados1)
modelo01 = update(modelo00, family=binomial(link='probit'))
modelo02 = update(modelo00, family=binomial(link='cloglog'))
modelo03 = update(modelo00, family=binomial(link='cauchit'))
AIC(modelo00,modelo01,modelo02,modelo03)
## df AIC
## modelo00 5 2354.626
## modelo01 5 2355.864
## modelo02 5 2353.651
## modelo03 5 2360.281
Selecionamos a função de ligação complementar log-log, menor valor de AIC, como a mais adequada.
modelo04 = step(modelo02)
## Start: AIC=2353.65
## Resposta ~ Idade + Sexo + Cad.dur + Colesterol
##
## Df Deviance AIC
## - Cad.dur 1 2345.4 2353.4
## <none> 2343.7 2353.7
## - Colesterol 1 2425.2 2433.2
## - Idade 1 2504.3 2512.3
## - Sexo 1 2750.3 2758.3
##
## Step: AIC=2353.43
## Resposta ~ Idade + Sexo + Colesterol
##
## Df Deviance AIC
## <none> 2345.4 2353.4
## - Colesterol 1 2425.5 2431.5
## - Idade 1 2509.8 2515.8
## - Sexo 1 2751.5 2757.5
De maneira automática não descartamos nenhuma variável explicativa.
summary(modelo04)
##
## Call:
## glm(formula = Resposta ~ Idade + Sexo + Colesterol, family = binomial(link = "cloglog"),
## data = dados1)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.8908 -0.8981 0.5030 0.7978 2.0801
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.804673 0.228822 -12.257 <2e-16 ***
## Idade 0.040300 0.003337 12.078 <2e-16 ***
## SexoFeminino -1.323691 0.073485 -18.013 <2e-16 ***
## Colesterol 0.005414 0.000601 9.007 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 2895.3 on 2257 degrees of freedom
## Residual deviance: 2345.4 on 2254 degrees of freedom
## (1246 observations deleted due to missingness)
## AIC: 2353.4
##
## Number of Fisher Scoring iterations: 5
Procurando alternativas.
par(mfrow=c(1,1),mar=c(5,4,1,1),cex=1.0)
Transformada = I(log(Colesterol)/I(Idade^2))
xyplot(Transformada ~ Resposta | Sexo, data = dados1)
modelo05 = glm(Resposta ~ Sexo + Transformada, family=binomial(link='cloglog'))
summary(modelo05)
##
## Call:
## glm(formula = Resposta ~ Sexo + Transformada, family = binomial(link = "cloglog"))
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.2174 -0.9963 0.5538 0.7497 2.4785
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 1.23237 0.08009 15.39 <2e-16 ***
## SexoFeminino -1.19605 0.07000 -17.09 <2e-16 ***
## Transformada -336.01229 31.63797 -10.62 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 2895.3 on 2257 degrees of freedom
## Residual deviance: 2443.8 on 2255 degrees of freedom
## (1246 observations deleted due to missingness)
## AIC: 2449.8
##
## Number of Fisher Scoring iterations: 5
residuos = resid(modelo05, type='pearson')
par(mfrow=c(2,2),mar=c(5,4,1,1),cex=0.8)
plot(residuos, pch=19, cex=0.6)
grid()
hist(residuos)
grid()
box()
qqnorm(residuos, pch=19, cex=0.6)
grid()
plot(residuos~fitted(modelo05), pch=19, cex=0.8)
grid()
par(mfrow=c(1,1),mar=c(5,4,1,1),cex=1.0)
plot(modelo05$y~fitted(modelo05), pch=19,cex=0.8, xlab='Valores preditos',
ylab='Valores observados')
grid()
Observamos que no gráfico de valores estimados vs observados há muitos erros nas estimativas da resposta.
PERGUNTA: para quais valores de estimativa da P(Y = 1) deve-se assumir que o valor estimado da resposta é Y = 1 e para quais Y = 0?
mu.preditos=predict(modelo05,type='response')
Y.preditos1=ifelse(mu.preditos>0.5,1,0)
table(modelo05$y,Y.preditos1)
## Y.preditos1
## 0 1
## 0 452 316
## 1 268 1222
Y.preditos2=ifelse(mu.preditos>0.7,1,0)
table(modelo05$y,Y.preditos2)
## Y.preditos2
## 0 1
## 0 534 234
## 1 453 1037
Y.preditos3=ifelse(mu.preditos>0.4,1,0)
table(modelo05$y,Y.preditos3)
## Y.preditos3
## 0 1
## 0 227 541
## 1 106 1384
Y.preditos4=ifelse(mu.preditos>0.9,1,0)
table(modelo05$y,Y.preditos4)
## Y.preditos4
## 0 1
## 0 765 3
## 1 1440 50
Para decidirmos adequadamente o valor de corte para considerarmos como reposta Y = 1 ou Y = o utilizamos a chamada Curva ROC.
library(pROC)
plot.roc(modelo05$y,fitted(modelo05))
grid()
Y.preditos5=ifelse(mu.preditos>0.7,1,0)
table(modelo05$y,Y.preditos5)
## Y.preditos5
## 0 1
## 0 534 234
## 1 453 1037
Sensitividade (verdadeiros positivos) 70%
Specificidade (verdadeiros negativos) = 70%