Zunächst installieren wir Pakete, die wir benötigen, um die folgenden Analysen durchzuführen.
if (!require('rstudioapi')) install.packages('rstudioapi')
if (!require('Hmisc')) install.packages('Hmisc')
if (!require('MASS')) install.packages('MASS')
if (!require('caret')) install.packages('caret')
if (!require('dplyr')) install.packages('dplyr')
if (!require('CCA')) install.packages('CCA')
if (!require('mlogit')) install.packages('mlogit')
if (!require('lmtest')) install.packages('lmtest')
Jetzt laden wir die installierten Pakete. Das Paket “rstudiopai”
enthält die Funktion getActiveDocumentContext()
, die es uns
später erleichtert, das Working Directory zu setzen. Das Paket “Hmisc”
enthält die Funktion rcorr()
, die wir nutzen um einfach
Korrelationsmatrizen erstellen zu können. Das Paket “MASS” benötigen
wir, da es eine Funktion namens lda()
enthält, mit der wir
Diskriminanzanalysen berechnen können. Das Paket “caret” enthält die
Funktion confusionMatrix()
, mit der wir einfach
Konfusionsmatrizen mit begleitenden Informationen (z.B.
Vorhersageakkuratheit) anfordern können. Aus dem Paket “dplyr” benötigen
wir wieder die Funktion recode()
, um einfach Variablen
umkodieren zu können. Das Paket “CCA” benötigen wir wegen seiner
Funktion cc()
, mit der wir kanonische Korrelationsanalysen
berechnen können. Das Paket “mlogit” enthält eine gleichnamige Funktion,
die es uns erlaubt, multinomiale logistische Regressionen zu berechen.
Das Paket “lmtest” benötigen wir schließlich, da es eine Funktion namens
lrtest()
enthält, mit der wir Likelihood-Ratio-Tests
anfordern können, um Modelle zu vergleichen.
library(rstudioapi)
library(Hmisc)
library(MASS)
library(caret)
library(dplyr)
library(CCA)
library(mlogit)
library(lmtest)
Nun schalten wir die wissenschaftliche Notation ab, um möglichst viele Nachkommastellen im Output zu erhalten (das kann vor allem für p-Werte wichtig sein, die sonst schwer zu interpretieren sind).
options(scipen=999)
Hier setzen wir das Working Directory auf den Pfad, in dem sich auch dieses Notebook befindet. Dadurch findet R alle nötigen Dateien, so lange sich diese im selben Ordner wie dieses Notebook auf Ihrem Rechner befinden.
setwd(dirname(getActiveDocumentContext()$path))
Wir wollen uns nun anschauen, wie wir eine Diskriminanzanalyse berechnen können. Dazu laden wir den Datensatz “diskrim.RData” ein (erste Zeile) und lassen ihn uns ausgeben (zweite Zeile), um ihn zu inspizieren.
load('diskrim.RData')
diskrim
Wir nutzen die Funkion lda()
aus dem Paket “MASS”, um
eine Diskriminanzanalyse zu berechnen. Diese Funktion benötigt
mindestens zwei Argumente:
Wir packen die Ergebnisse wieder in ein Objekt, dass wir hier
“LDA_Ergebnisse” nennen. In der zweiten Zeile lassen wir uns diese
Ergebnise ausgeben. Wie Sie sehen, brauchen wir in diesem Fall dafür
nicht die Funktion summary()
, sondern wir geben einfach den
Namen des Objekts, das die Ergebnisse enthält, ein.
LDA_Ergebnisse <- lda(formula = sztype ~ sozatt + emo + panssneg + sansneg, data = diskrim)
LDA_Ergebnisse
## Call:
## lda(sztype ~ sozatt + emo + panssneg + sansneg, data = diskrim)
##
## Prior probabilities of groups:
## HN NSK HSK
## 0.3409091 0.2954545 0.3636364
##
## Group means:
## sozatt emo panssneg sansneg
## HN 0.02688377 0.09461278 0.5317344 0.6491836
## NSK -0.67979707 -0.60525263 -0.2709220 -0.2127489
## HSK 0.52713159 0.40306827 -0.2783769 -0.4357512
##
## Coefficients of linear discriminants:
## LD1 LD2
## sozatt 0.58815237 -0.58217800
## emo 0.59076594 0.02124984
## panssneg 0.01691179 -0.46933275
## sansneg -0.60569765 -0.74121389
##
## Proportion of trace:
## LD1 LD2
## 0.5413 0.4587
Wie wir sehen, hat unsere Ausgabe wieder mehrere Unterpunkte:
Sie fragen sich nun wahrscheinlich, was wir mit diesem Output anfangen sollen. Denn wir wissen nicht,
Wir wollen uns nun zunächst der ersten Fragestellung widmen. Dazu
plotten wir einmal die Lage unserer Patienten im zweidimensionalen Raum,
wobei wir die 1. kanonische Diskriminanzfunktion auf die x-Achse legen
und die 2. kanonische Diskriminanzfunktion auf die y-Achse legen. Dies
geht sehr einfach, indem wir das Objekt mit den Ergebnissen der
Diskriminanzanalyse einfach der Funktion plot()
übergeben.
plot(LDA_Ergebnisse)
Wir können sehen, dass sich NSK-Patienten eher im niedrigen Bereich der ersten kanonischen Diskriminanzfunktion befinden und HSK-Patienten eher im hohen Bereich. Insgesamt gibt es jedoch sehr starke Überlappungen zwischen unseren drei Gruppen (es würde uns also sehr schwer fallen, Grenzen zwischen den einzelnen Gruppen einzuzeichnen).
Wie viele Patienten würden also auf Basis unserer
Diskriminanzfunktionen korrekt und wie viele falsch klassifiziert
werden? Wir können uns die vorhergesagten Klassifikationen ausgeben
lassen, indem wir erneut die Funktion lda()
aufrufen. Wir
übergeben ihr aber zusätzlich das Argument “CV = TRUE”. CV steht für
cross-validation. Genau genommen führt R hier im Hintergrund eine
sogenannte leave-one-out cross-validation durch. Bei diesem Verfahren
wird die Diskriminanzanalyse nicht nur einmal, sondern N-mal im
Hintergrund ausgeführt (N entspricht der Anzahl unserer
Versuchspersonen). Bei jedem Durchlauf wird die Diskriminanzanalyse
dabei jedoch mit einer ausgeschlossenen Versuchsperson durchgeführt und
dann die Klasssenzugehörigkeit der ausgeschlossenen Versuchsperson
vorhergesagt.
Wir packen die Ergebnisse dieser cross-validation in ein Objekt namens “Vorhersagen” und lassen es uns ausgeben.
Vorhersagen <- lda(formula = sztype ~ sozatt + emo + panssneg + sansneg, data = diskrim, CV = TRUE)
Vorhersagen
## $class
## [1] HN HN HN NSK NSK HN HN NSK HN HSK NSK HN HSK HN HN HSK HN NSK HSK
## [20] HSK NSK HSK HSK NSK HN NSK NSK HN HSK HSK HN HSK HSK NSK NSK HSK HSK HN
## [39] HSK HSK HN HSK HN HSK
## Levels: HN NSK HSK
##
## $posterior
## HN NSK HSK
## 1 0.90009268 0.03139612 0.06851120
## 2 0.81093263 0.02156649 0.16750088
## 3 0.50760267 0.13683299 0.35556434
## 4 0.18960104 0.46663525 0.34376371
## 5 0.10636580 0.79941907 0.09421513
## 6 0.53609206 0.27917644 0.18473149
## 7 0.51705191 0.10061833 0.38232976
## 8 0.41005893 0.49338089 0.09656018
## 9 0.64988644 0.14654817 0.20356539
## 10 0.15124743 0.06531112 0.78344145
## 11 0.31487506 0.49561703 0.18950791
## 12 0.50724938 0.08383290 0.40891772
## 13 0.34964319 0.20569531 0.44466150
## 14 0.47479897 0.41371922 0.11148182
## 15 0.82167608 0.07708761 0.10123632
## 16 0.06191909 0.19937150 0.73870941
## 17 0.69661271 0.13874900 0.16463829
## 18 0.18414472 0.71706090 0.09879438
## 19 0.03321443 0.33643037 0.63035521
## 20 0.18832683 0.33672348 0.47494970
## 21 0.10842129 0.87249666 0.01908205
## 22 0.30716083 0.08892267 0.60391650
## 23 0.13118217 0.05690819 0.81190964
## 24 0.33153049 0.60186077 0.06660874
## 25 0.56522730 0.27685883 0.15791387
## 26 0.10973675 0.88358110 0.00668215
## 27 0.09633029 0.80017754 0.10349217
## 28 0.50710479 0.14649640 0.34639881
## 29 0.14491349 0.27169672 0.58338979
## 30 0.02063422 0.18414547 0.79522031
## 31 0.61407239 0.06511719 0.32081042
## 32 0.09164140 0.21855779 0.68980081
## 33 0.22051773 0.22450790 0.55497437
## 34 0.03615684 0.65841484 0.30542832
## 35 0.30049749 0.51149222 0.18801029
## 36 0.28483304 0.08389128 0.63127568
## 37 0.03627933 0.04464418 0.91907649
## 38 0.46300002 0.31660504 0.22039494
## 39 0.13561869 0.14992414 0.71445717
## 40 0.23281662 0.25111030 0.51607308
## 41 0.91074779 0.07247510 0.01677711
## 42 0.02899667 0.06264161 0.90836172
## 43 0.72465656 0.06611818 0.20922526
## 44 0.46261172 0.01150085 0.52588743
##
## $terms
## sztype ~ sozatt + emo + panssneg + sansneg
## attr(,"variables")
## list(sztype, sozatt, emo, panssneg, sansneg)
## attr(,"factors")
## sozatt emo panssneg sansneg
## sztype 0 0 0 0
## sozatt 1 0 0 0
## emo 0 1 0 0
## panssneg 0 0 1 0
## sansneg 0 0 0 1
## attr(,"term.labels")
## [1] "sozatt" "emo" "panssneg" "sansneg"
## attr(,"order")
## [1] 1 1 1 1
## attr(,"intercept")
## [1] 1
## attr(,"response")
## [1] 1
## attr(,".Environment")
## <environment: R_GlobalEnv>
## attr(,"predvars")
## list(sztype, sozatt, emo, panssneg, sansneg)
## attr(,"dataClasses")
## sztype sozatt emo panssneg sansneg
## "factor" "numeric" "numeric" "numeric" "numeric"
##
## $call
## lda(formula = sztype ~ sozatt + emo + panssneg + sansneg, data = diskrim,
## CV = TRUE)
##
## $xlevels
## named list()
Uns interessieren hierbei nur die ersten beiden Bereiche der Ausgabe:
Die vorhergesagten Klassen, die wir somit erhalten haben, können wir
mittels einer Kreuztabelle mit den tatsächlichen Klassen der
Versuchspersonen abgleichen: Dies könnten wir einfach mit der Funktion
table()
machen, der wir die tatsächlichen und die
vorhergesagten Klassen als Argumente übergeben (wie wir es im Kapitel zu
binär-logistischer Regression getan haben). Aus Komfort-Gründen, wollen
wir hier nun allerdings die Funktion confusionMatrix()
aus
dem Paket “caret” verwenden, da sie uns direkt die Akkuratheit der
Klassifikation mit ausrechnet und einen Signifikanztest, ob die
Hinzunahme unserer vier Variablen die Vorhersagegüte verbessert.
confusionMatrix(data = Vorhersagen$class, reference = diskrim$sztype)
## Confusion Matrix and Statistics
##
## Reference
## Prediction HN NSK HSK
## HN 9 3 4
## NSK 4 5 2
## HSK 2 5 10
##
## Overall Statistics
##
## Accuracy : 0.5455
## 95% CI : (0.3885, 0.6961)
## No Information Rate : 0.3636
## P-Value [Acc > NIR] : 0.01049
##
## Kappa : 0.313
##
## Mcnemar's Test P-Value : 0.55288
##
## Statistics by Class:
##
## Class: HN Class: NSK Class: HSK
## Sensitivity 0.6000 0.3846 0.6250
## Specificity 0.7586 0.8065 0.7500
## Pos Pred Value 0.5625 0.4545 0.5882
## Neg Pred Value 0.7857 0.7576 0.7778
## Prevalence 0.3409 0.2955 0.3636
## Detection Rate 0.2045 0.1136 0.2273
## Detection Prevalence 0.3636 0.2500 0.3864
## Balanced Accuracy 0.6793 0.5955 0.6875
Wie wir sehen können, werden 24 Versuchspersonen richtig klassifiziert und 20 falsch. Dies entspricht einer Akkuratheit von ca. 54.5% (was eher moderat ist). Das 95% Konfidenzinterval der Akkuratheit liegt zwischen 0.3885 und 0.6961. Die No Information Rate beträgt 0.3636. Dieser Wert entspricht dem Anteil der Personen mit der häufigsten Klasse (HSK, wie wir oben gesehen haben). Da das Konfidenzintervall den Wert der No Information Rate nicht beinhaltet, verbessert sich die Klassifikation also signifikant durch die Hinzunahme unserer vier unabhängigen Variablen. Dies zeigt auch der Wert, der sich bei P-Value [Acc > NIR] findet, an.
Sie fragen sich an dieser Stelle eventuell, warum uns die Funktion
lda()
so einen “unbrauchbaren” Output liefert, wenn wir das
Argument “CV = TRUE” weglassen und warum wir so einen Aufwand haben, bis
wir endlich einen p-Wert erhalten. Dies liegt an der Forschungs- und
Anwendungspraxis im Bereich von Klassifizierungsfragestellungen: In den
meisten Forschungs- und Anwendungsfragen wollen wir nicht wissen, ob ein
Klassifikationsmodell überhaupt signifikanten Mehrwert gegenüber einer
Klassifikation auf Basis der häufigsten Klasse hat, sondern wir wollen
ein möglichst gutes Vorhersagemodell aufstellen (in vielen
Anwendungsfragen geht es darum, die Klassifikationsakkuratheit im
Bereich von über 90% noch um ein bis zwei Prozentpunkte zu erhöhen).
Deswegen interessiert der “schnöde” p-Wert in derartigen Fragestellungen
oft nicht.
Der Grund, warum uns lda()
standardmäßig keine
vorhergesagten Werte für unsere Versuchspersonen liefert, liegt auch in
der typischen Forschungs- und Anwendungspraxis: Um die Güte eines
Klassifikationsmodells zu bestimmen, braucht man zwei Datensets:
Warum kann man nicht einfach die gleichen Daten als Trainingsset und
als Testset verwenden? Hierbei kommt es zum Problem des “Overfitting”.
Overfitting beschreibt das Problem, dass ein Modell sich zu genau an die
Trainingsdaten anpasst (z.B. auch an Outlier innerhalb des
Trainingssets) und sich dann sehr schlecht eignet, um neue Daten, bei
denen wir die Klassenzugehörigkeiten nicht kennen, zu klassifizieren
(was meist allerdings das Ziel von Klassifikationsverfahren ist).1 Deswegen
gibt uns lda()
auch standardmäßig keine vorhergesagten
Klassenzugehörigkeiten für unsere Versuchspersonen aus, das es davon
ausgeht, dass wir noch ein separates Testset haben, für das uns dann die
vorhergesagten Klassenzugehörigkeiten interessieren.
Die leave-one-out cross-validation, die wir oben verwendet haben, ist streng genommen eine “Notlösung”: Weil uns nur ein kleines Datenset (N = 44) zur Verfügung steht, wollen wir es nicht noch kleiner machen, indem wir Versuchspersonen ausschließen, um sie anschließend als Testdaten zu verwenden. Daher teilt die leave-one-out cross-validation die Daten künstlich in Trainings- und Testdaten. Wie bereits beschrieben, wird bei diesem Verfahren die Diskriminanzanalyse N-mal durchgeführt. Bei jedem Durchlauf wird eine Versuchsperson aus der Berechnung ausgeschlossen. Die Diskriminanzanalyse wird also mit N-1 Versuchspersonen gefittet (Trainingsset). Anschließend wird die Klasse für die ausgeschlossene Versuchsperson vorhergesagt (Testset).2 Mehr Informationen zum Thema Kreuzvalidierung können Sie dem entsprechenden Abschnitt im Buchkapitel entnehmen.
Wir wollen nun einmal den Zusammenhang zwischen der
Diskriminanzanalyse und der kanonischen Korrelationsanalyse
verdeutlichen. Dazu kodieren wir die Gruppenvariable zunächst in zwei
Kontrastvariablen. Zu diesem Zweck nutzen wir wieder die Funktion
recode()
aus dem Paket “dplyr”.
diskrim <- diskrim %>%
mutate(k1 = recode(sztype, 'HN' = 0, 'HSK' = -1, 'NSK' = 1),
k2 = recode(sztype, 'HN' = 1, 'HSK' = -0.5, 'NSK' = -0.5))
Um uns die Eingaben gleich etwas zu erleichtern, schauen wir mit der
Funktion colnames()
, welche Spaltennummern unsere
unabhängigen Variablen und unsere Kontrastvariablen haben.
colnames(diskrim)
## [1] "sztype" "sozatt" "emo" "panssneg" "sansneg" "k1" "k2"
Anhand der Spaltennummern packen wir die Kontrastvariablen nun in ein Objekt namens “set1” und die unabhängigen Variablen in ein Objekt namens “set2”.
set1 <- diskrim[,6:7]
set2 <- diskrim[,2:5]
Mit der Funktion cc()
aus dem Paket “CCA” berechnen wir
nun eine kanonische Korrelationsanalyse zwischen unseren beiden
Variablensets (erste Zeile) und lassen uns die Gewichte der unabhängigen
Variablen auf die beiden kanonischen Variaten ausgeben (zweite
Zeile).
kk_ergebnisse <- cc(set1, set2)
kk_ergebnisse$ycoef
## [,1] [,2]
## sozatt -0.50595950 -0.51246777
## emo -0.50820783 0.01870538
## panssneg -0.01454841 -0.41313465
## sansneg 0.52105287 -0.65246063
Die Gewichte der unabhängigen Variablen für die kanonischen Variaten sind zwar nicht identisch zu den Koeffizenten der Diskriminanzfunktion, aber sie entsprechen Ihnen konzeptuell. Wir können das auch ganz einfach zeigen: Wenn wir die Gewichte der unabhängigen Variablen für die kanonischen Variaten aus der kanonischen Korrelationsanalyse durch die Koeffizienten der Diskriminanzfunktion aus der Diskriminanzanalyse teilen, sehen wir, dass diese durch einen Skalierungsfaktor ineinander überführt werden können (-0.86 für die erste kanonische Variate und 0.88 für die zweite).
kk_ergebnisse$ycoef / LDA_Ergebnisse$scaling
## [,1] [,2]
## sozatt -0.8602524 0.8802596
## emo -0.8602524 0.8802596
## panssneg -0.8602524 0.8802596
## sansneg -0.8602524 0.8802596
Die Unterschiede in der Skalierung kommen zu Stande, da bei der kanonischen Korrelationsanalyse die Normierungs-Nebenbedingung gilt, dass die Varianzen der kanonischen Variaten den Wert eins annehmen (vielleicht errinern Sie sich). Bei der Diskriminanzanalyse gilt jedoch eine andere Nebenbedingung (die wir gleich lernen werden).
Um die Unterschiede in der Skalierung zwischen den Diskriminanzfunktionen und den kanonischen Variaten klar zu machen, bilden wir diese nun einmal von Hand. Zunächst bilden wir die Diskriminanzfunktionen D1 und D2 für jeden Probanden von Hand. Dabei nutzen wir aus, dass die Gewichte der Funktionen bereits im Unterobjekt “scaling” des Objekts “LDA_Ergebnisse” gespeichert sind.
diskrim$D1 <- LDA_Ergebnisse$scaling[1,1] * diskrim$sozatt + LDA_Ergebnisse$scaling[2,1] * diskrim$emo + LDA_Ergebnisse$scaling[3,1] * diskrim$panssneg + LDA_Ergebnisse$scaling[4,1] * diskrim$sansneg
diskrim$D2 <- LDA_Ergebnisse$scaling[1,2] * diskrim$sozatt + LDA_Ergebnisse$scaling[2,2] * diskrim$emo + LDA_Ergebnisse$scaling[3,2] * diskrim$panssneg + LDA_Ergebnisse$scaling[4,2] * diskrim$sansneg
Nun bilden wir die kanonischen Variaten U1 und U2 für jede Versuchsperson. Hierbei nutzen wir aus, dass die Gewichte der kanonischen Variaten im Unterobjekt “ycoef” des Objekts “kk_ergebnisse” gespeichert sind.
diskrim$U1 <- kk_ergebnisse$ycoef[1,1] * diskrim$sozatt + kk_ergebnisse$ycoef[2,1] * diskrim$emo + kk_ergebnisse$ycoef[3,1] * diskrim$panssneg + kk_ergebnisse$ycoef[4,1] * diskrim$sansneg
diskrim$U2 <- kk_ergebnisse$ycoef[1,2] * diskrim$sozatt + kk_ergebnisse$ycoef[2,2] * diskrim$emo + kk_ergebnisse$ycoef[3,2] * diskrim$panssneg + kk_ergebnisse$ycoef[4,2] * diskrim$sansneg
Um uns die Anforderung der Korrelationsmatrix zu erleichtern,
überprüfen wir wieder mit colnames()
, welche Spaltennummern
die neu gebildeten Variablen haben: Es sind die Spalten 8 bis 11.
colnames(diskrim)
## [1] "sztype" "sozatt" "emo" "panssneg" "sansneg" "k1"
## [7] "k2" "D1" "D2" "U1" "U2"
Jetzt fordern wir mit der Funktion rcor()
eine
Korrelationsmatrix zwischen den Variablen D1, D2, U1 und U2 an. Wie wir
bereits aus vorherigen Kapiteln wissen, erwartet die Funktion
rcorr()
eine Matrix, so dass wir die entsprechenden Spalten
des Data-Frames “diskrim” zunächst mit der Funktion
as.matrix()
in eine Matrix transformieren müssen.
rcorr(as.matrix(diskrim[8:11]))
## D1 D2 U1 U2
## D1 1 0 -1 0
## D2 0 1 0 1
## U1 -1 0 1 0
## U2 0 1 0 1
##
## n= 44
##
##
## P
## D1 D2 U1 U2
## D1 1 0 1
## D2 1 1 0
## U1 0 1 1
## U2 1 0 1
Wir sehen anhand der Korrelationsmatrix zunächst, dass die Variablen D1 und D2 auf der einen Seite sowie die Variablen U1 und U2 auf der anderen Seite perfekt zu Null korrellieren. Dies ist nicht verwunderlich, da die Variablen per Definition so gebildet werden, dass sie jeweils zu 0 korrelieren. Interessanter ist stattdessen, dass die Variablen D1 und U1 perfekt zu -1 korrelieren und die Variablen D2 und U2 perfekt zu 1. Dies zeigt erneut, dass die D-Variablen anhand eines konstanten Skalierungsfaktors in die U-Variablen überführt werden können.
Nach welchen Regeln werden nun die Gewichte skaliert? Für die
kanonische Korrelationsanalyse kennen wir die Regel bereits: Die
Gewichte werden so skaliert, dass die kanonischen Variaten die
Standardabweichung 1 haben. Wir können das einmal überprüfen. Dazu
nutzen wir wieder die uns bereits bekannte Funktion
sapply()
, um die Standardabweichung für alle vier
interessierenden Variablen gleichzeitig anfordern zu können.
sapply(X = diskrim[8:11], FUN = sd)
## D1 D2 U1 U2
## 1.162449 1.136029 1.000000 1.000000
Wie wir sehen, ist die Standardabweichung für unsere beiden kanonischen Variaten U1 und U2 tatsächlich exakt 1. Dies trifft allerdings nicht für die Variablen D1 und D2 zu. Nach welchen Regeln wurden die Gewichte also hier skaliert? Sie wurden so skaliert, dass die Kovarianzmatrix innerhalb der Gruppen isotrop ist (das bedeutet, dass sie der Sphärizitätsanforderung genügt). Genauer müssen Sie die Skalierung an dieser Stelle nicht verstehen. Es reicht hier zu wissen, dass die Skalierungsbedingungen für die kanonische Korrelationsanalyse und die Diskriminanzanalyse unterschiedlich sind.
Wir wollen nun eine multinomiale logistische Regression rechnen, bei
der die Klassenzugehörigkeit der Patienten durch unsere vier
unabhängigen Variablen vorhergesagt werden soll. Wir wollen dazu die
Funktion mlogit()
aus dem gleichnamigen Paket nutzen.
Leider verlangt diese Funktion es, dass wir unsere Daten vorher in einen
sogenannten dfidx Data-Frame überführen.3 Was das besondere an
so einem dfidx Data-Frame ist, werden wir gleich sehen. Um unsere Daten
in einen dfidx Data-Frame zu überführen, benötigen wir die Funktion
dfidx()
, der wir drei Argumente übergeben.
Hier transformieren wir unsere Daten in einen dfidx Data-Frame namens diskrim_dfidx (erste Zeile). Und lassen ihn uns ausgeben (zweite Zeile).
diskrim_dfidx <- dfidx(data = diskrim[,1:5], choice = 'sztype', shape = 'wide')
diskrim_dfidx
## sztype sozatt emo panssneg sansneg idx
## 1 TRUE 0.33589584 0.62118399 1.70286182 1.87288567 1:HN
## 2 FALSE 0.33589584 0.62118399 1.70286182 1.87288567 1:HSK
## 3 FALSE 0.33589584 0.62118399 1.70286182 1.87288567 1:NSK
## 4 TRUE 1.18038405 0.96507382 0.91772500 1.71493862 2:HN
## 5 FALSE 1.18038405 0.96507382 0.91772500 1.71493862 2:HSK
## 6 FALSE 1.18038405 0.96507382 0.91772500 1.71493862 2:NSK
## 7 TRUE 0.31489911 0.27925344 0.80896367 0.27802074 3:HN
## 8 FALSE 0.31489911 0.27925344 0.80896367 0.27802074 3:HSK
## 9 FALSE 0.31489911 0.27925344 0.80896367 0.27802074 3:NSK
## 10 TRUE -0.55639095 -0.36446116 0.30415511 -0.54085464 4:HN
## 11 FALSE -0.55639095 -0.36446116 0.30415511 -0.54085464 4:HSK
## 12 FALSE -0.55639095 -0.36446116 0.30415511 -0.54085464 4:NSK
## 13 TRUE -1.74009920 -0.46350623 0.49179046 -0.04328081 5:HN
## 14 FALSE -1.74009920 -0.46350623 0.49179046 -0.04328081 5:HSK
## 15 FALSE -1.74009920 -0.46350623 0.49179046 -0.04328081 5:NSK
## 16 TRUE -0.31478264 0.26314124 -0.13147022 1.06545781 6:HN
## 17 FALSE -0.31478264 0.26314124 -0.13147022 1.06545781 6:HSK
## 18 FALSE -0.31478264 0.26314124 -0.13147022 1.06545781 6:NSK
## 19 TRUE -0.41634888 1.59146347 1.77479950 0.91749398 7:HN
## 20 FALSE -0.41634888 1.59146347 1.77479950 0.91749398 7:HSK
## 21 FALSE -0.41634888 1.59146347 1.77479950 0.91749398 7:NSK
## 22 TRUE -1.13895300 -0.33235904 0.37599129 0.82661130 8:HN
## 23 FALSE -1.13895300 -0.33235904 0.37599129 0.82661130 8:HSK
## 24 FALSE -1.13895300 -0.33235904 0.37599129 0.82661130 8:NSK
## 25 TRUE -0.03334942 0.43539159 0.67255104 0.95089954 9:HN
## 26 FALSE -0.03334942 0.43539159 0.67255104 0.95089954 9:HSK
## 27 FALSE -0.03334942 0.43539159 0.67255104 0.95089954 9:NSK
## 28 TRUE 1.79657105 0.09481423 -0.97031666 -0.04569045 10:HN
## 29 FALSE 1.79657105 0.09481423 -0.97031666 -0.04569045 10:HSK
## 30 FALSE 1.79657105 0.09481423 -0.97031666 -0.04569045 10:NSK
## 31 TRUE -0.73433521 0.07936348 -0.45775285 0.68313857 11:HN
## 32 FALSE -0.73433521 0.07936348 -0.45775285 0.68313857 11:HSK
## 33 FALSE -0.73433521 0.07936348 -0.45775285 0.68313857 11:NSK
## 34 TRUE 0.73509077 0.38364258 0.94069743 0.27532993 12:HN
## 35 FALSE 0.73509077 0.38364258 0.94069743 0.27532993 12:HSK
## 36 FALSE 0.73509077 0.38364258 0.94069743 0.27532993 12:NSK
## 37 TRUE 1.15224948 -0.93265613 -0.39398160 0.02153359 13:HN
## 38 FALSE 1.15224948 -0.93265613 -0.39398160 0.02153359 13:HSK
## 39 FALSE 1.15224948 -0.93265613 -0.39398160 0.02153359 13:NSK
## 40 TRUE -0.24798663 -1.01666807 -0.12748247 0.75131556 14:HN
## 41 FALSE -0.24798663 -1.01666807 -0.12748247 0.75131556 14:HSK
## 42 FALSE -0.24798663 -1.01666807 -0.12748247 0.75131556 14:NSK
## 43 TRUE 0.07041208 -0.18448548 2.06748471 1.00995457 15:HN
## 44 FALSE 0.07041208 -0.18448548 2.06748471 1.00995457 15:HSK
## 45 FALSE 0.07041208 -0.18448548 2.06748471 1.00995457 15:NSK
## 46 FALSE -0.24903753 -0.76156346 0.21400671 -2.00800314 16:HN
## 47 FALSE -0.24903753 -0.76156346 0.21400671 -2.00800314 16:HSK
## 48 TRUE -0.24903753 -0.76156346 0.21400671 -2.00800314 16:NSK
## 49 FALSE -0.67781574 0.89693507 -0.89235276 1.58992791 17:HN
## 50 FALSE -0.67781574 0.89693507 -0.89235276 1.58992791 17:HSK
## 51 TRUE -0.67781574 0.89693507 -0.89235276 1.58992791 17:NSK
## 52 FALSE -0.87742042 -1.66032594 -0.53381993 -0.28068378 18:HN
## 53 FALSE -0.87742042 -1.66032594 -0.53381993 -0.28068378 18:HSK
## 54 TRUE -0.87742042 -1.66032594 -0.53381993 -0.28068378 18:NSK
## 55 FALSE -0.94314046 0.67210138 -2.07314783 -0.83897257 19:HN
## 56 FALSE -0.94314046 0.67210138 -2.07314783 -0.83897257 19:HSK
## 57 TRUE -0.94314046 0.67210138 -2.07314783 -0.83897257 19:NSK
## 58 FALSE 0.01686436 -0.50777012 -0.25562538 -0.83461848 20:HN
## 59 FALSE 0.01686436 -0.50777012 -0.25562538 -0.83461848 20:HSK
## 60 TRUE 0.01686436 -0.50777012 -0.25562538 -0.83461848 20:NSK
## 61 FALSE -1.83077016 -2.79174465 0.10739932 -0.52478259 21:HN
## 62 FALSE -1.83077016 -2.79174465 0.10739932 -0.52478259 21:HSK
## 63 TRUE -1.83077016 -2.79174465 0.10739932 -0.52478259 21:NSK
## 64 FALSE 0.84438752 -0.13546580 0.19380941 -0.49245953 22:HN
## 65 FALSE 0.84438752 -0.13546580 0.19380941 -0.49245953 22:HSK
## 66 TRUE 0.84438752 -0.13546580 0.19380941 -0.49245953 22:NSK
## 67 FALSE 0.47664250 1.10431163 -0.21473283 -0.57780379 23:HN
## 68 FALSE 0.47664250 1.10431163 -0.21473283 -0.57780379 23:HSK
## 69 TRUE 0.47664250 1.10431163 -0.21473283 -0.57780379 23:NSK
## 70 FALSE -0.97378438 -1.20297922 -0.92499720 0.69996330 24:HN
## 71 FALSE -0.97378438 -1.20297922 -0.92499720 0.69996330 24:HSK
## 72 TRUE -0.97378438 -1.20297922 -0.92499720 0.69996330 24:NSK
## 73 FALSE -0.43949146 -0.56904392 0.70655740 0.45197878 25:HN
## 74 FALSE -0.43949146 -0.56904392 0.70655740 0.45197878 25:HSK
## 75 TRUE -0.43949146 -0.56904392 0.70655740 0.45197878 25:NSK
## 76 FALSE -2.72562327 -2.37027826 0.56457063 0.03242990 26:HN
## 77 FALSE -2.72562327 -2.37027826 0.56457063 0.03242990 26:HSK
## 78 TRUE -2.72562327 -2.37027826 0.56457063 0.03242990 26:NSK
## 79 FALSE -1.15023171 -1.23667570 -1.14795257 -0.40466318 27:HN
## 80 FALSE -1.15023171 -1.23667570 -1.14795257 -0.40466318 27:HSK
## 81 TRUE -1.15023171 -1.23667570 -1.14795257 -0.40466318 27:NSK
## 82 FALSE -0.30794115 0.69421487 0.73429910 0.42195159 28:HN
## 83 FALSE -0.30794115 0.69421487 0.73429910 0.42195159 28:HSK
## 84 TRUE -0.30794115 0.69421487 0.73429910 0.42195159 28:NSK
## 85 FALSE 0.04832165 -0.01195069 0.05083475 -1.09845314 29:HN
## 86 TRUE 0.04832165 -0.01195069 0.05083475 -1.09845314 29:HSK
## 87 FALSE 0.04832165 -0.01195069 0.05083475 -1.09845314 29:NSK
## 88 FALSE 1.06320501 1.06358450 -3.09383215 -1.10703867 30:HN
## 89 TRUE 1.06320501 1.06358450 -3.09383215 -1.10703867 30:HSK
## 90 FALSE 1.06320501 1.06358450 -3.09383215 -1.10703867 30:NSK
## 91 FALSE 0.73964563 0.92162469 0.72117527 0.69973578 31:HN
## 92 TRUE 0.73964563 0.92162469 0.72117527 0.69973578 31:HSK
## 93 FALSE 0.73964563 0.92162469 0.72117527 0.69973578 31:NSK
## 94 FALSE 0.95580988 -0.69738747 -0.74305466 -1.62180256 32:HN
## 95 TRUE 0.95580988 -0.69738747 -0.74305466 -1.62180256 32:HSK
## 96 FALSE 0.95580988 -0.69738747 -0.74305466 -1.62180256 32:NSK
## 97 FALSE 0.39210333 -0.09811246 -0.12415132 -0.65624257 33:HN
## 98 TRUE 0.39210333 -0.09811246 -0.12415132 -0.65624257 33:HSK
## 99 FALSE 0.39210333 -0.09811246 -0.12415132 -0.65624257 33:NSK
## 100 FALSE 0.02855979 -1.18326870 -1.60149904 -1.83925409 34:HN
## 101 TRUE 0.02855979 -1.18326870 -1.60149904 -1.83925409 34:HSK
## 102 FALSE 0.02855979 -1.18326870 -1.60149904 -1.83925409 34:NSK
## 103 FALSE -0.31902017 -0.70447256 -0.46457190 -0.03347530 35:HN
## 104 TRUE -0.31902017 -0.70447256 -0.46457190 -0.03347530 35:HSK
## 105 FALSE -0.31902017 -0.70447256 -0.46457190 -0.03347530 35:NSK
## 106 FALSE 0.49502620 1.13774129 0.77387567 -0.29700024 36:HN
## 107 TRUE 0.49502620 1.13774129 0.77387567 -0.29700024 36:HSK
## 108 FALSE 0.49502620 1.13774129 0.77387567 -0.29700024 36:NSK
## 109 FALSE 1.65908373 0.13602573 -0.51912071 -2.02439376 37:HN
## 110 TRUE 1.65908373 0.13602573 -0.51912071 -2.02439376 37:HSK
## 111 FALSE 1.65908373 0.13602573 -0.51912071 -2.02439376 37:NSK
## 112 FALSE -0.51901637 -0.09288501 1.24988155 -0.18468275 38:HN
## 113 TRUE -0.51901637 -0.09288501 1.24988155 -0.18468275 38:HSK
## 114 FALSE -0.51901637 -0.09288501 1.24988155 -0.18468275 38:NSK
## 115 FALSE -0.04031698 1.71276667 -0.19287633 -0.47027550 39:HN
## 116 TRUE -0.04031698 1.71276667 -0.19287633 -0.47027550 39:HSK
## 117 FALSE -0.04031698 1.71276667 -0.19287633 -0.47027550 39:NSK
## 118 FALSE 0.02476277 0.98387235 -0.81085596 0.06378856 40:HN
## 119 TRUE 0.02476277 0.98387235 -0.81085596 0.06378856 40:HSK
## 120 FALSE 0.02476277 0.98387235 -0.81085596 0.06378856 40:NSK
## 121 FALSE -0.33003630 0.56240561 0.79934069 2.01820761 41:HN
## 122 TRUE -0.33003630 0.56240561 0.79934069 2.01820761 41:HSK
## 123 FALSE -0.33003630 0.56240561 0.79934069 2.01820761 41:NSK
## 124 FALSE 0.78136314 1.45331343 -1.03150129 -1.42255320 42:HN
## 125 TRUE 0.78136314 1.45331343 -1.03150129 -1.42255320 42:HSK
## 126 FALSE 0.78136314 1.45331343 -1.03150129 -1.42255320 42:NSK
## 127 FALSE 0.85606308 0.36240815 0.76504839 0.77176546 43:HN
## 128 TRUE 0.85606308 0.36240815 0.76504839 0.77176546 43:HSK
## 129 FALSE 0.85606308 0.36240815 0.76504839 0.77176546 43:NSK
## 130 FALSE 2.59855104 0.90342688 -0.23272323 0.22965596 44:HN
## 131 TRUE 2.59855104 0.90342688 -0.23272323 0.22965596 44:HSK
## 132 FALSE 2.59855104 0.90342688 -0.23272323 0.22965596 44:NSK
##
## ~~~ indexes ~~~~
## id1 id2
## 1 1 HN
## 2 1 HSK
## 3 1 NSK
## 4 2 HN
## 5 2 HSK
## 6 2 NSK
## 7 3 HN
## 8 3 HSK
## 9 3 NSK
## 10 4 HN
## 11 4 HSK
## 12 4 NSK
## 13 5 HN
## 14 5 HSK
## 15 5 NSK
## 16 6 HN
## 17 6 HSK
## 18 6 NSK
## 19 7 HN
## 20 7 HSK
## 21 7 NSK
## 22 8 HN
## 23 8 HSK
## 24 8 NSK
## 25 9 HN
## 26 9 HSK
## 27 9 NSK
## 28 10 HN
## 29 10 HSK
## 30 10 NSK
## 31 11 HN
## 32 11 HSK
## 33 11 NSK
## 34 12 HN
## 35 12 HSK
## 36 12 NSK
## 37 13 HN
## 38 13 HSK
## 39 13 NSK
## 40 14 HN
## 41 14 HSK
## 42 14 NSK
## 43 15 HN
## 44 15 HSK
## 45 15 NSK
## 46 16 HN
## 47 16 HSK
## 48 16 NSK
## 49 17 HN
## 50 17 HSK
## 51 17 NSK
## 52 18 HN
## 53 18 HSK
## 54 18 NSK
## 55 19 HN
## 56 19 HSK
## 57 19 NSK
## 58 20 HN
## 59 20 HSK
## 60 20 NSK
## 61 21 HN
## 62 21 HSK
## 63 21 NSK
## 64 22 HN
## 65 22 HSK
## 66 22 NSK
## 67 23 HN
## 68 23 HSK
## 69 23 NSK
## 70 24 HN
## 71 24 HSK
## 72 24 NSK
## 73 25 HN
## 74 25 HSK
## 75 25 NSK
## 76 26 HN
## 77 26 HSK
## 78 26 NSK
## 79 27 HN
## 80 27 HSK
## 81 27 NSK
## 82 28 HN
## 83 28 HSK
## 84 28 NSK
## 85 29 HN
## 86 29 HSK
## 87 29 NSK
## 88 30 HN
## 89 30 HSK
## 90 30 NSK
## 91 31 HN
## 92 31 HSK
## 93 31 NSK
## 94 32 HN
## 95 32 HSK
## 96 32 NSK
## 97 33 HN
## 98 33 HSK
## 99 33 NSK
## 100 34 HN
## 101 34 HSK
## 102 34 NSK
## 103 35 HN
## 104 35 HSK
## 105 35 NSK
## 106 36 HN
## 107 36 HSK
## 108 36 NSK
## 109 37 HN
## 110 37 HSK
## 111 37 NSK
## 112 38 HN
## 113 38 HSK
## 114 38 NSK
## 115 39 HN
## 116 39 HSK
## 117 39 NSK
## 118 40 HN
## 119 40 HSK
## 120 40 NSK
## 121 41 HN
## 122 41 HSK
## 123 41 NSK
## 124 42 HN
## 125 42 HSK
## 126 42 NSK
## 127 43 HN
## 128 43 HSK
## 129 43 NSK
## 130 44 HN
## 131 44 HSK
## 132 44 NSK
## indexes: 1, 2
Wir wollen uns den dfidx Data-Frame nun einmal genauer anschauen. Leider sieht die Darstellung dieses Data-Frames unterschiedlich aus, je nachdem, ob wir ihn uns in der Ausgabe in RStudio anzeigen lassen oder ob wir uns die Ausgabe im HTML-Dokument anschauen. Wir gehen hier auf die Anzeige im HTML-Dokument ein, da sie etwas übersichtlicher ist. Wir können zunächst sehen, dass die Ausgabe zweigeteilt ist. Oben sehen wir einen Data-Frame mit 132 Zeilen. Die Zeilenanzahl hat sich also verdreifacht. Woran liegt das? Dies hängt mit der letzten Spalte namens “idx” zusammen, die neu gebildet wurde. Bei dieser Variable handelt es sich um eine Index-Variable. Wie sie sehen können, enthält jede Zeile dieser Variable zwei Werte: Eine Zahl und einen String. Wie kann das sein? Nach allem, was wir über Data-Frames in R wissen, kann jede Spalte nur Werte eines Typs (also entweder numerisch oder String) enthalten. Außerdem kann jede Zelle in einem Data-Frame normalerweise nur einen Wert enthalten. Die Lösung sehen wir im zweiten Teil der Ausgabe: Genau genommen enthält die Spalte “idx” einen “Unter-Data-Frame” mit zwei Spalten. Wie wir im unteren Teil der Ausgabe sehen können, enthält die Spalte “id1” dieses Unter-Data-Frames Zahlen, während die Spalte “id2” Strings enthält. Die Kombination dieser beiden Spalten kann uns auch erklären, warum unser Data-Frame nun dreimal mehr Zeilen hat als der urprüngliche: Jede Versuchsperson hat nun drei Zeilen. Welche drei Zeilen zu welcher Versuchsperson gehören, gibt die Zahl in “id1” an. Wir sehen auch, dass in “id2” jede Versuchsperson in ihren drei Zeilen die Werte “HN”, “HSK” und “NSK” hat. Dementsprechend wird die Gruppenzugehörigkeit einer Versuchsperson nicht mehr über einen von drei möglichen Werten in der Spalte “sztype” ausgedrückt. Statdessen nimmt die Spalte “sztype” den Wert TRUE in den Spalten an, wo der Wert in der Spalte “id2” der Gruppenzugehörigkeit der in “id1” referenzierten Versuchsperson entspricht. Die restlichen Zeilen nehmen den Wert FALSE an. Somit hat jede Versuchsperson in ihren drei Zeilen einmal den Wert TRUE und zweimal den Wert FALSE.
Nun wollen wir mittels der Funktion mlogit()
eine
multinomiale logistische Regression berechnen. Dazu übergeben wir der
Funktion drei Argumente:
lm()
gewohnt sind. Wir geben zunächst (wie
gewohnt) die vorherzusagende Variable gefolgt von einer Tilde (~) ein.
Dann folgt aber nur das Intercept (symbolisiert durch die 1) danach
folgt ein senkrechter Strich (|). Hinter dem Strich werden alle
Prädiktorvariablen (getrennt durch Pluszeichen) eingegebensummary()
lassen wir uns dann die Ergebnisse anzeigen.multlogreg <- mlogit(formula = sztype ~ 1 | sozatt + emo + panssneg + sansneg, data = diskrim_dfidx, reflevel = 'HN')
summary(multlogreg)
##
## Call:
## mlogit(formula = sztype ~ 1 | sozatt + emo + panssneg + sansneg,
## data = diskrim_dfidx, reflevel = "HN", method = "nr")
##
## Frequencies of alternatives:choice
## HN HSK NSK
## 0.34091 0.36364 0.29545
##
## nr method
## 5 iterations, 0h:0m:0s
## g'(-H)^-1g = 0.000429
## successive function values within tolerance limits
##
## Coefficients :
## Estimate Std. Error z-value Pr(>|z|)
## (Intercept):HSK 0.10674 0.51357 0.2078 0.83535
## (Intercept):NSK -0.13656 0.54010 -0.2528 0.80039
## sozatt:HSK 0.19099 0.55617 0.3434 0.73130
## sozatt:NSK -1.15781 0.67141 -1.7245 0.08463 .
## emo:HSK 1.10253 0.66191 1.6657 0.09578 .
## emo:NSK 0.30606 0.64193 0.4768 0.63352
## panssneg:HSK -0.60929 0.61126 -0.9968 0.31887
## panssneg:NSK -0.88210 0.61808 -1.4271 0.15354
## sansneg:HSK -1.38441 0.62755 -2.2061 0.02738 *
## sansneg:NSK -1.11671 0.64319 -1.7362 0.08253 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Log-Likelihood: -33.933
## McFadden R^2: 0.29567
## Likelihood ratio test : chisq = 28.489 (p.value = 0.00038965)
Wir haben hier wieder eine mehrgeteilte Ausgabe:
Wir möchten nun aber noch einen Globaltest erhalten, welchen Beitrag ein Prädiktor für die Trennung der drei Gruppen insgesamt leistet (anstatt diesen Beitrag getrennt für zwei binomial logistische Regressionen zu erhalten). Wir machen dies hier exemplarisch für den Prädiktor “sansneg”. Wir könnten dies aber natürlich analog auch für alle anderen Prädiktoren machen.
Zunächst fitten wir zu diesem Zweck ein weiteres Modell, in das wir alle Prädiktoren, bis auf den Prädiktor “sansneg” aufnehmen. Dieses Modell nennen wir “multlogreg_nosans”
multlogreg_nosans <- mlogit(sztype~1 | sozatt + emo + panssneg, data = diskrim_dfidx, reflevel = 'HSK')
Nun können wir mit der Funktion lrtest()
aus dem Paket
“lmtest” einen Likelihood-Ratio Test anfordern, der diese beiden Modelle
vergleicht.
lrtest(multlogreg_nosans, multlogreg)
Wir sehen, Dass die Differenz aus den -2Log-Likelihoods der beiden Modelle wieder eine \(\chi^2\)-verteilte Prüfgröße ergibt. Diese ist mit zwei Freiheitsgraden assoziiert. Dies kommt daher, dass für den Prädiktor “nosans” bei einer dreigestuften Klassenvariable zwei b-Gewichte geschätzt werden. Schließlich können wir noch den mit der Prüfgröße assoziierten p-Wert entnehmen.
Nun wollen wir uns (ähnlich wie bei der Diskriminanzanalyse) eine
Konfusionsmatrix ausgeben lassen. Dazu benötigen wir zunächst die
vorhergesagten Werte für unsere Versuchspersonen. Um diese zu erhalten,
müssen wir einen kleinen Umweg über die a-posteriori
Wahrscheinlichkeiten gehen. Diese erhalten wir mittels der Funktion
predict()
, die wir schon aus dem Kapitel zu binomial
logistischer Regression kennen. Bei der binomial logistischen Regression
konnten wir das Argument “newdata” einfach weglassen und R wusste, dass
es dann die Vorhersagen für die Daten, anhand derer das Modell gefittet
wurde, liefern soll. Dies funktioniert im Falle der multinomial
logistischen Regression leider nicht, so dass wir der Funktion das
Argument “newdata = diskrim_dfidx” übergeben müssen, damit R weiß, für
welche Daten die Vorhersagen getroffen werden sollen.
a_posteriori <- predict(object = multlogreg, newdata = diskrim_dfidx)
a_posteriori
## HN HSK NSK
## 1 0.924181171 0.057644649 0.01817418
## 2 0.809984279 0.174143825 0.01587190
## 3 0.524854788 0.350759688 0.12438552
## 4 0.235032012 0.276390423 0.48857757
## 5 0.190940039 0.071923718 0.73713624
## 6 0.551805562 0.191524128 0.25667031
## 7 0.575320430 0.325454889 0.09922468
## 8 0.500714667 0.078677704 0.42060763
## 9 0.659674252 0.209754343 0.13057140
## 10 0.216098158 0.723860106 0.06004174
## 11 0.333063068 0.180455961 0.48648097
## 12 0.529961198 0.398851256 0.07118755
## 13 0.540377332 0.330642917 0.12897975
## 14 0.647686788 0.085578190 0.26673502
## 15 0.905623581 0.058412082 0.03596434
## 16 0.068170343 0.441883363 0.48994629
## 17 0.410263529 0.205526703 0.38420977
## 18 0.223034297 0.068701374 0.70826433
## 19 0.013556080 0.298595254 0.68784867
## 20 0.175540766 0.415385505 0.40907373
## 21 0.163320151 0.011426086 0.82525376
## 22 0.290831064 0.575407119 0.13376182
## 23 0.076527201 0.799275599 0.12419720
## 24 0.323365665 0.052867347 0.62376699
## 25 0.631075217 0.119895444 0.24902934
## 26 0.146144580 0.004799888 0.84905553
## 27 0.086255410 0.069446865 0.84429773
## 28 0.433409816 0.348433211 0.21815697
## 29 0.116336856 0.571931033 0.31173211
## 30 0.006497645 0.872632180 0.12087017
## 31 0.503800681 0.436233391 0.05996593
## 32 0.077293536 0.710513285 0.21219318
## 33 0.195016218 0.561545420 0.24343836
## 34 0.033230702 0.341430489 0.62533881
## 35 0.306715906 0.205293039 0.48799105
## 36 0.180938350 0.730322388 0.08873926
## 37 0.023168010 0.930048775 0.04678321
## 38 0.458817058 0.251637974 0.28954497
## 39 0.050426041 0.793529580 0.15604438
## 40 0.122789499 0.609370894 0.26783961
## 41 0.868224350 0.063381497 0.06839415
## 42 0.010654568 0.917964418 0.07138101
## 43 0.667129840 0.280960778 0.05190938
## 44 0.192186197 0.797447047 0.01036676
Nun nutzen wir die Funktion max.col()
, um in jeder Zeile
die Nummer der Spalte zu erhalten, die den höchsten Wert (also die
höchste a-posteriori Wahrscheinlichkeit) enthält. Den so kreierten
Zahlenvektor nutzen wir, um daraus einen Vektor der entsprechenden
Klassenlabels zu erstellen. Schließlich sagen wir R noch, dass es mit
der Funktion as.factor()
den Vektor mit den Klassenlabels
in den Typ “factor” umwandeln soll.
pred_classes <- as.factor(colnames(a_posteriori)[max.col(a_posteriori)])
pred_classes
## [1] HN HN HN NSK NSK HN HN HN HN HSK NSK HN HN HN HN NSK HN NSK NSK
## [20] HSK NSK HSK HSK NSK HN NSK NSK HN HSK HSK HN HSK HSK NSK NSK HSK HSK HN
## [39] HSK HSK HN HSK HN HSK
## Levels: HN HSK NSK
Wir nutzen wieder die Funktion confusionMatrix()
aus dem
Paket “caret”, um eine Konfusionsmatrix der vorhergesagten und der
tatsächlichen Klassenzugehörigkeiten zu erhalten.
confusionMatrix(data = pred_classes, reference = diskrim$sztype)
## Warning in confusionMatrix.default(data = pred_classes, reference =
## diskrim$sztype): Levels are not in the same order for reference and data.
## Refactoring data to match.
## Confusion Matrix and Statistics
##
## Reference
## Prediction HN NSK HSK
## HN 11 3 4
## NSK 3 7 2
## HSK 1 3 10
##
## Overall Statistics
##
## Accuracy : 0.6364
## 95% CI : (0.4777, 0.7759)
## No Information Rate : 0.3636
## P-Value [Acc > NIR] : 0.0002162
##
## Kappa : 0.4526
##
## Mcnemar's Test P-Value : 0.5724067
##
## Statistics by Class:
##
## Class: HN Class: NSK Class: HSK
## Sensitivity 0.7333 0.5385 0.6250
## Specificity 0.7586 0.8387 0.8571
## Pos Pred Value 0.6111 0.5833 0.7143
## Neg Pred Value 0.8462 0.8125 0.8000
## Prevalence 0.3409 0.2955 0.3636
## Detection Rate 0.2500 0.1591 0.2273
## Detection Prevalence 0.4091 0.2727 0.3182
## Balanced Accuracy 0.7460 0.6886 0.7411
Uns wird hier zunächst eine Warnmeldung ausgegeben, die besagt, dass
die Faktorstufen im Falle der vorhergesagten und der tatsächlichen
Klassenzugehörigkeiten eine andere Reihenfolge hatten. Dieses Problem
hat die Funktion confusionMatrix()
aber im Hintergrund
selbst behoben.
Als nächstes können wir sehen, dass die Akkuratheit der Vorhersage insgesamt 63.6% beträgt. Damit ist die Vorhersage der multinomialen logistischen Regression deutlich besser als die der Diskriminanzanalyse. Man muss allerdings hinzufügen, dass die Diskriminanzanalyse einen unfairen Nachteil hatte: Wie wir bereits ausgeführt haben, hat die Diskriminanzanalyse nämlich die leave-one-out cross-validation verwendet. Wie wir im Exkurs zu Trainings- und Testdaten dargestellt haben, führt diese Methode in der Regel dazu, dass die Vorhersagequalität im Bezug auf das Trainingsdatenset verringert wird, dass dafür aber das Problem des Overfittings vermieden wird. Es könnte also sein, dass die Schätzung der Vorhersagequalität für die multinomiale logistische Regression überschätzt wird, da hier Trainings- und Testset die gleichen Daten beinhaltet haben. Dem Buchkapitel können Sie weitere Informationen dazu entnehmen, welches der beiden Verfahren bei Klassifikationsproblemen vorzuziehen ist.
So gibt es andere Klassifikationsalgorithmen neben der Diskriminanzanalyse, die standardmäßig eine Akkuratheit von 100% bei der Vorhersage der Klassen der Trainingsdaten erreichen (z.B. sogenannte decision trees). Derartige Modelle werden aber meist vereinfacht, so dass sie zwar keine Akkuratheit von 100% mehr bei der Klassifikation des Trainingsdatensets haben, aber wesentlich besser auf neue Daten generalisieren.↩︎
Die leave-one-out cross-validation ist eine Spezialform der k-fold cross validation. Dabei wird ein vorhandenes Datenset in k gleich große Teile geteilt. Danach wird der Klassifikationsalgorithmus k mal ausgeführt, wobei immer ein anderer der k gebildeten Subsets aus den Trainingsdaten ausgeschlossen wird und als Testset verwendet wird. Ein in der Praxis überlicher Wert ist \(k = 10\). Bei der leave-one-out cross-validtion gilt \(k = N\).↩︎
Es gäbe zwar auch eine Funktion, die mit unseren Daten
im vorliegenden Format arbeiten könnte, nämlich multinom()
aus dem Paket “nnet”. Die Ausgabe dieser Funktion ist allerdings so
sparsam, dass man sich am Ende fast alle relevanten Tests selbst von
Hand ausrechnen muss. Somit bereitet die Funktion mlogit()
für unsere Zwecke insgesamt weniger Aufwand als die Funktion
multinom()
.↩︎