5  Index- und Skalenbildung

Oft erheben wir z.B. in Befragungen bestimmte Konstrukte nicht nur mit einer Frage oder einem Item, sondern operationalisieren sie über mehrere Fragen/Items. Für die Auswertung interessieren uns dann aber weniger die Antworten auf diese einzelnen Fragen/Items, sondern das Gesamtbild, das sich daraus ergibt. Zu diesem Zweck verdichten wir dann mehrere Variablen zu einer. Dies wird als Index- oder Skalenbildung bezeichnet.

Wir laden zunächst wieder wie immer das tidyverse-Paket und öffnen zudem den Datensatz des Victim Blaming-Experiments. Außerdem laden wir das psych-Paket, das für die Prüfung der internen Konsistenz benötigt wird. Dieses muss ggf. erst installiert werden, was RStudio auch vorschlägt.

library(psych)
library(tidyverse)
vb <- readxl::read_excel("data/victim_blaming.xlsx")

5.1 Summenindex berechnen

Ein Summenindex wird - wie der Name schon sagt - durch Aufsummieren der zugehörigen Variablen berechnet. Ein gutes Beispiel für den Einsatz eines Summenindexes sind die Variablen v_9a bis v_9g. Diese enthalten die Information, welche (und wie viele) Strafen die Proband:innen für die Täter:innen fordern (Sie sollten von der Schulleitung ermahnt werden, sie sollten von der Schule fliegen, sie sollten genauso bloßgestellt werden wie Sophia, sie sollten eine Strafe zahlen, sie sollten sich öffentlich entschuldigen, sie sollten nachsitzen müssen, sonstige Strafe) und sind 0/1 codiert (1 = Strafe gefordert, 0 = Strafe nicht gefordert). Durch Aufsummieren erhalten wir also einen Index, der uns verrät, wie viele Strafen (0 bis 7) jemand fordert und der somit als Indikator für die Einschätzung der Schwere des Cybermobbing-Vorfalls interpretiert werden kann.

Unser erster Gedanke ist, per mutate()-Befehl einen neuen Summenindex aus v_9a bis v_9g zu berechnen.

vb |>
  mutate(strafen = v_9a + v_9b + v_9c + v_9d + v_9e + v_9f + v_9g) |>
  select(v_9a, strafen) # der Select-Befehl dient lediglich der Tabellenerstellung für die Übersicht
# A tibble: 586 × 2
   v_9a strafen
  <dbl>   <dbl>
1    NA      NA
2    NA      NA
3    NA      NA
4    NA      NA
5     0       1
# ℹ 581 more rows

Dabei sehen wir ein Problem: Sobald in einer der sieben Variablen NA steht, wird auch die Summe NA. Während dies manchmal beabsichtigt sein kann, ergibt es in diesem Fall keinen Sinn. Denn schauen wir uns den Fragebogen und die Filterführung an, wird klar, dass die Frage nach den geforderten Strafen nur gestellt wurde, wenn die:der Proband:in vorher bei der Frage nach dem Strafmaß (v_8) nicht mit “1 = gar nicht bestrafen” geantwortet hat. Somit bedeutet ein NA für die v_9er-Variablen, dass keine Strafe gefordert wurde, der Summenindex-Wert sollte also 0 sein.

Um zeilenweise einen Summenindex zu berechnen, gibt es in R die Funktion rowSums(), die als Argument einen Datensatz bekommt. Unser zweiter Lösungsansatz ist daher folgender: Wir wählen mit select() die relevanten Spalten aus dem Gesamtdatensatz aus und übergeben diesen Ausschnitt an rowSums(), der wieder ein na.rm Argument hat, mit dem wir fehlende Werte berücksichtigen oder ignorieren können. Die Standardeinstellung ist hier FALSE, d.h. fehlende Werte in einer Variablen führen dazu, dass die Summe nicht berechnet wird. Das ändern wir nun, indem wir TRUE an das Funktionsargument übergeben. Wir speichern das Ergebnis in einem neuen Objekt strafen_index für die spätere Verwendung zwischen.

Da die Variablen v_9a bis v_9g im Datensatz alle hintereinander stehen, können wir - statt alle einzeln einzutippen - auch mit dem : dazwischen arbeiten. So werden alle Variablen ausgewählt, die zwischen v_9a und v_9g stehen.

strafen_ind <- vb |>
  select(v_9a:v_9g) |>
  rowSums(na.rm = TRUE)

