5  Daten transformieren und Skalen bilden

Wie wird aus sechs einzelnen Items eine messbare Einstellung?

In Kapitel 4 hast du den Datensatz gelesen, Variablen gefunden und fehlende Werte deklariert. Jetzt geht es um das, was in der quantitativen Sozialforschung Operationalisierung heißt: Aus einer abstrakten Idee („Islamfeindlichkeit”) werden konkrete Variablen, die du am Ende rechnen kannst.

Hinweis

Forschungsjournal: Wo stehst du in deiner Mini-Studie? Du hast die Rohdaten — jetzt baust du das, was am Ende deine abhängige Variable sein wird. Die Skalenbildung ist methodisch der zentrale Schritt: hier entscheidet sich, ob deine Modelle in den späteren Kapiteln auf etwas Stabilem aufsetzen. Wenn dieses Kapitel zu Ende ist, hältst du islamophobie und populismus als saubere Variablen in der Hand.

5.1 Worum es geht

Frag jemanden direkt: „Sind Sie islamfeindlich?“* — und du wirst fast immer ein Nein bekommen. Selbst von Menschen, die in Wahlumfragen rechtspopulistisch wählen und in Diskussionen klar abgrenzende Aussagen treffen. Das hat zwei Gründe. Erstens: Niemand will sich öffentlich als „islamfeindlich” bezeichnen — das ist ein Begriff, der negativ konnotiert ist. Zweitens: Einstellungen sind nicht so klar umrissen wie ein Ja-oder-Nein. Jemand kann findet manche* Aspekte einer Religion problematisch, andere nicht — und ist deshalb ein bisschen islamskeptisch, ohne die ganze Etikette anzunehmen.

Die Sozialforschung löst dieses Problem mit einem alten Trick: Sie fragt nicht direkt nach dem Konstrukt, sondern nach mehreren konkreten Aussagen, die das Konstrukt indirekt erfassen. Statt „Sind Sie islamfeindlich?” fragt sie:

„Ich finde, dass die Ausübung des Islam in Deutschland beschränkt werden sollte.”

und

„Der Islam passt in unsere Gesellschaft.”

und

„Die Anwesenheit von Muslimen bringt Konflikte.”

Zusammen ergeben diese sechs Items ein Bild davon, wie eine Person zur muslimischen Bevölkerung in Deutschland steht. Aus den Antworten wird ein einziger Skalenwert berechnet, der robuster und differenzierter ist als jede Einzelantwort.

Diesen Übersetzungsschritt — vom abstrakten Konstrukt zur messbaren Variable — nennt die quantitative Sozialforschung Operationalisierung. Sie ist der methodische Kern jeder empirischen Studie: Eine Theorie kannst du nur dann an Daten prüfen, wenn du sie vorher in messbare Größen übersetzt hast.

Dieses Kapitel zeigt dir den Weg von den sechs rohen Items bis zur fertigen Skala. Fünf Schritte:

  1. Neue Variablen erzeugen (mutate()) — etwa aus zwei alten Variablen eine abgeleitete Größe ableiten.
  2. Bedingungslogik (case_when(), if_else()) — Kategorien neu schneiden („wer < 30 ist, gilt als jung”).
  3. Rekodieren (rec()) — die zentrale Operation: Werte umkodieren, Kategorien zusammenfassen, umpolen (Reverse Coding).
  4. Skalen bilden (row_means()) — aus mehreren Items einen Mittelwert pro Befragte:n.
  5. Vergleichbar machen (pomps()) — Skalen unterschiedlicher Bandbreite auf eine 0–100-Basis bringen.

Am Ende des Kapitels hast du die zwei Skalen der Mini-Studie — Islamfeindlichkeit (islamophobie, 1–7) und Populismus (populismus, 1–5) — sauber aufgebaut und dokumentiert. Damit gehst du ab Kapitel 7 in die Analyse.

Was du nach diesem Kapitel kannst

  • Neue Variablen mit mutate() erzeugen.
  • Mit case_when(), case_match() und if_else() Bedingungslogik schreiben.
  • Subgruppen-Aggregate mit summarise(.by = ...) rechnen.
  • Variablen mit rec() rekodieren — vom einfachen Umkodieren über "dicho"/"quart" bis zum Umpolen (Reverse Coding).
  • Dummy-Variablen für Regressionen mit to_dummy() erzeugen.
  • Variablen standardisieren (std()) und zentrieren (center()).
  • Aus mehreren Items eine gewichtete Mittelwert-Skala mit row_means() und kontrolliertem min_valid bilden.
  • Skalen unterschiedlicher Bandbreite mit pomps() auf eine gemeinsame 0–100-Skala bringen.
  • Die vollständige Datenpräp-Pipeline der Mini-Studie nachvollziehen und auf eigene Konstrukte übertragen.

5.2 Daten transformieren

Vier Verben aus dplyr decken den Großteil aller Datentransformationen ab:

Funktion Wirkung
mutate() Variablen neu erzeugen oder ändern (SPSS: COMPUTE)
case_when() / case_match() Vektorisierte Bedingungslogik (SPSS: IF)
if_else() Knappe Form für zwei-stufige Bedingungen
summarise() Zusammenfassungen pro Gruppe (SPSS: AGGREGATE)
group_by() Gruppierung für nachfolgende Operationen
distinct() Einzigartige Werte einer Variable
rename() Variablen umbenennen

5.2.1 Neue Variablen mit mutate()

allbus |>
  select(age) |>
  mutate(geburtsjahr = 2023 - age) |>
  head(3)
# A tibble: 3 × 2
  age       geburtsjahr
  <dbl+lbl>       <dbl>
1 50               1973
2 51               1972
3 69               1954

Soll dieselbe Transformation auf mehrere Variablen wirken, hilft across():

allbus |>
  mutate(across(c(mm01, mm02, mm03), as.numeric))

5.2.2 Bedingungslogik mit case_when() und if_else()

case_when() ist das R-Äquivalent zu SPSS’ IF. Du listest Bedingungen in der Form bedingung ~ wert auf — die erste zutreffende gewinnt.

allbus |>
  select(educ) |>
  mutate(
    bildung = case_when(
      educ %in% 1:2 ~ "niedrig",
      educ %in% c(3, 7) ~ "mittel",
      educ %in% 4:5 ~ "hoch",
      .default = NA
    )
  ) |>
  count(bildung)
# A tibble: 4 × 2
  bildung     n
  <chr>   <int>
1 hoch     2472
2 mittel   1665
3 niedrig   982
4 <NA>      127

Bei nur zwei Ausprägungen ist if_else(bedingung, wert_wenn_wahr, wert_wenn_falsch) knapper:

allbus |>
  mutate(jung = if_else(age < 30, "jung", "30+")) |>
  count(jung)
# A tibble: 3 × 2
  jung      n
  <chr> <int>
1 30+    4529
2 jung    694
3 <NA>     23

Seit dplyr 1.1 gibt es zusätzlich case_match() — knapper als case_when(), wenn du nur Werte mappst (ohne Vergleichsoperatoren):

allbus |>
  select(eastwest) |>
  mutate(region = case_match(eastwest, 1 ~ "West", 2 ~ "Ost")) |>
  count(region)
# A tibble: 2 × 2
  region     n
  <chr>  <int>
1 Ost     1679
2 West    3567

5.2.3 Aggregation mit group_by() und summarise()

allbus |>
  group_by(eastwest) |>
  summarise(
    n_faelle           = n(),
    n_einz_bildung     = n_distinct(educ),
    durchschnitt_alter = mean(age, na.rm = TRUE)
  )
# A tibble: 2 × 4
  eastwest               n_faelle n_einz_bildung durchschnitt_alter
  <dbl+lbl>                 <int>          <int>              <dbl>
1 1 [ALTE BUNDESLAENDER]     3567              8               51.7
2 2 [NEUE BUNDESLAENDER]     1679              8               54.3

n() zählt alle Fälle in der Gruppe, n_distinct() zählt einzigartige Werte einer Variablen.

Tipp

.by als Alternative. Seit dplyr 1.1 kannst du die Gruppierung auch direkt im Aufruf von summarise() oder mutate() setzen, ohne group_by() davor:

allbus |>
  summarise(
    durchschnitt_alter = mean(age, na.rm = TRUE),
    .by = eastwest
  )
# A tibble: 2 × 2
  eastwest               durchschnitt_alter
  <dbl+lbl>                           <dbl>
1 1 [ALTE BUNDESLAENDER]               51.7
2 2 [NEUE BUNDESLAENDER]               54.3

Das ist kürzer und vermeidet, dass du ungroup() vergisst.

5.2.4 distinct() und rename()

distinct() zeigt dir alle einzigartigen Ausprägungen einer Variable — die schnellste Antwort auf „welche Codes gibt es eigentlich?“:

allbus |>
  distinct(eastwest)
# A tibble: 2 × 1
  eastwest              
  <dbl+lbl>             
1 1 [ALTE BUNDESLAENDER]
2 2 [NEUE BUNDESLAENDER]

rename() benennt Variablen um — neuer Name links, alter Name rechts:

allbus |>
  rename(geschlecht = sex, alter = age) |>
  select(geschlecht, alter) |>
  head(3)
# A tibble: 3 × 2
  geschlecht alter    
  <dbl+lbl>  <dbl+lbl>
1 1 [MANN]   50       
2 1 [MANN]   51       
3 2 [FRAU]   69       

Beide sind kleine, aber regelmäßig genutzte Werkzeuge — gerade beim Übersetzen von kryptischen ALLBUS-Namen in sprechende Kürzel für deinen Analyse-Datensatz.

5.3 Rekodierung mit rec()

