4 Erste psychometrische Auswertungen
Dieses Kapitel arbeitet einige Kennwerte der klassischen Testtheorie auf
und bespricht wie wir diese in R
berechnen können. Dabei werden die
folgenden Konzepte behandelt:
- Summenwerte
- Item-Schwierigkeit
- Item-Trennschärfe
- Item-Interkorrelation
- Reliabilität
- Interne Konsistenz („Cronbachs Alpha“)
- Split-Half/Odd-Even-Reliabilität
- Spearman-Brown-Formel
Angenommen, eine Datentabelle enthält die Punktzahlen von zehn
Schulkindern in einer Klassenarbeit mit fünf Aufgaben. Diese kann man
gut in einer \(10 \times 5\) (Reihe \(\times\) Spalten) Datentabelle
darstellen. Ein Eintrag kodiert, ob das Kind (Reihe) die Aufgabe
(Spalte) korrekt gelöst hat. Korrekte Antworten werden mit 1 kodiert,
falsche Antworten mit 0 – ein typisches Datenformat in der
psychologischen Diagnostik. Wenn uns Daten in diesem Format vorliegen,
können wir auf viele Funktionen in R
zurückgreifen, um grundlegende
psychometrische Auswertungen durchzuführen. Dies sind etwa die
Bestimmung der Schwierigkeit und der Trennschärfe von Items, sowie die
Bestimmung einer Split-Half Reliabilität. Für fortgeschrittenere
Auswertungen – wie etwa die Berechnung von Cronbachs Alpha oder einer
Faktorenanalyse – werden wir auf Pakete zurückgreifen, die uns über die
Basics in R
hinaus weitere Funktionalitäten bieten. Aber auch für
diese Analysen benötigen wir genau dieses Datenformat!
Um das fortführende Beispiel selbst nachzuvollziehen, muss der folgende
data.frame
eingelesen werden:
test_data <- data.frame(
Item_1 = c(1, 1, 1, 0, 0, 0, 1, 1, 1, 0),
Item_2 = c(0, 0, 1, 0, 0, 0, 0, 0, 0, 0),
Item_3 = c(1, 0, 1, 0, 1, 1, 1, 0, 1, 0),
Item_4 = c(1, 0, 1, 0, 1, 0, 0, 0, 1, 0),
Item_5 = c(1, 0, 1, 0, 1, 0, 0, 0, 0, 0)
)
Merke: Das ist das Standard-Datenformat für all unsere psychometrischen Berechnungen: (a) Zeilen sind Fälle; (b) Spalten sind Items bzw. Messvariablen; (c) Zellen enthalten Datenpunkte, etwa die Korrektheit von Antworten (kodiert mit 1/0). Datenpunkte müssen nicht unbedingt – wie es in diesem Beispiel der Fall ist – dichotom sein, sondern können beispielsweise auch die Antworten in einem Persönlichkeitsfragebogen auf einer Likert-Skala repräsentieren.
4.1 Summenwerte
Wir bestimmen zunächst die Testscores der 10 Kinder. Da jede Zeile ein
Kind repräsentiert, ist der Gesamt-Testscore die Summe der Werte in
jeder Reihe. Die Summe der Reihen (engl: rows) eines data.frames
können wir mit der Funktion rowSums()
bestimmen:
[1] 4 1 5 0 3 1 2 1 3 0
Es ist manchmal praktisch Berechnungen, die pro Fall einen Wert ergeben,
direkt an den ursprünglichen data.frame
anzuhängen. Wie in Kapitel 3
erklärt, ist das mit der $
-Notation möglich:
Item_1 Item_2 Item_3 Item_4 Item_5 score
1 1 0 1 1 1 4
2 1 0 0 0 0 1
3 1 1 1 1 1 5
4 0 0 0 0 0 0
5 0 0 1 1 1 3
6 0 0 1 0 0 1
7 1 0 1 0 0 2
8 1 0 0 0 0 1
9 1 0 1 1 0 3
10 0 0 0 0 0 0
Da viele viele Analysen aber nur einen data.frame
mit den Item-Spalten
benötigt (\(\to\) psychometrisches Standardformat), ist hier Vorsicht bei
der Weiterverwendung geboten!
4.2 Item-Schwierigkeiten
Die Schwierigkeit eines Items ist die mittlere Punktzahl aller Personen in diesem Item. Auch bei Items, die nicht Korrektheit kodieren, kann man von Item-Schwierigkeit sprechen. Beispielsweise wäre dann die Item-Schwierigkeit die mittlere Zustimmungsrate für ein Item in einem Persönlichkeitsinventar, in dem Antworten auf einer 5-stufigen Likert-Skala gegeben werden. Hierbei macht die Einteilung in hohe vs. niedrige Schwierigkeit wenig Sinn; technisch gesehen bedeuten immer niedrigere Werte eine höhere Schwierigkeit (also etwa eine niedrige Zustimmungsrate).
Technisch gesehen ist die Schwierigkeit eines Items der Mittelwert der
Itemwerte in einer Spalte (engl: column) eines data.frames
im
psychometrischen Standardformat. Den Mittelwert pro Spalte kann ich mit
der Funktion colMeans()
bestimmen (analog gibt es auch die Funktionen
colSums()
und rowMeans()
):
Item_1 Item_2 Item_3 Item_4 Item_5 score
0.6 0.1 0.6 0.4 0.3 2.0
Da ich gerade den Gesamtscore als Spalte an test_data
angehängt habe,
bekomme ich die mittlere Punktzahl der Schüler/innen in den fünf
Testitems direkt mitgeliefert.
Die Funktion colMeans()
generalisiert die Funktion mean()
von einem
einzelnen Vektor auf alle Spalten in einem data.frame
. Beachtet: Würde
der data.frame
auch Spalten vom Typ factor
oder character
enthalten, wäre es nicht möglich, Funktionen wie rowSums()
und
colMeans()
darauf anzuwenden. Hier muss jede Spalte einen numerischen
Vektor enthalten.
4.3 Item-Interkorrelationen
Als Nächstes geben wir mit der Funktion cor()
die Korrelationen
zwischen allen Items als Korrelationsmatrix aus. Wenn cor()
als
Argument einen data.frame
erhält, wird eine Tabelle ausgegeben, die
die Korrelation zwischen allen Spalten – d.h. Items – des
data.frames
enthält.
Item_1 Item_2 Item_3 Item_4 Item_5 score
Item_1 1.00 0.27 0.17 0.25 0.09 0.51
Item_2 0.27 1.00 0.27 0.41 0.51 0.62
Item_3 0.17 0.27 1.00 0.67 0.53 0.76
Item_4 0.25 0.41 0.67 1.00 0.80 0.89
Item_5 0.09 0.51 0.53 0.80 1.00 0.81
score 0.51 0.62 0.76 0.89 0.81 1.00
Die Korrelationen wurden aus Darstellungszwecken mit der Funktion round()
auf
zwei Nachkommastellen gerundet. Die Ausgabe der Funktion cor()
ist eine
Tabelle, die alle Korrelationen zwischen den Items (und auch mit dem
Gesamtscore) abbildet. Beachtet, dass die Matrix symmetrisch ist, also die
Korrelation zwischen Item 1 und Item 2 natürlich der Korrelation zwischen Item 2
und Item 1 entspricht. Auf der Diagonalen befindet sich immer eine 1, da jedes
Item perfekt mit sich selbst korreliert. Die ausgegebene Tabelle erinnert an
einen data.frame
, ist aber technisch gesehen eine andere Datenstruktur,
nämlich eine Matrix. Der Unterschied zwischen Matritzen und data.frames
soll
uns jedoch zunächst nicht kümmern.
4.3.1 Exkurs: Programmatische Untersuchung der Korrelationsmatrix
Große Item-Korrelationsmatritzen sind oftmals unübersichtlich und erschweren den Überblick darüber, welche Items stärker oder weniger stark miteinander korrelieren. Eine visuelle Inspektion ist demnach mühsam und fehleranfällig. Stattdessen würden wir lieber programmatisch die Eigenschaften der Korrelationsmatrix erforschen. Glücklicherweise ist dies mit R möglich, da die Korrelationsmatrix selbst nur ein R-Objekt ist und wir beliebig damit arbeiten können.
Typischerweise weiß man beispielsweise gerne, welche zwei Items am stärksten miteinander korrelieren. Um dieser Frage nachzugehen, lernen wir in diesem Abschnitt, dass vektorisierte R-Funktionen im Normalfall nicht nur auf einfachen Vektoren agieren (siehe Kapitel 2), sondern sich auch auf komplexere Strukturen wie eine Korrelationsmatrix übertragen lassen.
Speichern wir zunächst die Item-Korrelationsmatrix in einer Variablen ab. Dabei achten wir darauf, die Korrelation zum Summenscore aus der Korrelationsmatrix zu entfernen; es interessieren uns nur die Korrelationen zwischen den einzelnen Items (der nächste Abschnitt behandelt die Bedeutung der Korrelationen zwischen Items und Summenscore):
Zunächst stellen wir fest, dass logische Operationen auf Korrelationsmatritzen anwendbar sind. Wir können so etwa feststellen, welche Items stärker als zu r = .50 miteinander korrelieren:
Item_1 Item_2 Item_3 Item_4 Item_5
Item_1 TRUE FALSE FALSE FALSE FALSE
Item_2 FALSE TRUE FALSE FALSE TRUE
Item_3 FALSE FALSE TRUE TRUE TRUE
Item_4 FALSE FALSE TRUE TRUE TRUE
Item_5 FALSE TRUE TRUE TRUE TRUE
Die Ausgabe ist eine logische Matrix, die für jedes Itempaar kodiert, ob die
Korrelation zwischen diesen Items größer ist als r = .50. Bei Item 5 und Item
2 ist dies beispielsweise der Fall. Eine solche logische Matrix kann jedoch
gerade bei vielen Items unübersichtlich werden. Wir können mit der Funktion
which()
herausfinden, welche Items mit mehr als r = .50
miteinander korrelieren:
row col
Item_1 1 1
Item_2 2 2
Item_5 5 2
Item_3 3 3
Item_4 4 3
Item_5 5 3
Item_3 3 4
Item_4 4 4
Item_5 5 4
Item_2 2 5
Item_3 3 5
Item_4 4 5
Item_5 5 5
Da wir hier eine Matrix und nicht einen Vektor untersuchen, müssen wir das
Argument arr.ind = TRUE
setzen, um eine sinnvolle Ausgabe zu erhalten.
Besonders übersichtlich ist diese Ausgabe jedoch immer noch nicht, da sie auch
alle “Autokorrelationen” markiert – also die Diagonale der Korrelationsmatrix,
die die Korrelation jedes Items mit sich selbst abbildet. Dies wollen wir
vermeiden. Eine Möglichkeit ist es, die Diagonale der Korrelationsmatrix
anzupassen. Auch hier verwenden wir eine Operation, die wir im Kapitel zu
Vektoren kennengelernt haben und die auch auf Matritzen generalisiert:
Item_1 Item_2 Item_3 Item_4 Item_5
Item_1 NA 0.27 0.17 0.25 0.09
Item_2 0.27 NA 0.27 0.41 0.51
Item_3 0.17 0.27 NA 0.67 0.53
Item_4 0.25 0.41 0.67 NA 0.80
Item_5 0.09 0.51 0.53 0.80 NA
Wir ersetzen auf diese Weise alle Einsen der Korrelationsmatrix durch einen
fehlenden Wert; danach können wir per which()
einfacher erfragen, welche
Korrelationen größer als r = .50 sind:
row col
Item_5 5 2
Item_4 4 3
Item_5 5 3
Item_3 3 4
Item_5 5 4
Item_2 2 5
Item_3 3 5
Item_4 4 5
Noch besser wird die Ausgabe, wenn wir die Redundanz aus der Korrelationsmatrix
entfernen; schließlich befinden sich im oberen und unteren Dreieck der Matrix
dieselben Informationen. Wir können die Korrelationen oben rechts durch
Verwendung der Funktion upper.tri()
24 durch NA
ersetzen:
Item_1 Item_2 Item_3 Item_4 Item_5
Item_1 NA NA NA NA NA
Item_2 0.27 NA NA NA NA
Item_3 0.17 0.27 NA NA NA
Item_4 0.25 0.41 0.67 NA NA
Item_5 0.09 0.51 0.53 0.8 NA
row col
Item_5 5 2
Item_4 4 3
Item_5 5 3
Item_5 5 4
Item 5 korreliert also stark mit den Items 2, 3 und 4, und Item 3 korreliert noch stark mit Item 4.
Mit einem ähnlichen Vorgehen können wir programmatisch – ohne visuelle
Inspektion – bestimmen, zwischen welchen Items die stärkste Korrelation
besteht. Hier wenden wir zunächst die Funktion max()
auf die
Korrelationsmatrix an:
[1] 0.8017837
Beachtet, dass diese Operation nicht sinnvoll gewesen wäre, wenn die
Autokorrelationen auf der Diagonalen noch enthalten gewesen wären. Nun können
wir durch eine logische Abfrage und die Funktion which()
bestimmen, zwischen
welchen Items die stärkste Korrelation besteht:
row col
Item_5 5 4
Am stärksten korrelieren also die Items 4 und 5 miteinander. Zugegeben, das hätten wir im Falle von 5 Items auch einfach durch Betrachten der Korrelationsmatrix erfassen können, aber gerade bei sehr großen Test-Inventaren ist die programmatische Untersuchung einer Korrelationsmatrix einer visuellen Inspektion gegenüber deutlich zu bevorzugen.
4.4 Item-Trennschärfen
Interessant ist die letzte Spalte (bzw. genauso die letzte Zeile) der obigen Korrelationsmatrix:
Item_1 Item_2 Item_3 Item_4 Item_5 score
Item_1 1.00 0.27 0.17 0.25 0.09 0.51
Item_2 0.27 1.00 0.27 0.41 0.51 0.62
Item_3 0.17 0.27 1.00 0.67 0.53 0.76
Item_4 0.25 0.41 0.67 1.00 0.80 0.89
Item_5 0.09 0.51 0.53 0.80 1.00 0.81
score 0.51 0.62 0.76 0.89 0.81 1.00
Diese gibt an, wie stark die Korrelation zwischen jedem Item und dem Testscore
ausfällt. Dieser Kennwert ist die (unkorrigierte) Trennschärfe der Items; wir
erhalten sie, da wir oben den Testscore als Spalte an unseren data.frame
angehängt haben. Die Item-Trennschärfe macht eine Aussage darüber, wie stark das
Abschneiden in einem Item mit dem Gesamt-Testscore zusammenhängt. Je höher die
Trennschärfe, desto besser vermag das Item zwischen Schüler/innen mit viel und
wenig Wissen (also einem hohen bzw. einem niedrigen Gesamt-Testscore) zu
trennen. Die Trennschärfe ist ein Kennwert, der zur Beurteilung der Güte eines
Items dienen kann.
Oftmals wird die „part-whole“ korrigierte Trennschärfe berechnet, bei der zur Berechnung der Trennschärfe jedes Items der Itemscore dieses Items aus der Gesamtpunktzahl ausgelassen wird. Somit wird eine „Kriterienkontamination“ vermieden, die zu einer Erhöhung der Trennschärfe führt. Diese Kriterienkontamination ergibt sich bei der unkorrigierten Trennschärfe daraus, dass der Itemscore selbst in das „Kriterium“ – also den Gesamt-Testscore – eingeht.25 Im Folgenden berechnen wir eine part-whole korrigierte Trennschärfe für Item 2. Zunächst erstelle ich einen Vektor zur Auswahl der Items, die ich zur Berechnung des Testscores unter Ausschluss von Item 2 heranziehe:
## Wähle Antworten auf Items 1, 3, 4, 5 aus:
select_items <- paste0("Item_", (1:5)[-2])
responses_no_item2 <- test_data[, select_items]
## Betrachte die Tabelle:
head(responses_no_item2)
Item_1 Item_3 Item_4 Item_5
1 1 1 1 1
2 1 0 0 0
3 1 1 1 1
4 0 0 0 0
5 0 1 1 1
6 0 1 0 0
Die Variable corrected_score
enthält nun die Testscores, die unter
Ausschluss des zweiten Items gebildet wurden. Das Vorgehen zur
Berechnung der bereinigten Scores lässt sich mithilfe der
[·,·]
-Notation und den Funktionen paste0()
und rowSums()
auch auf
beliebig viele Items erweitern. Da wir hier den Summenwert nur über vier
Items gebildet haben, hätte auch der folgende Code funktioniert:
Wie folgt können wir nun mithilfe der Funktion cor()
die korrigierte
Trennschärfe für Item 2 bestimmen:
[1] 0.4842001
Die korrigierte Trennschärfe von 0.48 liegt unter der unkorrigierten Trennschärfe von 0.62. Je weniger Items ein Test hat, desto mehr Gewicht hat das einzelne Item für den Testscore und umso stärker weichen korrigierte und unkorrigierte Trennschärfe voneinander ab. Bei nur fünf Items kann der Effekt substantiell sein.
Es ist zu beachten, dass die Funktion cor()
an dieser Stelle anders
verwendet wird als oben: Hier übergebe ich der Funktion cor()
mit dem
Befehl cor(test_data$Item_2, corrected_score)
zwei Vektoren gleicher
Länge. Ein Vektor enthält die Korrektheiten der Antworten auf Item 2,
der andere Vektor enthält den um Item 2 bereinigten Testscore. Oben habe
ich der Funktion cor()
nur ein Argument übergeben, nämlich den
data.frame
test_data
. In dem Fall wurde eine Tabelle ausgegeben –
eine Korrelationsmatrix –, die die Korrelationen zwischen allen
Spalten enthält.
Ich empfehle den Code-Block zur Berechnung der korrigierten Trennschärfe genau zu studieren. Darin finden sich viele der Grundlagen aus Kapitel 2 und 3 wieder:
- Die Erstellung von Vektoren mit der
1:n
-Notation - Die Negativ-Auswahl von Elementen aus Vektoren mit der
[·]
-Notation - Die Generierung eines Vektors vom Typ
character
mit der Funktionpaste0()
- Die Auswahl von Spalten in einem
data.frame
mit der[·,·]
-Notation
Wir merken, dass es mühsamer ist, die korrigierte Trennschärfe zu
berechnen als die unkorrigierte. Die unkorrigierte Trennschärfe erhielt
ich oben einfach, indem ich einen ganzen data.frame
an die Funktion
cor()
übergeben habe. Ich musste nur einen einzigen Funktionsaufruf –
oder eine Zeile Code – investieren. Um jedoch die korrigierte
Trennschärfe zu bestimmen, muss ich bei n Items n Mal einen
korrigierten Gesamtscore berechnen. Für jedes Item muss ich dann jeweils
das Item mit diesem korrigierten Score korrelieren. Wenn wir das für
jedes Item „händisch“ machen würden, wäre das sehr aufwendig
(beispielsweise könnten wir den Code oben n Mal kopieren und jeweils
die Itemnummern anpassen – das wäre sehr fehleranfällig). Einer der
Hauptgründe aus denen wir R
lernen ist, dass wir uns solche Arbeit
nicht machen wollen. Stattdessen wollen wir lernen, wie wir repetitive
Arbeiten automatisieren können. In Kapitel 7 lernen wir
Schleifen kennen, die uns ermöglichen, ohne wesentlich mehr Aufwand für
beliebig viele Items korrigierte Trennschärfen zu bestimmen.
4.5 Cronbachs Alpha
Als Nächstes bestimmen wir „Cronbachs Alpha“ als Maß für die interne Konsistenz der Antworten der Schüler/innen. Cronbachs Alpha ist ein Schätzer für die Reliabilität eines Tests. Im Falle eines Leistungstest mit dichotomer Bepunktung gibt es eine Antwort auf die Frage: Haben Kinder, die ein Item richtig beantworten, auch eine erhöhte Wahrscheinlichkeit, andere Items richtig zu beantworten? (Ebenso: haben Kinder, die ein Item falsch beantworten, auch eine erhöhte Wahrscheinlichkeit, andere Items falsch zu beantworten?). Je näher Cronbachs Alpha an 1 ist, desto stärker ist das der Fall – desto stärker ist die interne Konsistenz der Punktwerte. Ein Wert von 0 spricht dafür, dass gar keine Systematik in den Punktzahlen liegt – ob ich viele oder wenig Punkte bekommen habe, ist gänzlich zufällig.
R
bietet in der Grundversion keine Möglichkeit, Cronbachs Alpha zu
bestimmen. Man könnte sich eine eigene Berechnung programmieren, die
Cronbachs Alpha umsetzt.26 Wir machen uns aber zunutze, dass
bereits andere R
-Nutzer Cronbachs Alpha als Funktion umgesetzt haben,
und diese in einem Paket zur Verfügung gestellt haben. Eine Umsetzung
von Cronbachs Alpha findet sich im Paket psych
(Revelle, 2019). Mit der
Funktion library()
kann ich Pakete laden, die nicht zur
Grundausstattung von R
gehören. Voraussetzung ist, dass ich das Paket
auf meinem Rechner installiert habe. Die Erweiterbarkeit durch Pakete
ist eine der großen Stärken von R
.
Falls das Paket nicht installiert ist, kann ich es mit dem folgenden Befehl installieren:
Praktischerweise arbeitet die Funktion alpha()
aus dem psych
Paket genau mit dem Standard-Datenformat, das uns vorliegt: Zeilen
kennzeichnen Testteilnehmer, Spalten kennzeichnen Items. Wichtig ist
aber nun: Wir haben soeben den Testscore als zusätzliche Spalte an die
Testdatentabelle angehängt. Diese geht aber nicht in die Berechnung von
Cronbachs Alpha ein, sondern nur die Punktzahlen für die Items. Deswegen
entferne ich die Spalte score
wie folgt wieder:
[1] "Item_1" "Item_2" "Item_3" "Item_4" "Item_5"
Wir haben gelernt, dass wir Variablen mit der Funktion rm()
löschen
können. Wir können sie aber nicht nutzen, wenn wir Spalten aus
data.frames
entfernen wollen. Das liegt daran, dass die Spalte selber
keine Variable ist, sondern zu einem data.frame
gehört. Deswegen muss
man Spalten mit dem Befehl data.frame$spalte <- NULL
entfernen. NULL
ist in R
ein Wert, der für „Nicht-Existenz“ steht.
Nachdem wir das Paket psych
geladen und die Spalte score
entfernt haben, können wir Cronbachs Alpha mit der Funktion alpha()
bestimmen:
Reliability analysis
Call: alpha(x = test_data)
raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
0.76 0.77 0.8 0.4 3.3 0.12 0.4 0.34 0.34
95% confidence boundaries
lower alpha upper
Feldt 0.40 0.76 0.93
Duhachek 0.53 0.76 0.99
Reliability if an item is dropped:
raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
Item_1 0.82 0.82 0.82 0.53 4.5 0.082 0.035 0.52
Item_2 0.74 0.74 0.77 0.42 2.9 0.136 0.084 0.39
Item_3 0.70 0.72 0.75 0.39 2.5 0.156 0.062 0.34
Item_4 0.61 0.64 0.63 0.31 1.8 0.201 0.032 0.27
Item_5 0.66 0.67 0.66 0.34 2.1 0.170 0.032 0.27
Item statistics
n raw.r std.r r.cor r.drop mean sd
Item_1 10 0.51 0.49 0.29 0.23 0.6 0.52
Item_2 10 0.62 0.68 0.55 0.48 0.1 0.32
Item_3 10 0.76 0.73 0.65 0.57 0.6 0.52
Item_4 10 0.89 0.87 0.89 0.78 0.4 0.52
Item_5 10 0.81 0.82 0.82 0.67 0.3 0.48
Non missing response frequency for each item
0 1 miss
Item_1 0.4 0.6 0
Item_2 0.9 0.1 0
Item_3 0.4 0.6 0
Item_4 0.6 0.4 0
Item_5 0.7 0.3 0
Wir sehen, dass die Funktion alpha()
viel Output mit
Informationen zum übergebenen Item-Datensatz generiert und uns nicht
nur den Wert für Cronbachs Alpha zurückgibt. Dieser kann unter
raw_alpha
abgelesen werden und beträgt 0.76.
4.6 Split-Half-Reliabilität
Cronbachs Alpha ist ein Schätzer für die Reliabilität eines Tests. Andere mögliche Schätzer sind die Retest-Reliabilität und die Split-Half-Reliabilität. Diese basieren auf der Berechnung einer Korrelation zwischen zwei Punktwerten. Für die Bestimmung der Retest-Reliabilität lassen wir Testteilnehmer zweimal denselben Test bearbeiten und korrelieren die Punktwerte, die sich zu den zwei Testzeitpunkten ergeben.
Noch leichter ist die Bestimmung der Split-Half-Reliabilität, welche nicht das mehrmalige Bearbeiten desselben Tests erfordert. Dabei teilen wir die Items des Tests in zwei Gruppen ein und bilden Summenwerte für die beiden Testhälften, welche wir dann miteinander korrelieren. Wir müssen dabei berücksichtigen, dass wir nur die Hälfte des Tests zur Schätzung der Reliabilität verwenden. Dies kann mithilfe der Spearman-Brown-Formel korrigiert werden.
Die Spearman-Brown-Formel schätzt die Reliabilität eines Tests für den hypothetischen Fall, dass man diesen um einen bestimmten Faktor verlängern würde (d.h. man würde die bestehenden Items replizieren). Man kann sie verwenden, um den Reliabilitätsschätzer einer Split-Half-Korrelation zu korrigieren, da in diesen nur die Hälfte der Items eingehen. Die Spearman-Brown Formel ist diese:
\[r' = \frac{r \, n}{1 + (n - 1) r}\]
Hierbei ist r’ die um die Testlänge korrigierte Reliabilität. r ist der derzeitige Reliabilitätsschätzer, also beispielsweise die Korrelation von zwei Testhälften. n ist der Faktor, um den der Test hypothetisch verlängert wird. Für die Schätzung der Split-Half-Reliabilität muss man einen Verlängerungsfaktor von 2 annehmen, da man die Reliabilität nur mit einem halbierten Test schätzt (im Vergleich dazu geht bei der Bestimmung der Retest-Reliabilität zweimal der gesamte Test in die Korrelation ein).
Um die spearman-brown-korrigierte Split-Half-Reliabilität zu schätzen, teilen wir zunächst die Items in zwei Mengen auf; hier ist es nicht möglich gleich große Teile zu generieren, also wählen wir die ersten drei und die letzten zwei Items aus:
Als nächstes berechnen wir die Korrelation zwischen den beiden Testhälften:
[1] 0.6049383
Nun wollen wir diese Korrelation mit der Spearman-Brown-Formel korrigieren. Zu diesem Zweck definieren wir eine eigene Funktion, die die Spearman-Brown-Formel umsetzt. An dieser Stelle reicht es aus, das Konzept einer eigenen Funktion zur Kenntnis zu nehmen – es wird in Kapitel 6 wieder aufgegriffen:
## Definiere eine SPEARMAN-BROWN Funktion. Sie nimmt zwei Argumente an:
## (a) einen Reliabilitäts-Schätzer
## (b) einen Verlängerungsfaktor
spearman_brown <- function(reliability, factor) {
numerator <- reliability * factor
denominator <- 1 + (factor-1) * reliability
corrected_reliability <- numerator / denominator
return(corrected_reliability)
}
Wenn wir die Funktion definiert haben – das heißt: den Funktions-Code in der Konsole ausgeführt haben –, können wir sie wie andere bekannte Funktionen aufrufen. Wir müssen zwei Argumente angeben: (1) Unseren initialen Schätzer der Reliabilität, also die Korrelation zwischen den zwei Testhälften; (2) den Verlängerungsfaktor, hier 2, da wir die Reliabilität für die doppelte Testlänge schätzen wollen:
[1] 0.7538462
Wie wir sehen, liegt die Spearman-Brown-korrigierte Split-Half-Reliabilität näher an Cronbachs Alpha (0.76) als die unkorrigierte Korrelation der zwei Testhälften. Das liegt daran, dass die Korrelation der zwei Testhälften die Reliabilität systematisch unterschätzt, da dieser Schätzer nur auf der Hälfte der Items beruht. Es ist sogar so, dass Cronbachs Alpha genau der Mittelwert aller möglichen Spearman-Brown korrigierten Split-Half-Koeffizienten ist.
Alternativ hätten wir auch die Odd-Even-Reliabilität berechnen können, die die Testitems in gerade und ungerade Items einteilt, also hier zwei Testscores einerseits für die Items 1, 3 und 5, und andererseits für die Items 2 und 4 berechnet. Diese lässt sich mit nur wenig Änderungen am Code oben umsetzen – ich schlage vor, dies als Übung zu machen.
4.7 In der Praxis: Nutzung von Zusatzpaketen
In der praktischen psychometrischen Auswertung werden wir oftmals auf externe Pakete zurückgreifen, um Berechnungen durchzuführen. Insbesondere die selbst programmierte Berechnung der korrigierten Trennschärfe war, wie oben vorgestellt, recht mühsam und fehleranfällig. Außerdem ergab sie erst einmal nur eine einzige Trennschärfe. Idealerweise hätten wir aber durch nur einen Funktionsaufruf direkt die Trennschärfen aller Items eines Tests bestimmt.
Zu diesem Zweck greifen wir noch einmal auf das Paket psych
zurück.
Wie wir im Abschnitt zu Cronbachs Alpha gesehen haben, gibt
die Funktion alpha()
nicht nur den Wert von Cronbachs Alpha zurück,
sondern führt gleich noch eine ganze Reihe weiterer Berechnungen für
den Item-Datensatz durch, der ihr übergeben wird. Darunter befinden
sich auch die unkorrigierten und korrigierten Item-Trennschärfen. Im
Output können wir eine Tabelle Item-Kennwerten betrachten:
library("psych")
alpha(test_data)
# Betrachte hier im Output nur die Tabelle mit den Item-Kennwerten:
n raw.r std.r r.cor r.drop mean sd
Item_1 10 0.51 0.49 0.29 0.23 0.6 0.52
Item_2 10 0.62 0.68 0.55 0.48 0.1 0.32
Item_3 10 0.76 0.73 0.65 0.57 0.6 0.52
Item_4 10 0.89 0.87 0.89 0.78 0.4 0.52
Item_5 10 0.81 0.82 0.82 0.67 0.3 0.48
Die Spalte mit der Überschrift raw.r
beinhaltet die unkorrigierten
Trennschärfen der Items, die Spalte mit der Überschrift r.drop
beinhaltet die korrigierten Trennschärfen. Für Item 2 wird dieselbe
(hier gerundete) korrigierte Trennschärfe ausgegeben, die wir
oben im Abschnitt zu Item-Trennschärfen per Hand
berechnet haben. Interessant ist auch die Spalte n
, die noch einmal
aufführt, auf der Basis wievieler Item-Teilnahmen die Werte berechnet
wurden.
Insgesamt ist das Paket psych
ein wichtiges R
-Zusatzpaket
für psychometrische Auswertungen. Der Autor des psych
-Pakets (William Revelle)
stellt außerdem auf seiner Website (https://personality-project.org/r/psych/)
hilfreiche Materialien für die psychometrische Auswertung in R
zur Verfügung.
Dazu gehört auch ein ganzes Buch zur psychometrischen Datenauswertung
(http://www.personality-project.org/r/book/).
Wer mehr zur Manipulation von Matritzen lernen möchte, kann eine Recherche zu den Funktionen
upper.tri()
,lower.tri()
unddiag()
durchführen.↩Praktisch gesehen werden unkorrigierte und korrigierte Trennschärfe dieselbe relative Rangreihe zwischen den Items hinsichtlich ihrer Diskriminationsgüte abbilden.↩
Das wäre sogar eine gute Übung. Die Formel findet sich unter https://de.wikipedia.org/wiki/Cronbachs_Alpha↩