Anschließend ergänzen wir den vb Datensatz, indem wir die neue Spalte anfügen.

vb <- vb |>
  mutate(strafen_index = strafen_ind)

vb |>
  select(v_9a, strafen_index)
# A tibble: 586 × 2
   v_9a strafen_index
  <dbl>         <dbl>
1    NA             0
2    NA             0
3    NA             0
4    NA             0
5     0             1
# ℹ 581 more rows

Abschließend berechnen wir den Mittelwert und die Standardabweichung der neuen Spalte (siehe hierzu Deskriptivstatistik).

vb |>
  summarise(
    Mittelwert = mean(strafen_index, na.rm = TRUE),
    Standardabweichung = sd(strafen_index, na.rm = TRUE)
  )
# A tibble: 1 × 2
  Mittelwert Standardabweichung
       <dbl>              <dbl>
1       2.26              0.926

Die Proband:innen schlagen im Mittel 2.3 (SD = 0.9) Strafen vor.

Wenn wir keine temporären Objekte wie strafen_index erstellen wollen, können wir rowSums() auch direkt innerhalb einer Pipeline mit mutate() verwenden. Anstelle von select() benötigen wir dann pick(), um die relevanten Spalten auszuwählen und einen Summenindex zu bilden.

vb |>
  mutate(strafen = rowSums(pick(v_9a:v_9g), na.rm = TRUE)) |>
  select(v_9a, strafen)
# A tibble: 586 × 2
   v_9a strafen
  <dbl>   <dbl>
1    NA       0
2    NA       0
3    NA       0
4    NA       0
5     0       1
# ℹ 581 more rows

5.2 Prüfung der internen Konsistenz

Im vorherigen Beispiel ging es um einen Summenindex. Diesen haben wir verwendet, weil wir angenommen haben, dass die Menge der geforderten Strafen uns eine relevante Information liefert. Ein anderer, sehr häufiger Anwendungsfall für das Bilden eines Indexes sind sogenannte Skalen. Skalen bestehen aus mehreren Items, also meist Aussagen, denen die Teilnehmer:innen einer Studie z.B. anhand einer Likert-Skala zustimmen o.ä. (etwas verwirrend ist hier, dass nicht nur das “Antwortformat”, sondern auch die Gesamtheit der Items als Skala bezeichnet wird). Ein Beispiel für eine solche Skala ist in unserem Victim Blaming-Datensatz die Victim Blaming-Skala (v_14a bis v_14e). Die Proband:innen beantworten die folgenden Aussagen auf einer Skala von 1 = trifft überhaupt nicht zu bis 5 = trifft voll und ganz zu:

Sophia (das Opfer) (a) …hat bekommen, was sie verdient, (b) … hat sich provozierend verhalten, (c) … wurde ungerecht behandelt, (d) … ist selbst schuld daran, (e) … hätte verhindern können, was passiert ist.

Uns interessieren nun aber für die Auswertung nicht die Antworten auf die einzelnen Aussagen (=Items), sondern wir wollen diese zu einem Wert zusammenfassen, der uns sagt, in welchem Maß die Proband:innen Victim Blaming betreiben.

Der Grund für die Abfrage eines Konstruktes (hier: Victim Blaming) über mehrere Items ist, dass diese ein Konstrukt meist reliabler messen als Einzelitems - so interessieren wir uns oft für komplexe Konstrukte, die schwer über eine Frage zu operationalisieren sind. Die Idee ist dabei, dass jedes Item, das Victim Blaming operationalisiert, für sich die Stärke des Victim Blaming anzeigen sollte (also: starkes Victim Blaming sollte sich in hohen Werten bei allen Einzelitems und allen Kombinationen von Einzelitems zeigen).

Die Reliabilität einer Skala können wir über verschiedene statistische Verfahren prüfen. Wir stellen im Folgenden ein sehr gängiges Maß vor, Cronbachs Alpha, das die interne Konsistenz (= vereinfacht gesagt: wie gut passen die Items zusammen?) einer Skala prüft.

Dies ist eine vereinfachte Darstellung! Um Cronbachs Alpha anwenden zu dürfen, müssten wir vorher bestimmte Voraussetzungen prüfen, das können wir aber nicht (fortgeschrittene Statistik). Das hier vorgestellte Vorgehen ist aber durchaus üblich in den Sozialwissenschaften und reicht somit für den Einstieg. Siehe hierzu vertiefend z.B. Field, 2009, 674ff.