Stell dir vor, du hast die Bildungsangaben von 5.246 Personen in der Variable educ. Werte 1 bis 7 stehen für sieben verschiedene Schulabschlüsse — vom Volksschulabschluss bis zum Abitur, plus „anderer Abschluss” als 7. Für eine Regression willst du das aber nicht als sieben Kategorien haben, sondern gröber: niedrig / mittel / hoch. Du rekodierst die Variable.

Das ist die häufigste Datenoperation in der Sozialforschung — und gleichzeitig eine der fehleranfälligsten. Ein vertauschter Wert, eine vergessene Kategorie, und deine ganze Analyse läuft auf einem falschen Maßstab. SPSS hat dafür den RECODE-Befehl mit einer eigenen kleinen Syntax. mariposas rec()-Funktion macht dasselbe, ist aber für tidyverse-Workflows gebaut: pipe-freundlich, behält Labels, und versteht eine kompakte Regel-Syntax, in der du eine ganze Umkodierung in einer einzigen Zeichenkette ausdrückst.

Syntax:

data |>
  rec(variable, rules = "1=1; 2:3=2; else=NA")

Die Regel-Syntax im Überblick:

Muster Wirkung Beispiel
alt=neu Einzelwert wird umkodiert "1=10; 2=20"
lo:hi=neu Wertebereich umkodieren "1:3=1"
min:x=neu, x:max=neu Dynamische Grenzen "min:5=1; 6:max=2"
[Label] Inline-Wertelabel vergeben "1:2=1 [niedrig]; 3:5=2 [hoch]"
else=copy Alle nicht erwähnten Werte unverändert "1:3=1; else=copy"
else=NA Alle nicht erwähnten Werte werden NA "1=1; else=NA"
NA=neu NA durch einen Wert ersetzen "NA=0; else=copy"
val=NA Bestimmte Werte zu NA machen "-9=NA; -8=NA; else=copy"
"rev" Skala umpolen (max + min - x) rules = "rev"
"dicho" Dichotomisieren am Median (0/1) rules = "dicho"
"dicho(x)" Dichotomisieren am festen Cut-Punkt rules = "dicho(3)"
"mean" Dichotomisieren am Mittelwert rules = "mean"
"quart" In vier Quartilgruppen aufteilen rules = "quart"

Regeln werden in Reihenfolge geprüft, die erste passende gewinnt.

5.3.1 Beispiel: Bildung kategorisieren

allbus |>
  rec(educ, rules = "1:2=1 [niedrig]; 3=2 [mittel]; 4:5=3 [hoch]; else=NA",
      as.factor = TRUE) |>
  count(educ)
# A tibble: 4 × 2
  educ        n
  <fct>   <int>
1 niedrig   982
2 mittel   1639
3 hoch     2472
4 <NA>      153

Mit as.factor = TRUE wird die rekodierte Variable direkt ein Faktor; die […]-Notation in den Regeln vergibt die Wertelabels in einem Aufwasch.

5.3.2 Spezial-Modi: Dichotomisieren und Quartile

Statt eine Regel-Kette zu schreiben, kannst du eine Variable in einem Aufruf am Median, an einem festen Cut-Punkt, am Mittelwert oder in Quartile zerlegen:

allbus |>
  rec(age, rules = "dicho(50)", suffix = "_d") |>
  count(age_d)
# A tibble: 3 × 2
  age_d     n
  <dbl> <int>
1     0  2281
2     1  2942
3    NA    23

Hier wird age_d zu 0 für unter 50, zu 1 für 50+. Mit suffix = "_d" bekommt die neue Variable einen klaren Namen — das Original bleibt unangetastet.

allbus |>
  rec(age, rules = "quart", suffix = "_q") |>
  count(age_q)
# A tibble: 5 × 2
  age_q     n
  <dbl> <int>
1     1  1322
2     2  1344
3     3  1259
4     4  1298
5    NA    23

age_q ist jetzt eine kategoriale Variable mit den Werten 1–4 für die Altersquartile.

5.3.3 Lehrstück: Umpolen (Reverse Coding)

Was passiert, wenn du sechs Items zu einer Skala zusammenrechnest, von denen vier in dieselbe Richtung formuliert sind und zwei entgegengesetzt? Du bekommst Müll. Die positiv formulierten Items ziehen den Mittelwert in die eine Richtung, die negativen in die andere — und am Ende heben sich Effekte auf, die eigentlich addiert werden sollten.

Genau das ist der Fall bei unserer Islamfeindlichkeits-Skala. Die Forscher:innen haben die sechs Items absichtlich gemischt formuliert — vier negativ („Islam beschränken”), zwei positiv („Islam passt in die Gesellschaft”). Das ist eine bewusste Methode gegen einen klassischen Survey-Bias namens Akquieszenz: die Neigung mancher Befragten, Aussagen pauschal zuzustimmen, egal worum es geht. Wenn alle sechs Items gleich gepolt wären, würde diese Tendenz das Ergebnis verzerren. Durch die Mischung neutralisiert sie sich.

