Erforderliche Pakete laden

library(rms)    # binär logistische Regression
library(MASS)   # Modellvereinfachung
library(DAAG)   # Kreuzvalidierung
library(pROC)   # ROC-Analyse

Datensatz einlesen und Modell spezifizieren

# Datensatz 'data': pro Versuchsperson eine Zeile
data <- read.table("https://mmi.psycho.unibas.ch/r-toolbox/data/LR1.txt", header=TRUE)

# Modell spezifizieren
model <- Symptom~Alter+Geschlecht

Binär logistische Regression

library(rms)
variablen <- all.vars(model)
data2 <- na.omit(data[, variablen, drop=FALSE])
data2[,variablen[1]] <- as.factor(data2[,variablen[1]])
m <- lrm(model, data=data2, x=TRUE, y=TRUE)

# Wichtigkeit der Prädiktoren/Faktoren
Prädiktoren <- anova(m)

# Pseudo R2
model0 <- as.formula(paste(variablen[1], "~1", sep=""))   # Nullmodell
m0<-glm(model0, data = data2, family=binomial(link=logit))
n <- nrow(na.omit(data2[,variablen]))
Cox.and.Snell <- as.numeric(1-exp((2/n)*(logLik(m0)-logLik(m))))
Negelkerke <- as.numeric((1-exp((2/n)*(logLik(m0)-logLik(m))))/(1-exp(logLik(m0)*(2/n))))
McFadden <- as.numeric(1-(logLik(m)/logLik(m0)))
R2 <- data.frame(Cox.and.Snell,Negelkerke,McFadden)

# Klassifikation
pr <- predict(m, type="fitted"); pr.nominal <- pr
pr.nominal[pr < .5] <- levels(data2[,variablen[1]])[1]
pr.nominal[pr >= .5] <- levels(data2[,variablen[1]])[2]
pr.nominal <- factor(pr.nominal, levels= levels(data2[,variablen[1]]))
klass.tab <- xtabs(~ data2[,variablen[1]] + pr.nominal)
# Nach Zufall zu erwartender Anteil richtiger Klassifikationen
Zufall <- as.numeric(rowSums(klass.tab) %*% rowSums(klass.tab)/sum( (klass.tab))^2)
# Anteil richtig klassifiziert
ant.ri.kl <- sum(diag(klass.tab))/sum(klass.tab) # insgesamt
Prozent.korrekt <- diag(klass.tab)/apply(klass.tab,1,sum)*100 # pro Zeile
klass.tab  <-cbind(klass.tab, "korrekt in %"=Prozent.korrekt)
names(dimnames(klass.tab)) <- c("beobachtet", "vorhergesagt")

# Output
list("Tests für das Gesamtmodell und pro Parameter"=m, "Odds Ratios: exp(B)"=exp(m$coeff), "Tests pro Prädiktor/Faktor"=Prädiktoren, "Pseudo R2"=R2, Klassifikation=klass.tab, "Anteil richtig klassifizierter Fälle"=ant.ri.kl, "Nach Zufall zu erwartender Anteil richtig klassifizierter Fälle" = Zufall)
## $`Tests für das Gesamtmodell und pro Parameter`
## Logistic Regression Model
##  
##  lrm(formula = model, data = data2, x = TRUE, y = TRUE)
##  
##                        Model Likelihood    Discrimination    Rank Discrim.    
##                              Ratio Test           Indexes          Indexes    
##  Obs            40    LR chi2     16.54    R2       0.451    C       0.849    
##   negativ       20    d.f.            2    g        2.104    Dxy     0.698    
##   positiv       20    Pr(> chi2) 0.0003    gr       8.199    gamma   0.703    
##  max |deriv| 7e-08                         gp       0.350    tau-a   0.358    
##                                            Brier    0.162                     
##  
##                      Coef    S.E.   Wald Z Pr(>|Z|)
##  Intercept           -6.3531 2.7793 -2.29  0.0223  
##  Alter                0.1581 0.0616  2.56  0.0103  
##  Geschlecht=weiblich -3.4898 1.1992 -2.91  0.0036  
##  
## 
## $`Odds Ratios: exp(B)`
##           Intercept               Alter Geschlecht=weiblich 
##         0.001741315         1.171234491         0.030506119 
## 
## $`Tests pro Prädiktor/Faktor`
##                 Wald Statistics          Response: Symptom 
## 
##  Factor     Chi-Square d.f. P     
##  Alter      6.58       1    0.0103
##  Geschlecht 8.47       1    0.0036
##  TOTAL      8.79       2    0.0123
## 
## $`Pseudo R2`
##   Cox.and.Snell Negelkerke  McFadden
## 1     0.3385871  0.4514495 0.2981885
## 
## $Klassifikation
##           vorhergesagt
## beobachtet negativ positiv korrekt in %
##    negativ      15       5           75
##    positiv       4      16           80
## 
## $`Anteil richtig klassifizierter Fälle`
## [1] 0.775
## 
## $`Nach Zufall zu erwartender Anteil richtig klassifizierter Fälle`
## [1] 0.5

Modellvereinfachung

library(MASS)
m.glm <- glm(model, data=data2, family='binomial')
stepAIC(m.glm, direction="both")
## Start:  AIC=44.92
## Symptom ~ Alter + Geschlecht
## 
##              Df Deviance    AIC
## <none>            38.917 44.917
## - Alter       1   48.869 52.869
## - Geschlecht  1   53.023 57.023
## 
## Call:  glm(formula = Symptom ~ Alter + Geschlecht, family = "binomial", 
##     data = data2)
## 
## Coefficients:
##        (Intercept)               Alter  Geschlechtweiblich  
##            -6.3531              0.1581             -3.4898  
## 
## Degrees of Freedom: 39 Total (i.e. Null);  37 Residual
## Null Deviance:       55.45 
## Residual Deviance: 38.92     AIC: 44.92

k-fold Cross Validation

k <- 10     # k eingeben
library(DAAG)
m.glm <- glm(model, data=data2, family='binomial')
CVbinary(m.glm, rand=NULL, nfolds=k, print.details=TRUE)
## 
## Fold:  10 7 6 3 9 4 2 8 5 1
## Internal estimate of accuracy = 0.775
## Cross-validation estimate of accuracy = 0.675

ROC-Analyse

# Prädiktor spezifizieren
# Entweder die Bezeichnung der Prädiktorvariable im Datensatz
# oder den Vektor mit den vorhergesagten Wahrscheinlichkeiten (pr) angeben
library(pROC)
predictor <- pr
response <- data2[,variablen[1]]
ROC <- roc(response, predictor, levels=levels(data2[,variablen[1]]), ci=TRUE); ROC
## Setting direction: controls < cases
## 
## Call:
## roc.default(response = response, predictor = predictor, levels = levels(data2[,     variablen[1]]), ci = TRUE)
## 
## Data: predictor in 20 controls (response negativ) < 20 cases (response positiv).
## Area under the curve: 0.8488
## 95% CI: 0.7282-0.9693 (DeLong)
plot(ROC, main="ROC-Analyse"); grid()
plot.roc(smooth(ROC), add=TRUE, lty=2)