Chapter 2 Klassifikationsmodelle

Wir nutzen nun statistische Modelle, um die beiden Usertypen Customer und Subscriber zu klassifizieren. Dazu nutzen wir die logistische Regression und drei Modelle, die den Satz von Bayes nutzen.

2.1 Logistische Regression

Für die logistische Regression wird angenommen, dass \[ P(Y=1\mid \boldsymbol X) = \frac{\exp\{\boldsymbol X \boldsymbol \beta\}}{1 + \exp\{\boldsymbol X \boldsymbol \beta\}}. \] Durch diese Definition der Wahrscheinlichkeit \(P(Y=1\mid \boldsymbol X)\) wird sichergestellt, dass die geschätzten Wahrscheinlichkeiten zwischen \(0\) und \(1\) liegen. Um die unbekannten Parameter \(\boldsymbol \beta\) zu schätzen, wird die Maximum Likelihood Methode angewendet.

Die Resultate für den Citi Bike Datensatz sind wie folgt:

# fit the model and show results
glm.fit = glm(usertype ~ month + dist + age + tripMin + hour + wday + gender, data = bikedata, family = binomial)
summary(glm.fit)
## 
## Call:
## glm(formula = usertype ~ month + dist + age + tripMin + hour + 
##     wday + gender, family = binomial, data = bikedata)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -3.4915   0.1582   0.2318   0.3134   8.4904  
## 
## Coefficients:
##                   Estimate Std. Error  z value Pr(>|z|)    
## (Intercept)      3.6319549  0.0658250   55.176  < 2e-16 ***
## month2          -0.3367680  0.0669443   -5.031 4.89e-07 ***
## month3          -0.5195498  0.0622710   -8.343  < 2e-16 ***
## month4          -1.2189329  0.0566514  -21.516  < 2e-16 ***
## month5          -1.4323948  0.0549298  -26.077  < 2e-16 ***
## month6          -1.4199102  0.0546407  -25.986  < 2e-16 ***
## month7          -1.5723995  0.0544593  -28.873  < 2e-16 ***
## month8          -1.5146433  0.0545346  -27.774  < 2e-16 ***
## month9          -1.5455682  0.0545370  -28.340  < 2e-16 ***
## month10         -1.4869200  0.0550121  -27.029  < 2e-16 ***
## month11         -1.1001050  0.0580674  -18.945  < 2e-16 ***
## month12         -0.8998576  0.0606854  -14.828  < 2e-16 ***
## dist             0.1247305  0.0048170   25.894  < 2e-16 ***
## age              0.0373975  0.0007212   51.857  < 2e-16 ***
## tripMin         -0.0527037  0.0005480  -96.183  < 2e-16 ***
## hour            -0.0155030  0.0013780  -11.250  < 2e-16 ***
## wdayDienstag     0.2136243  0.0262687    8.132 4.21e-16 ***
## wdayMittwoch     0.1147861  0.0256983    4.467 7.94e-06 ***
## wdayDonnerstag   0.1068818  0.0257257    4.155 3.26e-05 ***
## wdayFreitag     -0.0885485  0.0250741   -3.531 0.000413 ***
## wdaySamstag     -0.8838660  0.0230953  -38.270  < 2e-16 ***
## wdaySonntag     -0.7160752  0.0239171  -29.940  < 2e-16 ***
## genderMänner     0.3946814  0.0154090   25.614  < 2e-16 ***
## genderUnbekannt -4.3661745  0.0209874 -208.038  < 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: 346480  on 499364  degrees of freedom
## Residual deviance: 187297  on 499341  degrees of freedom
## AIC: 187345
## 
## Number of Fisher Scoring iterations: 7
# prediction
glm.probs = predict(glm.fit, type = "response")
contrasts(bikedata$usertype)
##            Subscriber
## Customer            0
## Subscriber          1
glm.pred = rep("Customer",dim(bikedata)[1])
glm.pred[glm.probs>0.5] = "Subscriber"
# state the results
table(glm.pred,bikedata$usertype)
##             
## glm.pred     Customer Subscriber
##   Customer      34080       8534
##   Subscriber    20947     435804
mean(glm.pred == bikedata$usertype)
## [1] 0.940963

2.2 Modelle basierend auf dem Satz von Bayes