Weiterhin ist zu beachten, dass Cronbachs Alpha lediglich die Reliabilitiät einer Skala prüfen kann, nicht aber ihre Validität, also die Frage, ob die Skala wirklich misst, was sie messen soll. Fragen der Validität sind Gegenstand anderer Kurse (z.B. des Befragungskurses).

Cronbachs Alpha sagt aus, wie gut mehrere Items ein gemeinsames, ihnen zugrundeliegendes Konstrukt messen. Es basiert auf der Idee von Kovaration und Korrelation (siehe hierzu Korrelation). Anhand von Cronbachs Alpha kann die Reliabilität einer Skala eingeschätzt werden. Als grobe Faustformel haben sich folgende Werte etabliert:

Alpha Bedeutung
> .90 exzellent
> .70 akzeptabel
<= .50 inakzeptabel

Warum > .90 kursiv gesetzt ist, erfahren Sie im Kurs :)

Cronbachs Alpha ist Teil des psych-Paketes. Da wir dieses nicht komplett laden (wollen), stellen wir es der entsprechenden Funktion alpha voraus. Vorher müssen wir mit select noch die Variablen auswählen, für die wir Cronbachs Alpha berechnen wollen.

Da die Variablen v_14a bis v_14e im Datensatz alle hintereinander stehen, können wir - statt alle einzeln einzutippen - auch mit dem : dazwischen arbeiten. So werden alle Variablen ausgewählt, die zwischen v_14a und v_14e stehen.

vb |>
  select(v_14a:v_14e) |>
  psych::alpha()
Some items ( v_14c ) were negatively correlated with the first principal component and 
probably should be reversed.  
To do this, run the function again with the 'check.keys=TRUE' option

Reliability analysis   
Call: psych::alpha(x = select(vb, v_14a:v_14e))

  raw_alpha std.alpha G6(smc) average_r  S/N   ase mean   sd median_r
      0.31      0.36    0.43       0.1 0.57 0.044  2.3 0.51     0.24

    95% confidence boundaries 
         lower alpha upper
Feldt     0.21  0.31  0.39
Duhachek  0.22  0.31  0.39

 Reliability if an item is dropped:
      raw_alpha std.alpha G6(smc) average_r  S/N alpha se  var.r med.r
v_14a     0.207      0.25    0.33     0.078 0.34    0.053 0.0967 0.089
v_14b     0.049      0.13    0.25     0.036 0.15    0.064 0.0901 0.016
v_14c     0.648      0.65    0.59     0.319 1.88    0.023 0.0063 0.339
v_14d     0.055      0.10    0.20     0.028 0.11    0.063 0.0725 0.016
v_14e     0.082      0.18    0.29     0.052 0.22    0.063 0.1111 0.050

 Item statistics 
        n raw.r std.r r.cor r.drop mean   sd
v_14a 586  0.51 0.587  0.43   0.23  1.3 0.80
v_14b 586  0.68 0.682  0.59   0.35  2.1 1.04
v_14c 586  0.12 0.041 -0.44  -0.31  4.3 1.13
v_14d 586  0.66 0.700  0.66   0.38  1.6 0.91
v_14e 586  0.67 0.645  0.51   0.32  2.1 1.07

Non missing response frequency for each item
         1    2    3    4    5 miss
v_14a 0.84 0.09 0.03 0.01 0.03    0
v_14b 0.34 0.34 0.21 0.09 0.02    0
v_14c 0.06 0.03 0.05 0.22 0.64    0
v_14d 0.60 0.27 0.09 0.03 0.02    0
v_14e 0.36 0.32 0.21 0.08 0.03    0

Betrachten wir den Output, sehen wir direkt am Anfang eine Warnmeldung: “Some items ( v_14c ) were negatively correlated with the total scale and probably should be reversed.”

Die v_14c scheint also nicht zu den anderen Items zu passen, sie korreliert negativ statt positiv mit ihnen. Schauen wir uns das Item an, wird auch klar, wieso das der Fall ist: v_14c wurde ungerecht behandelt ist umgekehrt gepolt - hier bedeutet ein hoher Wert niedriges Victim Blaming.

Um die interne Konsistenz zu prüfen, müssen wir v_14c also zunächst umpolen, sodass auch hier hohe Werte hohes Victim Blaming bedeuten. Am einfachsten geht dies bei 5er-Skalen, indem wir 6-x rechnen (allgemein: höchste Ausprägung +1, davon dann den jeweiligen Wert abziehen).

