4  Datenimport und Inspektion

Wer trägt islamfeindliche Einstellungen in Deutschland 2023?

Bevor du diese Frage beantworten kannst, brauchst du den Datensatz auf deinem Rechner — und du musst ihn so weit verstehen, dass du gezielt die richtigen Variablen herausziehen kannst. Dieses Kapitel begleitet dich vom Einlesen der SPSS-Datei über die ersten Inspektionsschritte bis zur sauberen Behandlung fehlender Werte. In Kapitel 5 baust du dann auf diesem Fundament die zwei Skalen der Mini-Studie auf.

Hinweis

Forschungsjournal: Wo stehst du in deiner Mini-Studie? Werkzeug steht (Kap. 1–3). Jetzt beginnt die eigentliche Forschungsarbeit. Mit diesem Kapitel hältst du am Ende einen Analyse-Datensatz in der Hand: 5.246 Befragte, dein eigenes Variablenset, fehlende Werte deklariert. Das ist der Rohzustand, von dem aus alle weiteren Etappen aufbauen.

4.1 Worum es geht

Stell dir vor, du bekommst von einer Kollegin einen USB-Stick mit der Aufschrift „ALLBUS 2023 — viel Spaß”. Du steckst ihn ein und öffnest die Datei. Was du siehst, ist nicht das, was du dir erhofft hast: 579 Spalten mit Namen wie mm01, pa29, pt06, wghtpew. Vier verschiedene negative Zahlen tauchen als „Wert” auf — -9, -11, -42. Manche Variablen sind als Zahl gespeichert, obwohl sie eigentlich eine Kategorie sind (sex = 1 heißt „Mann”). Und die wirklichen Beschriftungen — das, was tatsächlich gefragt wurde — liegen irgendwo versteckt, unsichtbar im Hintergrund.

Genau dieser Zustand ist normal. Sekundärdatensätze aus der quantitativen Sozialforschung sehen immer so aus. Sie sind so gebaut, dass viele Menschen sie für viele unterschiedliche Fragen nutzen können — und das geht nur, wenn die Daten zunächst roh bleiben. Deine Aufgabe ist es, aus diesem Rohzustand einen Analyse-Datensatz zu machen, der zu deiner Forschungsfrage passt.

Diese Schritte sind keine Vorarbeit, die man möglichst schnell hinter sich bringt. Sie sind der methodische Kern jeder ehrlichen Auswertung: Welche Fälle nimmst du raus? Wie behandelst du fehlende Werte? Wie übersetzt du mm01 = 7 in „diese Person lehnt Muslime stark ab”? Jede dieser Entscheidungen beeinflusst, was am Ende rauskommt — und jede gehört in eine Pipeline, die du jederzeit reproduzieren kannst. Das ist offene Wissenschaft im konkreten Handwerk.

Dieses Kapitel ist der Anker für alles, was folgt. Du legst hier den Analyse-Datensatz an, mit dem du in Kapitel 7 Verteilungen beschreibst, in Kapitel 8 Strukturen prüfst und in Kapitel 9 Hypothesen modellierst. Wenn dieser Anker hält, halten alle späteren Befunde.

Was du nach diesem Kapitel kannst

  • Einen SPSS-Datensatz mit read_spss() einlesen — inklusive aller Variablen- und Wertelabels.
  • Variablen über Name oder Label mit find_var() suchen.
  • Detail-Codebooks für ausgewählte Variablen mit codebook() erzeugen.
  • Variablen und Fälle gezielt auswählen, filtern, sortieren und umsortieren (select(), filter(), arrange(), relocate()).
  • Den <haven_labelled>-Datentyp verstehen und ihn bei Bedarf in Faktor oder numerisch konvertieren.
  • Variablenlabels und Wertelabels lesen, auslesen und setzen.
  • Fehlende Werte deklarieren und mit na_frequencies(), set_na() und drop_na() systematisch behandeln.

4.2 Setup

In jeder R-Sitzung lädst du zuerst die Pakete, mit denen du arbeitest. In diesem Buch sind das durchgehend nur zwei:

Tipp

SPSS → R. In SPSS bist du gewohnt, dass alle Funktionen direkt verfügbar sind. In R aktivierst du dir mit library() gezielt die Werkzeuge, die du brauchst — das hält den Funktions-Namensraum übersichtlich und macht jeden Schritt nachvollziehbar.