Die folgenden Modelle nutzen, dass \[ P(Y = 1 \mid \boldsymbol X) = \frac{\pi_1 f_1(\boldsymbol X)}{\pi_1 f_1(\boldsymbol X) + \pi_0 f_0(\boldsymbol X)} \] gilt, wobei \(\pi_k\) die prior Wahrscheinlichkeit ist, dass eine Beobachtung zur Klasse \(k \in \{0,1\}\) gehört. \(f_k(\boldsymbol X) = P(\boldsymbol X \mid Y = k)\) ist die Wahrscheinlichkeitsfunktion von \(\boldsymbol X\) für eine Beobachtung aus der Klasse \(k \in \{0,1\}\). Die Wahrscheinlichkeit muss modelliert werden. Darin unterscheiden sich die drei folgenden Modelle.

2.2.1 Lineare Diskriminanzanalyse

Für das erste Modell nehmen wir an, dass \(f_k(\boldsymbol X)\) einer multivariaten Normalverteilung \(\mathcal N (\boldsymbol \mu_k,\boldsymbol \Sigma)\) folgt, wobei \(\boldsymbol \mu_k\) der klassenspezifische Mittelwertsvektor und \(\boldsymbol \Sigma\) die Kovarianzmatrix beschreiben. Es wird angenommen, dass die Kovarianzmatrix für beide Klassen identisch ist.

Man kann zeigen, dass eine Beobachtung der Klasse zugewiesen wird, für die \[ \delta_k(\boldsymbol X) = \boldsymbol X^T \boldsymbol \Sigma^{-1} \, \boldsymbol \mu_k - \frac{1}{2}\boldsymbol \mu_k^T \, \boldsymbol \Sigma^{-1} \, \boldsymbol \mu_k + \log(\pi_k) \] am größten ist. Da \(\delta_k(\boldsymbol X)\) linear in \(\boldsymbol X\) ist, heißt die Methode lineare Diskriminanzanalyse. Um \(\delta_k(\boldsymbol X)\) zu bestimmen, werden \(\boldsymbol \Sigma\), \(\boldsymbol \mu_k\) und \(\pi_k\) aus den Daten geschätzt.

Die Resultate für den Citi Bike Datensatz sind wie folgt:

# fit the model and show results
lda.fit = lda(usertype ~ month + dist + age + tripMin + hour + wday + gender, data = bikedata)
lda.fit
## Call:
## lda(usertype ~ month + dist + age + tripMin + hour + wday + gender, 
##     data = bikedata)
## 
## Prior probabilities of groups:
##   Customer Subscriber 
##  0.1101939  0.8898061 
## 
## Group means:
##                month2     month3     month4    month5    month6    month7
## Customer   0.01717339 0.03003980 0.07983354 0.1232486 0.1343522 0.1473458
## Subscriber 0.05176240 0.05864004 0.07435106 0.1027259 0.1083590 0.1034550
##               month8    month9   month10    month11    month12     dist
## Customer   0.1405674 0.1325168 0.1023134 0.04879423 0.03200247 2.018440
## Subscriber 0.1087573 0.1029442 0.1088901 0.07405399 0.06162876 1.756924
##                 age  tripMin     hour wdayDienstag wdayMittwoch wdayDonnerstag
## Customer   45.33929 27.25513 14.42824   0.09793374    0.1082559      0.1087830
## Subscriber 41.50834 12.30056 13.83485   0.16165847    0.1626262      0.1617687
##            wdayFreitag wdaySamstag wdaySonntag genderMänner genderUnbekannt
## Customer     0.1300634   0.2406273   0.1993567    0.2438439      0.60980973
## Subscriber   0.1500007   0.1135757   0.1026448    0.7364596      0.01932088
## 
## Coefficients of linear discriminants:
##                          LD1
## month2          -0.039158582
## month3          -0.042915104
## month4          -0.210165898
## month5          -0.273438944
## month6          -0.274492950
## month7          -0.337849570
## month8          -0.314503134
## month9          -0.328917582
## month10         -0.290041626
## month11         -0.174799581
## month12         -0.127108509
## dist             0.046898236
## age              0.008527232
## tripMin         -0.019116695
## hour            -0.004768256
## wdayDienstag     0.053909746
## wdayMittwoch     0.032788449
## wdayDonnerstag   0.029144165
## wdayFreitag     -0.025291665
## wdaySamstag     -0.375218960
## wdaySonntag     -0.297795825
## genderMänner     0.118122522
## genderUnbekannt -4.469572138
# prediction
lda.probs = predict(lda.fit, bikedata)$posterior

lda.pred = rep("Customer",dim(bikedata)[1])
lda.pred[lda.probs[,2]>0.5] = "Subscriber"
# state the results
table(lda.pred,bikedata$usertype)
##             
## lda.pred     Customer Subscriber
##   Customer      33851       8876
##   Subscriber    21176     435462
mean(lda.pred == bikedata$usertype)
## [1] 0.9398196