Für dich heißt das: Bevor du die Items zu einer Skala zusammenrechnest, musst du die zwei positiv formulierten Items umpolen — also so umkodieren, dass am Ende alle sechs in dieselbe Richtung zeigen.

Item Wortlaut Polung
mm01 Islamausübung in Deutschland beschränken hoch = islamophob
mm02 Islam passt in die deutsche Gesellschaft hoch = TOLERANT — umpolen
mm03 Anwesenheit von Muslimen bringt Konflikt hoch = islamophob
mm04 Staat sollte islamische Gruppen beobachten hoch = islamophob
mm05 Muslimischer Bürgermeister in Ordnung hoch = TOLERANT — umpolen
mm06 Unter Muslimen sind viele rel. Fanatiker hoch = islamophob

Bevor du aus den sechs Items einen Mittelwert bildest, musst du mm02 und mm05 umpolen, sonst heben sich die Effekte auf. mariposa hat dafür den Spezial-Modus "rev":

allbus <- allbus |>
  rec(mm02, rules = "rev", suffix = "r") |>
  rec(mm05, rules = "rev", suffix = "r")

"rev" rechnet intern max(x) + min(x) - x — bei einer 7-stufigen Skala also 8 - x, was genau das gewünschte Umpolen ist. Mit suffix = "r" erzeugt mariposa zwei neue Variablen mm02r und mm05r; die Originale mm02 und mm05 bleiben unverändert. Das ist die saubere Form — du verlierst nichts und kannst die Umpolung jederzeit nachvollziehen.

Hinweis

Hintergrund: Warum positiv formulierte Items? In der Survey-Methodologie ist die Mischung aus zustimmend und ablehnend formulierten Items eine Standard-Technik gegen Akquieszenz — die Tendenz, allen Aussagen zuzustimmen. Wer die Akquieszenz-Falle herausrechnen will, muss umpolen. Vergisst du diesen Schritt, korrelieren die umgepolten Items negativ mit den anderen — und Cronbachs α (siehe Kapitel 8.4) bricht ein. Das ist das klassische Warnsignal einer vergessenen Umpolung.

Hinweis

Hintergrund: allbus <- allbus |> ... überschreibt. Wenn du allbus <- schreibst, ersetzt du das Tibble im Speicher um die rekodierten Spalten. Die Originaldatei ALLBUS2023.sav auf der Festplatte bleibt unangetastet — du kannst die Pipeline jederzeit neu starten. Möchtest du Zwischenstände parallel behalten, weist du einer neuen Variable zu (allbus_mm <- allbus |> rec(...)).

Wichtig

mariposa-Tipp: Saubere Umpolung mit suffix. Andere Pakete überschreiben gerne die Originalvariable beim Rekodieren. mariposa zwingt dich, dir bewusst zu sein, was du tust — Original bleibt, neue Variable bekommt einen klaren Namen mit Suffix. Wenn drei Wochen später ein:e Reviewer:in fragt „warum war Skalenwert für Fall 42 = 4.5?“, kannst du den Schritt rekonstruieren.

Warnung

Vorsicht: Polung immer prüfen, nicht raten. Schau dir vor jeder Skalenbildung das Wortlaut-Label der Items an (var_label()) — auch Items, die du schon hundertmal gesehen hast. Der nervigste Fehler einer Skala ist eine vergessene Umpolung; sie zeigt sich an einem überraschend niedrigen Cronbachs α.

5.3.4 Dummy-Variablen mit to_dummy()

Für Regressionen brauchst du oft Dummy-Variablen — eine kategoriale Variable mit k Ausprägungen wird in k-1 Indikator-Spalten zerlegt (0/1 pro Ausprägung). mariposas to_dummy() macht das in einem Aufruf:

allbus |>
  to_dummy(eastwest, ref = 1)        # West (=1) als Referenz, dummy für Ost

Die neuen Spalten werden automatisch angehängt; mit ref = legst du fest, welche Ausprägung als Referenz weggelassen wird. Dummy-Variablen brauchst du erst in Kapitel 9 für die Regression — lm() und linear_regression() aus mariposa erstellen sie für Faktoren auch automatisch im Hintergrund.

5.4 Standardisieren und zentrieren

Vor manchen Analysen ist es sinnvoll, eine Variable auf einen einheitlichen Maßstab zu bringen.

allbus |>
  std(age, suffix = "_z") |>     # neue Variable age_z (Mittelwert 0, SD 1)
  select(age, age_z) |>
  head(3)
# A tibble: 3 × 2
  age         age_z
  <dbl+lbl>   <dbl>
1 50        -0.138 
2 51        -0.0828
3 69         0.903 

Mit center() analog für mittelwertzentrierte Variablen:

allbus |>
  center(age, suffix = "_c")     # neue Variable age_c (Mittelwert 0)

Ohne suffix-Argument überschreiben beide Funktionen die Originalvariable — das ist selten gewünscht. Beide akzeptieren außerdem ein weights =-Argument, falls du die Standardisierung gewichtet machen willst.

5.5 Skalen bilden