vb <- vb |>
  mutate(v_14crec = 6 - v_14c)


vb |>
  select(v_14c, v_14crec)
# A tibble: 586 × 2
  v_14c v_14crec
  <dbl>    <dbl>
1     4        2
2     4        2
3     5        1
4     5        1
5     5        1
# ℹ 581 more rows

Nun können wir Cronbachs Alpha noch einmal berechnen - dieses Mal mit der umgepolten Variable.

vb |>
  select(v_14a, v_14b, v_14crec, v_14d, v_14e) |>
  psych::alpha()

Reliability analysis   
Call: psych::alpha(x = select(vb, v_14a, v_14b, v_14crec, v_14d, v_14e))

  raw_alpha std.alpha G6(smc) average_r S/N   ase mean   sd median_r
      0.65      0.66    0.62      0.28   2 0.023  1.8 0.64     0.29

    95% confidence boundaries 
         lower alpha upper
Feldt      0.6  0.65  0.69
Duhachek   0.6  0.65  0.69

 Reliability if an item is dropped:
         raw_alpha std.alpha G6(smc) average_r S/N alpha se  var.r med.r
v_14a         0.60      0.61    0.55      0.28 1.6    0.027 0.0093  0.29
v_14b         0.57      0.59    0.53      0.26 1.4    0.029 0.0089  0.27
v_14crec      0.65      0.65    0.59      0.32 1.9    0.023 0.0063  0.34
v_14d         0.54      0.55    0.49      0.24 1.2    0.031 0.0057  0.25
v_14e         0.62      0.63    0.57      0.30 1.7    0.026 0.0045  0.29

 Item statistics 
           n raw.r std.r r.cor r.drop mean   sd
v_14a    586  0.61  0.65  0.51   0.41  1.3 0.80
v_14b    586  0.69  0.68  0.57   0.45  2.1 1.04
v_14crec 586  0.61  0.58  0.39   0.31  1.7 1.13
v_14d    586  0.71  0.73  0.65   0.52  1.6 0.91
v_14e    586  0.63  0.61  0.45   0.36  2.1 1.07

Non missing response frequency for each item
            1    2    3    4    5 miss
v_14a    0.84 0.09 0.03 0.01 0.03    0
v_14b    0.34 0.34 0.21 0.09 0.02    0
v_14crec 0.64 0.22 0.05 0.03 0.06    0
v_14d    0.60 0.27 0.09 0.03 0.02    0
v_14e    0.36 0.32 0.21 0.08 0.03    0

Nun erscheint keine Warnung mehr und wir können uns der Interpretation des Outputs widmen. Im Prinzip ist der zentrale Wert, auf den wir schauen, raw_alpha, das uns den Cronbachs Alpha-Wert für unsere Victim Blaming-Skala angibt. Er liegt bei ,65 und ist damit leider nur fragwürdig. Das bedeutet, dass wir mit unserer Victim Blaming-Skala nicht unbedingt gut das zugrundeliegende Konstrukt messen.

Helfen kann hier ein Blick auf die Spalte raw_alpha unter Reliability if an item is dropped. Dort steht für jedes unserer fünf Items, welchen Cronbachs Alpha-Wert die Skala erreichen würde, wenn wir dieses Item rauslassen würde. Steht hier ein deutlich höherer Wert als oben unter raw_alpha, spricht dies dafür, dass das entsprechende Item nicht gut zu den anderen passt und wir erwägen sollten, es aus der Skala zu entfernen. Leider trifft das in unserem Fall nicht zu; das Weglassen eines Items hätte keine Verbesserung der Gesamtskala zur Folge.

Alle anderen Werte sind für uns nicht so zental.

Der nächste Schritt nach der Prüfung der internen Konsistenz ist nun, die einzelnen Items auch zu einem Index zu verrechnen. Auch wenn wir hier streng genommen einen zu niedrigen Cronbachs Alpha-Wert haben, gehen wir die Indexbildung am Beispiel von Victim Blaming durch.

5.3 Mittelwertindex berechnen

Neben dem Summenindex ergibt es häufig Sinn, einen Mittelwertindex zu berechnen. Das gilt v.a. dann, wenn wir mehrere, auf einer einheitlichen Antwortskala (z.B. einer 5-stufigen Likert-Skala) gemessenen Items zusammenfassen wollen. Denn dann ist der Wertebereich des Indexes gleich mit dem der Einzelitems und somit leichter zu interpretieren als ein Summenindex.