2.2.2 Quadratisch Diskriminanzanalyse

Für das zweite Modell nehmen wir an, dass \(f_k(\boldsymbol X)\) einer multivariaten Normalverteilung \(\mathcal N (\boldsymbol \mu_k,\boldsymbol \Sigma_k)\) folgt. Hier wird angenommen, dass die Kovarianzmatrix für beide Klassen unterschiedlich sein kann.

Man kann zeigen, dass eine Beobachtung der Klasse zugewiesen wird, für die \[ \delta_k(\boldsymbol X) = -\frac{1}{2}\left(\boldsymbol X - \boldsymbol \mu_k \right)^T\,\boldsymbol \Sigma_k^{-1} \, \left(\boldsymbol X - \boldsymbol \mu_k \right) - \frac{1}{2}\log(\mid\boldsymbol \Sigma \mid) + \log(\pi_k) \] am größten ist. Da \(\delta_k(\boldsymbol X)\) quadratisch in \(\boldsymbol X\) ist, heißt die Methode quadratische Diskriminanzanalyse.

Die Resultate für den Citi Bike Datensatz sind wie folgt:

# fit the model and show results
qda.fit = qda(usertype ~ month + dist + age + tripMin + hour + wday + gender, data = bikedata)
qda.fit
## Call:
## qda(usertype ~ month + dist + age + tripMin + hour + wday + gender, 
##     data = bikedata)
## 
## Prior probabilities of groups:
##   Customer Subscriber 
##  0.1101939  0.8898061 
## 
## Group means:
##                month2     month3     month4    month5    month6    month7
## Customer   0.01717339 0.03003980 0.07983354 0.1232486 0.1343522 0.1473458
## Subscriber 0.05176240 0.05864004 0.07435106 0.1027259 0.1083590 0.1034550
##               month8    month9   month10    month11    month12     dist
## Customer   0.1405674 0.1325168 0.1023134 0.04879423 0.03200247 2.018440
## Subscriber 0.1087573 0.1029442 0.1088901 0.07405399 0.06162876 1.756924
##                 age  tripMin     hour wdayDienstag wdayMittwoch wdayDonnerstag
## Customer   45.33929 27.25513 14.42824   0.09793374    0.1082559      0.1087830
## Subscriber 41.50834 12.30056 13.83485   0.16165847    0.1626262      0.1617687
##            wdayFreitag wdaySamstag wdaySonntag genderMänner genderUnbekannt
## Customer     0.1300634   0.2406273   0.1993567    0.2438439      0.60980973
## Subscriber   0.1500007   0.1135757   0.1026448    0.7364596      0.01932088
# prediction
qda.probs = predict(qda.fit, bikedata)$posterior

qda.pred = rep("Customer",dim(bikedata)[1])
qda.pred[qda.probs[,2]>0.5] = "Subscriber"
# state the results
table(qda.pred,bikedata$usertype)
##             
## qda.pred     Customer Subscriber
##   Customer      37964      25749
##   Subscriber    17063     418589
mean(qda.pred == bikedata$usertype)
## [1] 0.9142671

2.2.3 Naiver Bayes Ansatz

Für den naiven Bayes Ansatz nehmen wir zusätzlich zur quadratischen Diskriminanzanalyse an, dass \(\boldsymbol \Sigma_k\) eine Diagonalmatrix ist. Damit nehmen wir an, dass die Variablen \(\boldsymbol X\) in einer Klasse \(k \in \{0,1\}\) unabhängig sind.

Die Resultate für den Citi Bike Datensatz sind wie folgt:

# fit the model and show results
bayes.fit = naiveBayes(usertype ~ month + dist + age + tripMin + hour + wday + gender, data = bikedata)
bayes.fit
## 
## Naive Bayes Classifier for Discrete Predictors
## 
## Call:
## naiveBayes.default(x = X, y = Y, laplace = laplace)
## 
## A-priori probabilities:
## Y
##   Customer Subscriber 
##  0.1101939  0.8898061 
## 
## Conditional probabilities:
##             month
## Y                     1          2          3          4          5          6
##   Customer   0.01181238 0.01717339 0.03003980 0.07983354 0.12324859 0.13435223
##   Subscriber 0.04443239 0.05176240 0.05864004 0.07435106 0.10272585 0.10835895
##             month
## Y                     7          8          9         10         11         12
##   Customer   0.14734585 0.14056736 0.13251676 0.10231341 0.04879423 0.03200247
##   Subscriber 0.10345503 0.10875730 0.10294416 0.10889008 0.07405399 0.06162876
## 
##             dist
## Y                [,1]     [,2]
##   Customer   2.018440 1.477972
##   Subscriber 1.756924 1.411537
## 
##             age
## Y                [,1]     [,2]
##   Customer   45.33929 10.38480
##   Subscriber 41.50834 11.80702
## 
##             tripMin
## Y                [,1]     [,2]
##   Customer   27.25513 32.80761
##   Subscriber 12.30056 12.38863
## 
##             hour
## Y                [,1]     [,2]
##   Customer   14.42824 4.142023
##   Subscriber 13.83485 4.928154
## 
##             wday
## Y                Montag   Dienstag   Mittwoch Donnerstag    Freitag    Samstag
##   Customer   0.11497992 0.09793374 0.10825595 0.10878296 0.13006342 0.24062733
##   Subscriber 0.14772538 0.16165847 0.16262620 0.16176874 0.15000068 0.11357570
##             wday
## Y               Sonntag
##   Customer   0.19935668
##   Subscriber 0.10264483
## 
##             gender
## Y                Frauen     Männer  Unbekannt
##   Customer   0.14634634 0.24384393 0.60980973
##   Subscriber 0.24421949 0.73645963 0.01932088
# prediction
bayes.pred = predict(bayes.fit, bikedata)
# state the results
table(bayes.pred,bikedata$usertype)
##             
## bayes.pred   Customer Subscriber
##   Customer      33538      10373
##   Subscriber    21489     433965
mean(bayes.pred == bikedata$usertype)
## [1] 0.936195

2.3 Prediction mit Training- und Testdaten

Bisher haben wir den ganzen Datensatz genutzt, um die Modelle zu schätzen. Anschließend haben wir die Güte der Modelle danach bewertet, wie gut sie die Beobachtungen, die zur Schätzung genutzt wurden, klassifizieren. Da wir aber daran interessiert sind, Beobachtungen zu klassifizieren, die wir nicht zur Schätzung genutzt haben, teilen wir den Datensatz im Folgenden in Trainings- und Testdaten auf. Die Modelle werden nur mit dem Trainingsdatensatz geschätzt. Anschließend klassifizieren wir die Testdaten mithilfe der geschätzten Modelle. Um zufällige Effekte durch die Teilung des Datensatzes auszuschließen, wiederholen wir die Schätzung mit 50 unterschiedlichen Datensätzen.

# estimation

test_size = 0.1     # percentage of data for test sample
N = 50              # number of considered training sets
log_reg = rep(0,N)  # vector to store results of logistic regression
lda     = rep(0,N)  # vector to store results of LDA
qda     = rep(0,N)  # vector to store results of QDA
bayes   = rep(0,N)  # vector to store results of Naive Bayes
# We split the data set into training and test sample

for (i in 1:N){

      # split the model into train and test sample
      sample = sample.split(bikedata$usertype, SplitRatio = 1- test_size)
      train_sam = subset(bikedata, sample == TRUE)
      test_sam  = subset(bikedata, sample == FALSE)

      # fit the model
      ## logistic
      glm.fit = glm(usertype ~ month + dist + age + tripMin + hour + wday + gender, data = train_sam, family = binomial)
      glm.probs = predict(glm.fit, test_sam ,type = "response")

      glm.pred = rep("Customer",dim(test_sam)[1])
      glm.pred[glm.probs>0.5] = "Subscriber"

      ## linear discriminant analysis
      lda.fit = lda(usertype ~ month + dist + age + tripMin + hour + wday + gender, data = train_sam)
      lda.probs = predict(lda.fit, test_sam)$posterior

      lda.pred = rep("Customer",dim(test_sam)[1])
      lda.pred[lda.probs[,2]>0.5] = "Subscriber"

      ## quadratic discriminant analysis
      qda.fit = qda(usertype ~ month + dist + age + tripMin + hour + wday + gender, data = train_sam)
      qda.probs = predict(qda.fit, test_sam)$posterior

      qda.pred = rep("Customer",dim(test_sam)[1])
      qda.pred[qda.probs[,2]>0.5] = "Subscriber"

      ## naive Bayes
      bayes.fit = naiveBayes(usertype ~ month + dist + age + tripMin + hour + wday + gender, data = train_sam)
      bayes.fit

      # prediction
      bayes.pred = predict(bayes.fit, test_sam)

      # save the results
      log_reg[i] = mean(glm.pred == test_sam$usertype)
      lda[i]     = mean(lda.pred == test_sam$usertype)
      qda[i]     = mean(qda.pred == test_sam$usertype)
      bayes[i]   = mean(bayes.pred == test_sam$usertype)

}