Jetzt kommt der Moment, auf den dieses Kapitel zugelaufen ist: aus sechs umgepolten Items wird eine Skala. Das ist methodisch einfach — und konzeptionell der wichtigste Schritt zum Verstehen, was die Sozialforschung eigentlich macht.

Die Logik ist die folgende: Wenn die sechs Items alle dasselbe Konstrukt messen (was du in Kapitel 8 noch faktorenanalytisch prüfst), dann ist der Mittelwert über die sechs Items eine bessere Schätzung der zugrundeliegenden Einstellung als jedes einzelne Item für sich. Einzelne Items rauschen — jeder Mensch versteht eine Frage etwas anders, hat einen schlechten Tag oder reagiert besonders auf einen Begriff. Über sechs Items mittelt sich das Rauschen raus, und übrig bleibt das gemeinsame Signal: die Hintergrundeinstellung.

In SPSS würde das eine kurze COMPUTE-Anweisung sein. In R nutzt du row_means() aus mariposa, das genau für diesen Zweck gebaut ist. Es gibt drei verwandte Funktionen:

Funktion Was sie tut
row_means(data, ..., min_valid = N) Mittelwert pro Fall über die angegebenen Variablen
row_sums(data, ..., min_valid = N) Summe pro Fall
row_count(data, ..., count = wert) Wie oft ein bestimmter Wert in der Zeile vorkommt

Das Argument min_valid gibt vor, wie viele gültige Antworten mindestens da sein müssen, damit der Mittelwert berechnet wird. Andernfalls bleibt der Skalenwert NA. Faustregel: mindestens 80 % der Items.

Wichtig: row_means() (und ihre Geschwister) geben einen numerischen Vektor zurück — sie wollen also in einem mutate()-Aufruf eingebettet werden, mit pick() zur Variablenauswahl. Das ist tidyverse-idiomatisch und macht klar, dass eine neue Spalte entsteht.

5.5.1 Islamfeindlichkeits-Skala

allbus <- allbus |>
  mutate(
    islamophobie = row_means(pick(mm01, mm02r, mm03, mm04, mm05r, mm06),
                             min_valid = 5)
  )

Schnelle Prüfung, ob die Skala plausibel ist:

allbus |> describe(islamophobie)

Descriptive Statistics
----------------------
     Variable  Mean Median    SD Range   IQR Skewness    N Missing
 islamophobie 4.113      4 1.549     6 2.333    0.147 3345    1901
----------------------------------------
Hinweis

Hintergrund: Was misst die Skala? Werte nahe 1 bedeuten geringe Zustimmung zu islamfeindlichen Aussagen, Werte nahe 7 hohe Zustimmung. Da die positiv formulierten Items (mm02r, mm05r) umgepolt sind, „zieht” hohes Wohlwollen gegenüber Muslimen den Skalenwert nach unten — wie es bei einer Skala für Islamfeindlichkeit sein soll.

Hinweis

Forschungshintergrund: Wer hat das gemessen? Die sechs mm-Items sind etabliert in der deutschsprachigen Forschung zu gruppenbezogener Menschenfeindlichkeit (Decker & Brähler; Pickel/Pickel). Sie messen einen kohärenten Konstruktbereich — wir prüfen das in Kapitel 8.3 noch faktorenanalytisch und in Kapitel 8.4 mit Cronbachs α. Die Mini-Studie nutzt die Skala unter dem Namen islamophobie (kürzer, international anschlussfähig) — der inhaltliche Gegenstand bleibt jedoch Islam- bzw. Muslimfeindlichkeit als spezifische Facette gruppenbezogener Menschenfeindlichkeit.

5.5.2 Antwortstil prüfen mit row_count()

Bevor wir die Populismus-Skala bilden, ein kleiner Daten-Qualitäts-Check: Wie oft hat jemand bei den mm-Items die extremste Antwort (7) gewählt? Hoher Wert deutet auf eine response style hin — jemand kreuzt durchgängig „voll und ganz zu” an, unabhängig vom Item.

allbus |>
  mutate(n_extrem = row_count(pick(mm01, mm02, mm03, mm04, mm05, mm06),
                              count = 7)) |>
  count(n_extrem)
# A tibble: 7 × 2
  n_extrem     n
     <int> <int>
1        0  3399
2        1   958
3        2   407
4        3   214
5        4   233
6        5    30
7        6     5

Die meisten Befragten zeigen kein solches Muster — wer alle sechs Items mit 7 beantwortet, ist eine kleine Minderheit. row_count() ist generell nützlich für Daten-Quality-Checks: wie viele „weiß nicht”, wie viele Extremantworten, wie viele Mittelantworten?

5.5.3 Populismus-Skala

Hier wartet eine zweite Polungs-Falle — und genau die ist der Grund, warum du dich vor jeder Skalenbildung mit dem Codebook beschäftigst. Schau dir zuerst die Wertelabels eines pa-Items an:

val_labels(allbus$pa29)
STIMME VOLL ZU STIMME EHER ZU    TEILS/TEILS  LEHNE EHER AB  LEHNE GANZ AB 
             1              2              3              4              5 

Das pa-Modul nutzt eine 5-stufige Skala, bei der 1 = „stimme voll zu” und 5 = „lehne ganz ab” steht. Das ist die umgekehrte Logik zu den mm-Items, wo 1 Ablehnung und 7 Zustimmung bedeutete. Folglich heißt für pa29 „Abgeordnete nur dem Volk verpflichtet” ein niedriger Wert = populistisch.

Damit am Ende populismus so funktioniert wie islamophobie (hoch = mehr von der gemessenen Einstellung), polen wir alle sieben pa-Items um — sie sind alle gleich (invers) kodiert, die Umpolung läuft also für alle in einer Schleife identisch:

allbus <- allbus |>
  rec(pa29, rules = "rev", suffix = "r") |>
  rec(pa30, rules = "rev", suffix = "r") |>
  rec(pa31, rules = "rev", suffix = "r") |>
  rec(pa32, rules = "rev", suffix = "r") |>
  rec(pa33, rules = "rev", suffix = "r") |>
  rec(pa34, rules = "rev", suffix = "r") |>
  rec(pa35, rules = "rev", suffix = "r") |>
  mutate(
    populismus = row_means(pick(pa29r, pa30r, pa31r, pa32r, pa33r, pa34r, pa35r),
                           min_valid = 6)
  )

allbus |> describe(populismus)

Descriptive Statistics
----------------------
   Variable  Mean Median    SD Range   IQR Skewness    N Missing
 populismus 3.398  3.429 0.767     4 1.143    0.041 3563    1683
----------------------------------------
Hinweis

Forschungshintergrund: Populismus messen. Die sieben pa-Items basieren auf einer Skala von Schulz et al. (2017) und decken drei klassische Populismus-Dimensionen ab: Anti-Elitismus, Volkszentrismus, Manichäismus (Volk vs. korrupte Elite). Hohe Werte bedeuten populistische Einstellungsmuster — das ist nicht gleichzusetzen mit Wahlpräferenz für populistische Parteien, sondern eine Einstellung, die quer durchs Parteienspektrum vorkommen kann.

Warnung

Vorsicht: Polung wird in der Praxis öfter übersehen, als du denkst. Items in einer Itembatterie sind nicht immer in dieselbe Richtung kodiert — selbst nicht innerhalb derselben Welle desselben Datensatzes. Die mm-Items von ALLBUS 2023 nutzen 7-stufig (1 = nicht zu, 7 = voll zu), die pa-Items 5-stufig (1 = voll zu, 5 = lehne ab). Wenn du auf eine neue Skala stößt, gilt ausnahmslos: erst Wertelabels prüfen, dann Skala bauen.

5.6 Skalen vergleichbar machen mit pomps()

Stell dir vor, du sollst beurteilen, welcher Eindruck bei den Befragten stärker ausgeprägt ist: ihre Islamfeindlichkeit oder ihr Populismus? Mit den Original-Skalenwerten ist das eine Falle. Islamfeindlichkeit läuft von 1 bis 7, Populismus von 1 bis 5. Ein Mittelwert von 4 bedeutet auf der ersten Skala „leicht mittig”, auf der zweiten „obere Hälfte”. Ein direkter Vergleich der Mittelwerte ist also irreführend — du würdest Birnen mit Äpfeln vergleichen.

Die Lösung ist ein methodischer Klassiker: Beide Skalen werden auf einen gemeinsamen Bereich umgerechnet, typischerweise 0 bis 100. Eine Person mit dem Minimalwert ihrer Original-Skala landet auf 0, eine mit dem Maximalwert auf 100, und alles dazwischen wird linear umgerechnet. So sind die Werte direkt vergleichbar — wie wenn man Schul-Noten von zwei verschiedenen Notenssystemen in dieselbe Prozentschiene überführt.

Die Methode heißt POMPS (Percent of Maximum Possible Scores). Sie ist in der Methodenliteratur seit Cohen et al. (1999) etabliert und ein Standardwerkzeug für Skalenvergleiche.

Die Formel selbst ist banal — alle Werte werden auf einen Anteil relativ zur theoretischen Spannweite umgerechnet:

\[ \text{POMPS} = \frac{x - \text{min}}{\text{max} - \text{min}} \times 100 \]

mariposa hat das als pomps() direkt verbaut:

allbus <- allbus |>
  mutate(
    islamophobie_p = pomps(islamophobie, scale_min = 1, scale_max = 7),
    populismus_p   = pomps(populismus,   scale_min = 1, scale_max = 5)
  )

allbus |>
  summarise(
    islam_orig = round(mean(islamophobie,   na.rm = TRUE), 2),
    islam_p    = round(mean(islamophobie_p, na.rm = TRUE), 2),
    pop_orig   = round(mean(populismus,     na.rm = TRUE), 2),
    pop_p      = round(mean(populismus_p,   na.rm = TRUE), 2)
  )
