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
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.
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.
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:
mutate()) — etwa aus zwei alten Variablen eine abgeleitete Größe ableiten.case_when(), if_else()) — Kategorien neu schneiden („wer < 30 ist, gilt als jung”).rec()) — die zentrale Operation: Werte umkodieren, Kategorien zusammenfassen, umpolen (Reverse Coding).row_means()) — aus mehreren Items einen Mittelwert pro Befragte:n.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.
mutate() erzeugen.case_when(), case_match() und if_else() Bedingungslogik schreiben.summarise(.by = ...) rechnen.rec() rekodieren — vom einfachen Umkodieren über "dicho"/"quart" bis zum Umpolen (Reverse Coding).to_dummy() erzeugen.std()) und zentrieren (center()).row_means() und kontrolliertem min_valid bilden.pomps() auf eine gemeinsame 0–100-Skala bringen.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 |
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))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
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.
.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.
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.
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.
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.
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.
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.
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.
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(...)).
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.
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 α.
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 OstDie 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.
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.
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.
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
----------------------------------------
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.
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.
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?
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
----------------------------------------
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.
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.
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.
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.
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.
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)
)mm-Items (mm02, mm05) zu mm02r/mm05r — Skala 7-stufig.
pa-Items, weil sie 5-stufig invers kodiert sind (1 = stimme zu, 5 = lehne ab) — nach Umpolung gilt hoch = populistisch.
pa-Items — mindestens 6 von 7 müssen valide sein.
Mit dieser Pipeline ist der Datensatz fertig für die Analyse.
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.
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)
)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)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)
)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.
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.
mutate(), case_when(), case_match() und if_else().summarise(.by = ...) und nutzt n()/n_distinct().rec() — vom einfachen Umkodieren über "dicho"/"quart" bis zum sauberen Umpolen.to_dummy().std() und center().row_means() und kontrolliertem min_valid.row_count().pomps() direkt vergleichbar.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.