Wir nehmen als Beispiel die Victim Blaming-Items (Variablen v_14a bis v_14e). Wir wollen aus allen Einzelantworten einen Gesamtscore berechnen, der uns für jeden Teilnehmenden sagt, wie sehr diese:dieser dem Opfer die Schuld am Vorfall gibt.

Wie schon bei der Berechnung der internen Konsistenz müssen wir zunächst immer prüfen, ob alle Items, die wir verrechnen wollen, gleich gepolt sind, d.h. bei allen ein hoher Wert hohes Victim Blaming bedeutet (und umgekehrt). Wir wissen schon, dass dies für v_14c wurde ungerecht behandelt nicht gilt. Wir müssen also auch den Mittelwertindex mit der umgepolten Variablen berechnen (Wir haben die Variable oben schon gebildet, hier nur der Vollständigkeit halber noch einmal der Code).

vb <- vb |>
  mutate(v_14crec = 6 - v_14c)


vb |>
  select(v_14c, v_14crec)
# A tibble: 586 × 2
  v_14c v_14crec
  <dbl>    <dbl>
1     4        2
2     4        2
3     5        1
4     5        1
5     5        1
# ℹ 581 more rows

Nun können wir den Mittelwertindex berechnen. Hierfür sind zwei Schritte notwendig: (1) wir müssen mit select() die Variablen auswählen, die für die Indexbildung berücksichtigt werden sollen. (2) Wir bilden mit rowMeans() den Mittelwert dieser Variablen. Dabei geben wir an, dass dieser auch berechnet werden soll, wenn einzelene Werte NA sind.

vb_ind <- vb |>
  select(v_14a, v_14b, v_14crec, v_14d, v_14e) |>
  rowMeans(na.rm = TRUE)

vb <- vb |> # Hier fügen wir die neue Variable an unseren Datensatz an
  mutate(vb_index = vb_ind)

vb |> # Schließlich berechnen wir den Mittelwert und die Standardabweichung
  summarise(
    Mittelwert = mean(vb_index, na.rm = TRUE),
    Standardabweichung = sd(vb_index, na.rm = TRUE)
  )
# A tibble: 1 × 2
  Mittelwert Standardabweichung
       <dbl>              <dbl>
1       1.76              0.643

Die Proband:innen betreiben insgesamt sehr wenig Victim Blaming (M = 1.8, SD = 0.6).

5.4 Glossar

Funktion Definition
psych::alpha() Schätzung der internen Konsistenz (Reliabilität, Cronbachs Alpha) einer Skala, auf Basis der Spalten eines Dataframes/Tibbles
rowMeans() Berechnung des Zeilenmittelwerts über alle Spalten eines Dataframes/Tibbles
rowSums() Berechnung der Zeilensumme über alle Spalten eines Dataframes/Tibbles

5.5 Hausaufgabe

Für die Hausaufgabe analysieren wir den Datensatz gewohnheiten.xlsx.

  1. Berechnen Sie die interne Konsistenz und den Mittelwertindex für die Items zur Trait-Selbstkontrolle (p_sc1 bis p_sc13).

  2. Der SRHI (Self-Report Habit Index) misst die Gewohnheitsstärke. Es wurde u.a. die Gewohnheitsstärke für die Smartphone-Nutzung erhoben (s_srhi_r1 bis s_srhi_c2). Der SRHI besteht aus drei Subdimensionen (Wiederholung „rep“, geringe Aufmerksamkeit/Bewusstheit „auto“ und geringe Kontrollierbarkeit „control“). Sind diese drei Gewohnheitsdimensionen für das Smartphone jeweils intern konsistent? Falls ja, berechnen Sie für jede dieser Subdimensionen einen Mittelwertindex.

Achtung: im Datensatz gibt es bereits die hier zu berechnenden Variablen (p_sc, smart_srhi_rep, smart_srhi_auto und smart_srhi_control). Sie sollen aber mit den Originalitems selbst die interne Konsistenz und den Mittelwertindex berechnen!

Für alle Aufgaben gilt:

  • Geben Sie als Kommentar (mit # beginnend) an, welche Frage Sie bearbeiten, darunter folgt der zugehörige Code.

  • Die Antwortsätze folgen darunter, ebenfalls als Kommentar (mit # beginnend).