# A tibble: 1 × 4
  islam_orig islam_p pop_orig pop_p
       <dbl>   <dbl>    <dbl> <dbl>
1       4.11    51.9      3.4  60.0

Jetzt liest du den Vergleich direkt: liegt der POMPS-Mittelwert für Islamfeindlichkeit höher als der für Populismus, ist die durchschnittliche Bevölkerung in relativer Intensität stärker islamophob als populistisch — oder umgekehrt.

Wichtig

mariposa-Tipp: scale_min und scale_max immer angeben. Ohne diese Argumente nutzt pomps() den beobachteten Wertebereich (min(x), max(x)) — bei einer 1–7-Skala, in der niemand 1 angekreuzt hat, würde 2 zur „neuen Null”, was die Skala verzerrt. Gib bei Likert-Items immer den theoretischen Wertebereich an.

Hinweis

Hintergrund: Korrelationen bleiben erhalten. POMPS ist eine lineare Transformation — die Verteilung der Werte verändert sich nicht, nur der Maßstab. Korrelationen, Effektstärken und alle linearen Modelle liefern auf den POMPS-Variablen genau dieselben Ergebnisse wie auf den Originalen. Du verlierst also nichts; du gewinnst nur Vergleichbarkeit zwischen Skalen unterschiedlicher Bandbreite.

5.7 Die komplette Datenpräp-Pipeline

Was du in diesem Kapitel Stück für Stück aufgebaut hast, lässt sich zu einer einzigen sauberen Pipeline zusammenfassen. Diese Pipeline ist der Anker für Kap. 6–9 — du wirst sie als Setup-Block am Anfang jedes weiteren Kapitels wiederfinden (technisch eingebunden über source("R/prep.R")):

1allbus <- read_spss("ALLBUS2023.sav") |>
2  rec(mm02, rules = "rev", suffix = "r") |>
  rec(mm05, rules = "rev", suffix = "r") |>
3  rec(pa29, rules = "rev", suffix = "r") |>
  rec(pa30, rules = "rev", suffix = "r") |>
  rec(pa31, rules = "rev", suffix = "r") |>
  rec(pa32, rules = "rev", suffix = "r") |>
  rec(pa33, rules = "rev", suffix = "r") |>
  rec(pa34, rules = "rev", suffix = "r") |>
  rec(pa35, rules = "rev", suffix = "r") |>
  mutate(
    islamophobie   = row_means(pick(mm01, mm02r, mm03, mm04, mm05r, mm06),
4                               min_valid = 5),
    populismus     = row_means(pick(pa29r, pa30r, pa31r, pa32r, pa33r, pa34r, pa35r),
5                               min_valid = 6),
6    islamophobie_p = pomps(islamophobie, scale_min = 1, scale_max = 7),
    populismus_p   = pomps(populismus,   scale_min = 1, scale_max = 5)
  )
1
ALLBUS 2023 einlesen — fehlende Werte sind automatisch als tagged NAs gesetzt.
2
Umpolen der inversen mm-Items (mm02, mm05) zu mm02r/mm05r — Skala 7-stufig.
3
Umpolen aller pa-Items, weil sie 5-stufig invers kodiert sind (1 = stimme zu, 5 = lehne ab) — nach Umpolung gilt hoch = populistisch.
4
Skala Islamfeindlichkeit als Mittelwert der sechs (jetzt gleichpoligen) Items — mindestens 5 von 6 müssen valide sein.
5
Skala Populismus als Mittelwert der sieben umgepolten pa-Items — mindestens 6 von 7 müssen valide sein.
6
POMPS-Versionen beider Skalen auf 0–100 für direkten Vergleich (optional; die Original-Skalen bleiben erhalten).

Mit dieser Pipeline ist der Datensatz fertig für die Analyse.

Hinweis

Reviewer-Hinweis. In einem Methodenbericht würdest du genau diese Schritte dokumentieren: Welche Items? Welche umgepolt — warum? Welche Mindest-Validität? Welche Skalenrichtung? Wer das transparent macht, gibt Reviewer:innen das Werkzeug in die Hand, die Operationalisierung zu beurteilen. Wer nur cronbachs α = 0.87 berichtet, hat seine Pflicht nicht erfüllt.

Übungen

HinweisÜbung 1 · Skala Politische Effizienz · Reproduktion

Die pe-Items (pe01, pe04, pe05, pe06, pe07, pe08) messen politische Selbstwirksamkeit (kognitive Komponente). Prüfe zuerst die Variablenlabels mit var_label(), identifiziere ob Items umgepolt werden müssen, und baue analog eine Skala polit_effizienz mit min_valid = 5. Tipp: schaue dir die Wortlaute genau an.

allbus |>
  select(pe01, pe04, pe05, pe06, pe07, pe08) |>
  var_label()