4.3 Datensatz einlesen

Der ALLBUS 2023 liegt als SPSS-Datei (ALLBUS2023.sav) im Projektordner. Mit read_spss() aus mariposa liest du sie ein:

allbus <- read_spss("ALLBUS2023.sav")

allbus ist jetzt ein Tibble — ein moderner Datentyp im tidyverse. Tibbles verhalten sich wie klassische Data Frames, drucken aber kompakter und behalten ihre Spaltentypen besser. Was wir geladen haben:

allbus
# A tibble: 5,246 × 579
   za_nr          doi   version respid substudy    mode    splt23_1    splt23_2 
   <dbl+lbl>      <chr> <chr>    <dbl> <dbl+lbl>   <dbl+l> <dbl+lbl>   <dbl+lbl>
 1 8831 [ALLBUSc… http… v1.3.0…      1 NA(a) [TNZ… 2 [CAP… NA(a) [TNZ…   2 [SPL…
 2 8831 [ALLBUSc… http… v1.3.0…      2     1 [SIM… 3 [CAW…     1 [SPL… -15 [TNZ…
 3 8831 [ALLBUSc… http… v1.3.0…      3     1 [SIM… 4 [MAI…     1 [SPL… -15 [TNZ…
 4 8831 [ALLBUSc… http… v1.3.0…      4     1 [SIM… 4 [MAI…     1 [SPL… -15 [TNZ…
 5 8831 [ALLBUSc… http… v1.3.0…      5     2 [SEQ… 3 [CAW…     2 [SPL… -15 [TNZ…
 6 8831 [ALLBUSc… http… v1.3.0…      6 NA(a) [TNZ… 2 [CAP… NA(a) [TNZ…   1 [SPL…
 7 8831 [ALLBUSc… http… v1.3.0…      7     1 [SIM… 4 [MAI…     1 [SPL… -15 [TNZ…
 8 8831 [ALLBUSc… http… v1.3.0…      8     1 [SIM… 3 [CAW…     1 [SPL… -15 [TNZ…
 9 8831 [ALLBUSc… http… v1.3.0…      9     2 [SEQ… 3 [CAW…     2 [SPL… -15 [TNZ…
10 8831 [ALLBUSc… http… v1.3.0…     10 NA(a) [TNZ… 2 [CAP… NA(a) [TNZ…   2 [SPL…
# ℹ 5,236 more rows
# ℹ 571 more variables: eastwest <dbl+lbl>, german <dbl+lbl>, ep01 <dbl+lbl>,
#   ep03 <dbl+lbl>, ep04 <dbl+lbl>, ep06 <dbl+lbl>, xr19 <dbl+lbl>,
#   xr20 <dbl+lbl>, lm27 <dbl+lbl>, lm28 <dbl+lbl>, lm29 <dbl+lbl>,
#   lm30 <dbl+lbl>, lm31 <dbl+lbl>, lm32 <dbl+lbl>, lm33 <dbl+lbl>,
#   lm34 <dbl+lbl>, la01 <dbl+lbl>, li01 <dbl+lbl>, li02 <dbl+lbl>,
#   li03 <dbl+lbl>, li04 <dbl+lbl>, li05 <dbl+lbl>, li09 <dbl+lbl>, …

Im Kopf siehst du 5,246 × 579 — der Datensatz hat 5.246 Fälle und 579 Variablen. Darunter eine Auswahl der ersten Spalten mit ihren Datentypen.

Hinweis

Hintergrund: Was passiert beim Einlesen? read_spss() aus mariposa verwendet im Hintergrund das Paket haven und reichert die Daten mit zwei Eigenschaften an, die du aus SPSS kennst: Variablenlabels (eine ausführliche Beschriftung pro Spalte) und Wertelabels (eine Beschriftung pro Ausprägung). Beide Informationen bleiben unsichtbar in den Spalten gespeichert — du kannst sie jederzeit abrufen oder als Faktor sichtbar machen.

Falls du Daten in anderen Formaten brauchst, gibt es passende Geschwister-Funktionen:

read_stata("datei.dta")     # Stata
read_sas("datei.sas7bdat")  # SAS
read_xlsx("datei.xlsx")     # Excel

Und wenn du einen bearbeiteten Datensatz zurück nach SPSS exportieren möchtest:

write_spss(allbus, "allbus_bearbeitet.sav")

4.4 Erster Blick auf den Datensatz

Bei knapp 600 Variablen ist es unmöglich, sich alles in der Konsole anzeigen zu lassen. Drei Werkzeuge helfen dir bei der Orientierung:

glimpse(allbus)           # kompakte Strukturübersicht
nrow(allbus)              # Anzahl Fälle
ncol(allbus)              # Anzahl Variablen

4.4.1 Variablen finden mit find_var()

Die Variablennamen im ALLBUS sind kryptisch (mm01, pa29, wghtpew). Was wirklich gemessen wird, steht im Variablenlabel. mariposas find_var() durchsucht beide gleichzeitig — Name und Label — und liefert dir die Treffer als kleine Übersichtstabelle:

allbus |> find_var("muslim")
  col name                                    label
1 194 mm03 ANWESENHEIT VON MUSLIMEN BRINGT KONFLIKT
2 196 mm05   MUSLIMISCHER BUERGERMEISTER IN ORDNUNG
3 197 mm06 UNTER MUSLIMEN SIND VIELE REL. FANATIKER

Damit findest du die sechs mm-Items für unsere Islamfeindlichkeits-Skala. Standardmäßig wird in Namen und Labels gesucht; mit search = "label" schränkst du auf Labels ein, mit search = "name" auf Namen:

allbus |> find_var("alter", search = "label")
   col    name                                    label
1   93     age                       ALTER: BEFRAGTE(R)
2   94    agec        ALTER: BEFRAGTE(R), KATEGORISIERT
3  265    is01 PERSOENLICH.ALTERSSICHERUNG AUSREICHEND?
4  311   dw12a      BEFR.: ALTER BEI AUFGABE DES BERUFS
5  333   scage         GEGENWAERTIGER EHEPARTNER: ALTER
6  334  scagec   GEGENWAERTIGER EHEPARTNER: ALTER, KAT.
7  367    page                     LEBENSPARTNER: ALTER
8  368   pagec               LEBENSPARTNER: ALTER, KAT.
9  434  hh2age                    2.HAUSH.PERSON: ALTER
10 439  hh3age                    3.HAUSH.PERSON: ALTER
11 444  hh4age                    4.HAUSH.PERSON: ALTER
12 449  hh5age                    5.HAUSH.PERSON: ALTER
13 454  hh6age                    6.HAUSH.PERSON: ALTER
14 459  hh7age                    7.HAUSH.PERSON: ALTER
15 464  hh8age                    8.HAUSH.PERSON: ALTER
16 471    dh17        ALTER JUENGSTES HAUSHALTSMITGLIED
17 480  kh1age               ALTER, 1.KIND, AUSSER HAUS
18 483  kh2age               ALTER, 2.KIND, AUSSER HAUS
19 486  kh3age               ALTER, 3.KIND, AUSSER HAUS
20 489  kh4age               ALTER, 4.KIND, AUSSER HAUS
21 492  kh5age               ALTER, 5.KIND, AUSSER HAUS
22 495  kh6age               ALTER, 6.KIND, AUSSER HAUS
23 498  kh7age               ALTER, 7.KIND, AUSSER HAUS
24 501  kh8age               ALTER, 8.KIND, AUSSER HAUS
25 504  kh9age               ALTER, 9.KIND, AUSSER HAUS
26 507 kh10age              ALTER, 10.KIND, AUSSER HAUS
27 573    xi03                   INTERVIEWER(IN): ALTER
allbus |> find_var("^mm", search = "name")     # regex: alle mm-Items
  col name                                    label
1 170 mm07        FUER DEN BAU VON MOSCHEEN IN BRD?
2 192 mm01 ISLAMAUSUEBUNG IN DEUTSCHL. BESCHRAENKEN
3 193 mm02 ISLAM PASST IN DIE DEUTSCHE GESELLSCHAFT
4 194 mm03 ANWESENHEIT VON MUSLIMEN BRINGT KONFLIKT
5 195 mm04   STAAT SOLLTE ISLAM. GRUPPEN BEOBACHTEN
6 196 mm05   MUSLIMISCHER BUERGERMEISTER IN ORDNUNG
7 197 mm06 UNTER MUSLIMEN SIND VIELE REL. FANATIKER
Tipp

SPSS → R. In SPSS kennst du DISPLAY DICTIONARY für eine Gesamtübersicht. find_var() ist gezielter: du suchst nach einem inhaltlichen Stichwort und bekommst sofort die passenden Variablen — selbst wenn du die kryptischen Namen nicht im Kopf hast.

4.4.2 Detail-Übersicht mit codebook()

Für eine bestimmte Auswahl von Variablen liefert codebook() aus mariposa eine schöne HTML-Übersicht mit Labels, Ausprägungen und Häufigkeiten. Das ist das R-Äquivalent zum SPSS-DISPLAY DICTIONARY:

allbus |>
  codebook(mm01, mm02, mm03, mm04, mm05, mm06)
Tipp

SPSS → R: Dateninspektion. | SPSS | R | | ——————————- | ——————————– | | FREQUENCIES VARIABLES=mm01. | allbus \|> frequency(mm01) | | DESCRIPTIVES VARIABLES=age. | allbus \|> describe(age) | | DISPLAY DICTIONARY. | allbus \|> codebook(...) |

Hinweis

Reviewer-Hinweis. In einer Methodenbeschreibung gehört zu jeder Skala ein Mini-Codebook: Wortlaut der Items, Antwortformat, Missing-Behandlung, N pro Item. Wer das in codebook() als Tabelle generiert und in den Anhang seines Berichts schreibt, hat den Forschungsstandard erfüllt.

4.5 Variablen und Fälle auswählen

Die dplyr-Funktionen select(), filter() und arrange() sind dein tägliches Werkzeug, um aus einem großen Datensatz das herauszuholen, was du gerade brauchst.

4.5.1 Variablen auswählen mit select()

allbus |>
  select(mm01, mm02, mm03)
# A tibble: 5,246 × 3
   mm01                        mm02                        mm03              
   <dbl+lbl>                   <dbl+lbl>                   <dbl+lbl>         
 1     5 [..]                      3 [..]                      4 [..]        
 2 NA(b) [TNZ: SPLIT]          NA(b) [TNZ: SPLIT]          NA(b) [TNZ: SPLIT]
 3 NA(b) [TNZ: SPLIT]          NA(b) [TNZ: SPLIT]          NA(b) [TNZ: SPLIT]
 4 NA(b) [TNZ: SPLIT]          NA(b) [TNZ: SPLIT]          NA(b) [TNZ: SPLIT]
 5     2 [..]                      4 [..]                      4 [..]        
 6     3 [..]                      3 [..]                      3 [..]        
 7 NA(b) [TNZ: SPLIT]          NA(b) [TNZ: SPLIT]          NA(b) [TNZ: SPLIT]
 8 NA(b) [TNZ: SPLIT]          NA(b) [TNZ: SPLIT]          NA(b) [TNZ: SPLIT]
 9     1 [STIMME GAR NICHT ZU]     6 [..]                      2 [..]        
10     7 [STIMME VOLL+GANZ ZU]     1 [STIMME GAR NICHT ZU]     3 [..]        
# ℹ 5,236 more rows

Du kannst Bereiche mit : angeben und Variablen mit - ausschließen:

allbus |>
  select(mm01:mm06, eastwest, sex, age, educ)
# A tibble: 5,246 × 10
   mm01              mm02        mm03        mm04        mm05        mm06       
   <dbl+lbl>         <dbl+lbl>   <dbl+lbl>   <dbl+lbl>   <dbl+lbl>   <dbl+lbl>  
 1     5 [..]            3 [..]      4 [..]      2 [..]      6 [..]      2 [..] 
 2 NA(b) [TNZ: SPLI… NA(b) [TNZ… NA(b) [TNZ… NA(b) [TNZ… NA(a) [TNZ… NA(a) [TNZ…
 3 NA(b) [TNZ: SPLI… NA(b) [TNZ… NA(b) [TNZ… NA(b) [TNZ… NA(a) [TNZ… NA(a) [TNZ…
 4 NA(b) [TNZ: SPLI… NA(b) [TNZ… NA(b) [TNZ… NA(b) [TNZ… NA(a) [TNZ… NA(a) [TNZ…
 5     2 [..]            4 [..]      4 [..]      3 [..]      3 [..]      6 [..] 
 6     3 [..]            3 [..]      3 [..]      7 [STI…     6 [..]      3 [..] 
 7 NA(b) [TNZ: SPLI… NA(b) [TNZ… NA(b) [TNZ… NA(b) [TNZ… NA(a) [TNZ… NA(a) [TNZ…
 8 NA(b) [TNZ: SPLI… NA(b) [TNZ… NA(b) [TNZ… NA(b) [TNZ… NA(a) [TNZ… NA(a) [TNZ…
 9     1 [STIMME GA…     6 [..]      2 [..]      1 [STI…     7 [STI…     2 [..] 
10     7 [STIMME VO…     1 [STI…     3 [..]      6 [..]      1 [STI…     7 [STI…
# ℹ 5,236 more rows
# ℹ 4 more variables: eastwest <dbl+lbl>, sex <dbl+lbl>, age <dbl+lbl>,
#   educ <dbl+lbl>

Diese Auswahl — die sechs Skalen-Items plus Demografie — ist genau das, was du für die Mini-Studie brauchst.

Zwei nahe Verwandte von select():

  • pull(var) zieht eine einzelne Spalte als reinen Vektor heraus — nützlich, wenn du den Spalteninhalt direkt in eine Funktion füttern willst, die kein Tibble erwartet: allbus |> pull(age) |> mean(na.rm = TRUE).
  • relocate(var, .before = X, .after = Y) sortiert Spalten um, ohne welche zu entfernen — praktisch, wenn die wichtigsten Variablen vorne stehen sollen: allbus |> relocate(islamophobie, populismus, .before = sex).

4.5.2 Fälle filtern mit filter()

allbus |>
  filter(sex == 2) |>
  select(sex, age, educ)
# A tibble: 2,672 × 3
   sex       age       educ                  
   <dbl+lbl> <dbl+lbl> <dbl+lbl>             
 1 2 [FRAU]  69        4 [FACHHOCHSCHULREIFE]
 2 2 [FRAU]  18        5 [HOCHSCHULREIFE]    
 3 2 [FRAU]  45        5 [HOCHSCHULREIFE]    
 4 2 [FRAU]  26        3 [MITTLERE REIFE]    
 5 2 [FRAU]  71        2 [VOLKS-,HAUPTSCHULE]
 6 2 [FRAU]  66        2 [VOLKS-,HAUPTSCHULE]
 7 2 [FRAU]  39        3 [MITTLERE REIFE]    
 8 2 [FRAU]  51        3 [MITTLERE REIFE]    
 9 2 [FRAU]  29        5 [HOCHSCHULREIFE]    
10 2 [FRAU]  60        4 [FACHHOCHSCHULREIFE]
# ℹ 2,662 more rows

Die Vergleichs- und Logik-Operatoren aus Kapitel 3.4 (==, !=, <, >, &, |, %in%) bilden hier dein Vokabular. Komplexere Filter kombinierst du frei:

allbus |>
  filter(eastwest == 2 & age >= 30 & age <= 60) |>
  select(eastwest, age, educ) |>
  nrow()
[1] 825
Warnung

Vorsicht: Fehlende Werte. filter() schließt Fälle mit NA in der Bedingung automatisch aus. Das ist meist gewünscht, kann dich aber überraschen. Mit filter(is.na(variable)) filterst du gezielt fehlende Werte heraus.

4.5.3 Fälle sortieren mit arrange()

allbus |>
  select(age, educ) |>
  arrange(age) |>
  head(5)
# A tibble: 5 × 2
  age       educ                  
  <dbl+lbl> <dbl+lbl>             
1 18        5 [HOCHSCHULREIFE]    
2 18        5 [HOCHSCHULREIFE]    
3 18        3 [MITTLERE REIFE]    
4 18        1 [OHNE ABSCHLUSS]    
5 18        2 [VOLKS-,HAUPTSCHULE]

Absteigend mit desc():

allbus |>
  select(age, educ) |>
  arrange(desc(age)) |>
  head(5)
# A tibble: 5 × 2
  age       educ                  
  <dbl+lbl> <dbl+lbl>             
1 99        2 [VOLKS-,HAUPTSCHULE]
2 97        5 [HOCHSCHULREIFE]    
3 97        5 [HOCHSCHULREIFE]    
4 94        2 [VOLKS-,HAUPTSCHULE]
5 94        4 [FACHHOCHSCHULREIFE]

4.6 Datentypen verstehen

Wenn du in SPSS arbeitest, fragst du dich selten, welcher Typ eine Variable ist. SPSS macht das im Hintergrund: eine Variable ist „numerisch” oder „string”, und Wertelabels („1 = Mann, 2 = Frau”) sind nur eine Beschriftungs-Schicht obendrauf. In R ist das ein bisschen anders — und am Anfang verwirrend.

R kennt eine ganze Reihe von Datentypen: reine Zahlen (numeric), Text (character), Logik (logical), Kategorien mit fester Reihenfolge (factor). Beim Einlesen eines SPSS-Datensatzes kommt noch ein vierter Typ hinzu, den mariposa von haven übernimmt: <haven_labelled>. Das ist eine Art Hybrid: Die Spalte verhält sich nach außen wie eine Zahl, aber im Hintergrund tragen die Werte ihre SPSS-Wertelabels mit. So bleibt die Information „1 bedeutet Mann” erhalten, ohne dass du sie aus dem Codebook nachschlagen musst.

Mit class() siehst du den Typ einer Variable:

class(allbus$sex)
[1] "haven_labelled" "vctrs_vctr"     "double"        
class(allbus$age)
[1] "haven_labelled" "vctrs_vctr"     "double"        

Drei Konvertierungen wirst du immer wieder brauchen:

Funktion Wirkung
to_label(data, var) wandelt <haven_labelled> in einen Faktor mit den Wertelabels als Stufen — Standard, wenn du in ggplot()-Achsen lesbare Beschriftungen willst
to_numeric(data, var) wandelt in einen reinen numerischen Vektor — Labels gehen verloren
to_labelled(data, var, labels = ...) wandelt umgekehrt einen Faktor zurück in ein <haven_labelled>
allbus |>
  to_label(sex, eastwest) |>
  select(sex, eastwest) |>
  head(3)
# A tibble: 3 × 2
  sex   eastwest          
  <fct> <fct>             
1 MANN  ALTE BUNDESLAENDER
2 MANN  ALTE BUNDESLAENDER
3 FRAU  ALTE BUNDESLAENDER

Wenn du nur Labels abstreifen willst (z. B. weil eine Funktion mit labelled-Vektoren nicht klarkommt), nimmst du unlabel(): allbus |> unlabel(sex, age). Selten gebraucht, aber gut zu wissen, wenn ein fremdes Paket sich quer stellt.

Hinweis

Hintergrund: Warum nicht einfach Faktor? In SPSS sind Variablen entweder numerisch oder string. Wertelabels sind ein Zusatz. In R gibt es Faktoren (Kategorien) und numerische Vektoren als getrennte Typen. <haven_labelled> ist eine Brücke: Du arbeitest mit Zahlen, aber die Wertelabels reisen mit. Wann du das auflösen solltest:

  • to_label() wenn du sortierst, gruppierst, kreuztabellierst oder plottest — Faktoren liefern lesbare Outputs.
  • to_numeric() wenn du rechnest oder skalierst — z. B. bei Likert-Items, die du als pseudo-metrisch behandelst.
  • Beim Original lassen, wenn die Variable noch nicht final ist und du das Label später noch brauchst.

4.7 Variablen- und Wertelabels lesen und setzen

Funktion Wirkung
var_label(data) Variablenlabels auslesen
var_label(data) <- list(var = "Neue Beschriftung") Variablenlabel setzen
val_labels(data) Wertelabels auslesen
drop_labels(data) Alle Wertelabels entfernen, deren Ausprägung in den Daten gar nicht vorkommt
allbus |>
  select(mm01, mm02, mm03) |>
  var_label()
                                      mm01 
"ISLAMAUSUEBUNG IN DEUTSCHL. BESCHRAENKEN" 
                                      mm02 
"ISLAM PASST IN DIE DEUTSCHE GESELLSCHAFT" 
                                      mm03 
"ANWESENHEIT VON MUSLIMEN BRINGT KONFLIKT" 

Das Ergebnis ist ein benannter Character-Vektor — pro Variable das hinterlegte Label. So liest du, was eine kryptische Variable wie mm01 eigentlich bedeutet, ohne ins Codebook zu schauen.

4.8 Fehlende Werte deklarieren

Fehlende Werte sind in der Sozialforschung Normalität, nicht Ausnahme. Niemand beantwortet jede Frage einer Umfrage — manche überspringen einzelne Punkte, manche wissen es schlicht nicht, manche bekommen wegen eines Split-Designs bestimmte Fragen gar nicht vorgelegt. Und manche Antworten waren ursprünglich da, gingen aber durch einen Datenfehler verloren.

Die GESIS unterscheidet in ALLBUS deshalb vier Arten von fehlenden Werten und kodiert sie mit klar unterscheidbaren negativen Zahlen:

Code Bedeutung
-42 DATENFEHLER
-11 TNZ (trifft nicht zu / Split-Modul)
-9 KEINE ANGABE
-8 WEISS NICHT

Die Unterscheidung ist inhaltlich wichtig: ein „weiß nicht” ist methodisch etwas anderes als eine verweigerte Antwort, und ein „trifft nicht zu” (jemand hat die Frage gar nicht gestellt bekommen) ist wiederum etwas anderes als ein echter Datenfehler. Wenn du diese Codes als reguläre Zahlen behandelst — was passiert, wenn du sie einfach in einen Mittelwert wirfst — sind deine Ergebnisse Müll: ein „Durchschnittswert” von -3.4 für Lebenszufriedenheit ist offensichtlich Unsinn.

Beim Einlesen werden diese in SPSS als user-missing deklarierten Codes automatisch zu tagged NAs. „Tagged” heißt: sie zählen in Berechnungen als NA (also fehlend), behalten aber im Hintergrund die Information, welcher Missing-Typ sie sind. Du kannst sie also später trotzdem voneinander unterscheiden — etwa um zu zeigen, wie viele Personen „weiß nicht” gewählt haben.

Hinweis

Hintergrund: Split-Designs im ALLBUS. Manche Itembatterien werden nur einer Hälfte der Stichprobe gestellt (Code -11 für die andere Hälfte). Das gilt insbesondere für die mm-Items unserer Islamfeindlichkeits-Skala. Die effektive N für solche Splits liegt deshalb bei rund 2.500 statt 5.246 — methodisch kein Fehler, sondern Stichproben­architektur. In der Methodenbeschreibung gehört dieser Punkt erwähnt.

Wie viele Fälle pro Missing-Code in einer konkreten Variable stecken, zeigt dir na_frequencies():

na_frequencies(allbus$mm01)
   tag    n code            label
1    b 1647  -11       TNZ: SPLIT
2    d  123   -8      WEISS NICHT
3    c   73   -9     KEINE ANGABE
4    a    2  -42 DATENFEHLER: MFN
5 <NA>    0 <NA> (System Missing)

Du siehst die Aufschlüsselung: wie viele „weiß nicht”, wie viele „keine Angabe”, wie viele „trifft nicht zu” — alles in einem Aufruf. Praktisch, bevor du entscheidest, ob du bestimmte Codes als reguläre Werte behältst oder als endgültige Missings behandelst.

Wenn du eine Variable hast, in der bestimmte Werte erst nachträglich als fehlend gelten sollen — etwa Altersangaben über 100 als unplausibel —, deklarierst du sie mit set_na():

allbus |>
  set_na(age, na_values = c(-9, -8), verbose = TRUE)

Mit verbose = TRUE zeigt mariposa dir an, wie viele Fälle pro Wert zu NA wurden — kontrolliert und nachvollziehbar.

Mit drop_na() (aus tidyr) entfernst du Fälle mit NA:

allbus |>
  select(mm01, mm02, mm03) |>
  drop_na() |>
  nrow()
[1] 3285
Warnung

Vorsicht: Listenweiser Ausschluss. drop_na() schließt Fälle aus, sobald eine der ausgewählten Variablen NA ist. Das ist klassischer listwise deletion. Wenn du in einer großen Pipeline mit vielen Variablen drop_na() rufst, kann deine Fallzahl drastisch schrumpfen. Setze drop_na() deshalb gezielt auf die Variablen, die du wirklich brauchst.

Hinweis

Hintergrund: MCAR, MAR, MNAR. Die Methodenliteratur unterscheidet drei Missing-Mechanismen: Missing Completely at Random (Zufall, keine Verzerrung), Missing at Random (Zufall bedingt durch beobachtete Variablen, durch Modellierung korrigierbar) und Missing Not at Random (systematisch, schwer zu beheben). In Survey-Daten wie ALLBUS ist MAR der Regelfall; einfache Listwise Deletion (drop_na()) ist dann ein konservativer, aber transparenter Umgang. Imputationsverfahren (z. B. mice) sind die nächste Ausbaustufe — für ein Einsteigerbuch jedoch zu viel.

Übungen

HinweisÜbung 1 · Variablen finden · Reproduktion

Du willst eine Skala zu Vertrauen in Institutionen bauen, kennst aber die Variablennamen nicht auswendig. Nutze find_var(), um (a) alle Variablen mit „vertrau” im Label und (b) alle Variablen mit st am Namensanfang zu finden.

allbus |> find_var("vertrau", search = "label")
allbus |> find_var("^st", search = "name")
HinweisÜbung 2 · Codebook der politischen Vertrauens-Items · Reproduktion

Erstelle ein codebook() für die Items pt01 bis pt08 (Vertrauen in verschiedene Institutionen). Schau dir Labels und Wertelabels an.

allbus |>
  codebook(pt01, pt02, pt03, pt04, pt05, pt06, pt07, pt08)
HinweisÜbung 3 · Analyse-Subset bilden · Transfer

Erstelle einen Datensatz analyse, der nur die für die Mini-Studie nötigen Variablen enthält (mm01:mm06, pa29:pa35, eastwest, sex, age, educ, wghtpew) und nur Fälle, in denen mindestens fünf der sechs mm-Items gültig sind. Tipp: rowSums(!is.na(across(mm01:mm06))) >= 5 als Filterkriterium.

analyse <- allbus |>
  select(mm01:mm06, pa29:pa35, eastwest, sex, age, educ, wghtpew) |>
  filter(rowSums(!is.na(across(mm01:mm06))) >= 5)
nrow(analyse)
HinweisÜbung 4 · Eigene Forschungsfrage · Mini-Forschungsfrage

Wähle ein Thema, das dich politik- oder sozialwissenschaftlich interessiert (Migration, Klima, Geschlechterrollen, …). Finde mit find_var() zwei bis drei Variablen im ALLBUS 2023, die deine Frage beleuchten könnten. Erstelle ein codebook() für deine Auswahl. Beschreibe in 2–3 Sätzen, was du untersuchen würdest und welche Variable als unabhängige bzw. abhängige Variable dienen könnte.

Es gibt hier keine Musterlösung — die Übung trainiert das Auffinden und Verstehen von Variablen, nicht eine bestimmte Antwort.

Hinweis

Forschungsjournal: Stand deiner Mini-Studie. Du hast den ALLBUS 2023 eingelesen und hast die Werkzeuge, um durch 579 Variablen gezielt zu navigieren. Du weißt, was hinter mm01 bis mm06 steckt (die sechs Islamfeindlichkeits-Items), du kennst die Missing-Codes der GESIS, und du kannst dein Analyse-Subset gezielt zusammenstellen. Was als Nächstes kommt: In Kapitel 5 wandelst du die Rohitems in zwei Skalen um — Islamfeindlichkeit und Populismus.

Was du jetzt weißt

  • Du liest SPSS-Daten mit read_spss() ein und behältst Variablen- und Wertelabels.
  • Du findest Variablen über Name oder Label mit find_var() und holst dir Detail-Codebooks per codebook().
  • Du wählst Variablen und Fälle mit select(), filter(), arrange() aus — und sortierst sie mit relocate() um.
  • Du verstehst den <haven_labelled>-Typ und wandelst ihn bei Bedarf in Faktor oder numerisch.
  • Du liest und setzt Variablen- und Wertelabels mit var_label() und val_labels().
  • Du erkennst die ALLBUS-Missing-Codes, prüfst sie mit na_frequencies() und schließt Fälle gezielt aus.

Im nächsten Kapitel (Kapitel 5) lernst du, wie du aus diesen Rohvariablen die zwei Skalen baust, die die Mini-Studie trägt — Islamfeindlichkeit und Populismus.

Weiterführend