# Items pe05 und pe07 sind positiv gepolt, müssen umgepolt werden.
allbus <- allbus |>
  rec(pe05, rules = "rev", suffix = "r") |>
  rec(pe07, rules = "rev", suffix = "r") |>
  mutate(
    polit_effizienz = row_means(pick(pe01, pe04, pe05r, pe06, pe07r, pe08),
                                min_valid = 5)
  )
HinweisÜbung 2 · ISCED-Bildung kategorisieren · Reproduktion

Statt educ kannst du auch die international vergleichbare ISCED-Variable isced97 (1–6) als Bildungsmaß nehmen. Erstelle daraus drei Kategorien: ISCED 1–2 = „niedrig”, 3–4 = „mittel”, 5–6 = „hoch”.

allbus |>
  rec(isced97, rules = "1:2=1 [niedrig]; 3:4=2 [mittel]; 5:6=3 [hoch]",
      as.factor = TRUE) |>
  count(isced97)
HinweisÜbung 3 · Skalen vergleichbar machen · Transfer

Liegen die Befragten in Deutschland 2023 in der Mini-Studie stärker auf der Populismus- oder auf der Islamfeindlichkeits-Skala? Rechne beide Skalen auf POMPS um und vergleiche die gewichteten Mittelwerte (Hinweis: w_mean() aus mariposa für gewichtete Mittelwerte, Argument weights = wghtpew).

allbus |>
  summarise(
    islam = w_mean(islamophobie_p, weights = wghtpew),
    pop   = w_mean(populismus_p,   weights = wghtpew)
  )
HinweisÜbung 4 · Eigene Skala bauen · Mini-Forschungsfrage

Wähle ein politik-/sozialwissenschaftliches Konstrukt, das dich interessiert (Demokratiezufriedenheit, Vertrauen in Institutionen, Geschlechterrolleneinstellungen, …). Suche mit find_var() mindestens drei passende Items im ALLBUS 2023, prüfe ihre Polung, baue eine Skala mit row_means(min_valid = ...) und beschreibe in 3–4 Sätzen, wie du das Konstrukt operationalisiert hast und welche Items du warum einbezogen oder ausgeschlossen hast.

Es gibt hier keine Musterlösung — die Übung trainiert Operationalisierung, das Kernhandwerk empirischer Sozialforschung.

Hinweis

Forschungsjournal: Stand deiner Mini-Studie. Du hast zwei selbstgebaute Skalen: islamophobie (1–7) und populismus (1–5), beide mit kontrollierter Mindest-Validität und in POMPS-Versionen für direkten Vergleich. Die Skalenbildung ist dein methodischer Schritt — alles, was ab Kapitel 7 folgt, baut darauf auf. Was als Nächstes kommt: Bevor du die Skalen statistisch testest, lernst du in Kapitel 6 die ggplot2-Grammatik — die Werkzeuge, mit denen du Verteilungen und Zusammenhänge sichtbar machst.

Was du jetzt weißt

  • Du transformierst Variablen mit mutate(), case_when(), case_match() und if_else().
  • Du aggregierst Subgruppen mit summarise(.by = ...) und nutzt n()/n_distinct().
  • Du rekodierst Variablen mit rec() — vom einfachen Umkodieren über "dicho"/"quart" bis zum sauberen Umpolen.
  • Du erzeugst Dummy-Variablen mit to_dummy().
  • Du standardisierst und zentrierst Variablen mit std() und center().
  • Du baust gewichtete Mittelwert-Skalen mit row_means() und kontrolliertem min_valid.
  • Du prüfst Antwort-Stile und Datenqualität mit row_count().
  • Du machst Skalen unterschiedlicher Bandbreite mit pomps() direkt vergleichbar.
  • Du kennst die vollständige Datenpräp-Pipeline für die Mini-Studie — sie ist in R/prep.R gekapselt und wird in den folgenden Kapiteln per source() eingebunden.

Im nächsten Kapitel (Kapitel 6) lernst du das ggplot2-Grafiksystem kennen — du brauchst es ab dem Kapitel danach, um Verteilungen, Gruppenvergleiche und Zusammenhänge zu visualisieren.

Weiterführend

  • mariposa-Vignetten „Data Transformation” und „Scale Building”.
  • Hadley Wickham & Garrett Grolemund, R for Data Science (2e), Kapitel „Data Transformation”.
  • Cohen, P., Cohen, J., Aiken, L. S., & West, S. G. (1999). The Problem of Units and the Circumstance for POMP. Multivariate Behavioral Research, 34(3), 315–346 — die theoretische Basis von POMPS.
  • Schulz, A., Müller, P., Schemer, C., Wirz, D. S., Wettstein, M., & Wirth, W. (2017). Measuring populist attitudes on three dimensions. International Journal of Public Opinion Research, 30(2), 316–326 — Quelle der Populismus-Skala.
  • Decker, O., Brähler, E. (Hg.) (2020). Autoritäre Dynamiken. Neue Radikalität — alte Ressentiments. Leipziger Autoritarismus-Studie. — Forschungs­hintergrund zu gruppenbezogener Menschenfeindlichkeit.