1. Startseite
  2. Tools
  3. Forschungstools
  4. Datenaufbereitung mehrwelliger Befragungsdaten aus SoSci Survey
  1. Startseite
  2. Tools
  3. Umfragetools
  4. Datenaufbereitung mehrwelliger Befragungsdaten aus SoSci Survey
  1. Startseite
  2. Tools
  3. Datenaufbereitung mehrwelliger Befragungsdaten aus SoSci Survey

Datenaufbereitung mehrwelliger Befragungsdaten aus SoSci Survey

Hinweis: Dieser Beitrag knüpft an den vorangegangenen Artikel Erhebungsdesigns mit mehreren Messzeitpunkten in SoSci Survey umsetzen an. Dort wird gezeigt, wie die hier verwendete Beispielstudie aufgebaut ist: mit Registrierung über eine Opt-in-Frage, Serienmailversand und zwei Erhebungswellen. Wer nachvollziehen möchte, wie der hier aufbereitete Datensatz zustande kommt, sollte zunächst jenen Teil lesen. Die vorliegende Anleitung setzt dort an, wo der fertige Datenexport vorliegt.

Der größte Teil der Arbeit mit Befragungsdaten entfällt auf die Aufbereitung, nicht auf die Auswertung – häufig genannt wird ein Anteil von rund 70 Prozent. Die folgenden Schritte zeigen eine mögliche Abfolge für mehrwellige Befragungen. Je nach Fragebogenaufbau, Erhebungsweg und Auswertungsziel können Schritte entfallen, hinzukommen oder anders aussehen. Kontrollieren Sie nach jedem Schritt das Zwischenergebnis.

Ausgangslage der Beispielstudie und Datenstruktur

Der Datenexport der im ersten Teil beschriebenen Beispielstudie aus SoSci Survey enthält alle Fragebögen einer mehrwelligen Studie in einer gemeinsamen Datei. Die Variable QUESTNNR gibt für jede Zeile an, welcher Fragebogen beantwortet wurde. Eine Person, die an drei Befragungen teilgenommen hat, erscheint daher in drei Zeilen. Die Teilnehmenden-Kennung liegt in den Wellen, die über einen personalisierten Link durchgeführt wurden, als SERIAL vor. Da Registrierung über eine Opt-in-Frage erfolgte, steht dieselbe Kennung in der ersten Welle stattdessen in der Variable dieser Frage (beispielsweise R001) und muss vor der Zusammenführung nach SERIAL übertragen werden.

Da jeder Fragebogen eigene Rubrik-Kennungen verwendet, tragen inhaltlich identische Fragen in den verschiedenen Wellen unterschiedliche Variablennamen (etwa AD01 in t1 und BD01 in t2 für dieselbe Frage). Für eine Zeile eines bestimmten Messzeitpunkts sind deshalb alle Spalten der übrigen Wellen leer.

Ein Ausschnitt aus einem solchen Export könnte so aussehen:

SERIALQUESTNNRR001AD01_01BD01_01
(leer)t0abc123NANA
abc123t1NA3NA
xyz789t1NA2NA
abc123t2NANA5
xyz789t2NANA3
[Tab. 1 Rohadaten aus SoSci (Beispiel)]

Dieser Rohexport ist weder ein Wide- noch ein Long-Format. Im Wide-Format steht jede Person in genau einer Zeile. Im Long-Format hat jede Person je Messzeitpunkt eine eigene Zeile, jede messwiederholte Variable steht in genau einer Spalte, und eine zusätzliche Spalte gibt den Messzeitpunkt an. Beide Formate müssen aus dem Rohexport erst erzeugt werden.

Welche Datenwerte speichert SoSci Survey?

Neben der Struktur ist die Kodierung der Antworten zu beachten. Einige Eigenheiten wirken sich unmittelbar auf die Aufbereitung aus und führen sonst zu Ergebnissen, die plausibel aussehen, aber falsch sind. Gültige Antworten tragen stets einen positiven Wert. Diese Kodierung lässt sich nicht ändern, damit keine Überschneidung mit den Codes für fehlende Werte entsteht.

Bei Skalen erzeugt das Minimum den Wert 1, das Maximum den Wert n. Die angezeigte Beschriftung spielt keine Rolle: Wird die Skala von −2 bis +2 nummeriert oder das Minimum als Schulnote 6 beschriftet, wird trotzdem 1 gespeichert. Für das Umpolen ist deshalb die Zahl der Stufen maßgeblich, nicht die Beschriftung – bei sieben Stufen lautet die Formel 8 – x, bei fünf Stufen 6 – x.

Bei Einfachauswahl wird die Kennung der gewählten Option gespeichert, also 1 bis m. Bei Mehrfachauswahl wird jedes Item zu einer eigenen Variable mit den Werten 1 für nicht angekreuzt und 2 für angekreuzt. Daneben gibt es eine Sammelvariable ohne Item-Nummer, die die Anzahl der gewählten Optionen enthält – sie ist keine Antwortvariable und gehört nicht in die Umkodierung.

Für fehlende Werte sind vier Fälle zu unterscheiden, von denen nur die ersten beiden fehlende Werte im eigentlichen Sinn sind:

WertBedeutung
−9Die Frage wurde gestellt, aber nicht beantwortet
−8Eine ungültige Antwort wurde übermittelt
−1 bis −3Eine Ausweich- oder Residualoption wurde gewählt
leeres FeldDie Frage wurde im Interview nicht gestellt
[Tab. 2 Fehlende Werte in SoSci]

Die Codes −1 bis −3 stehen für inhaltliche Antworten, etwa „Nichts davon“ oder „Darüber habe ich noch nie nachgedacht“. Wer pauschal alle negativen Werte in fehlende Werte umwandelt, löscht diese Angaben.

Hinzu kommen technische Variablen, die SoSci Survey in jedem Fragebogen mitliefert. Für die Prüfung der Datenqualität sind vor allem FINISHED, LASTPAGE, MISSING, MISSREL, TIME_SUM und TIME_RSI nützlich. Da sie in allen Wellen gleich heißen, führen sie beim Zusammenführen zu Namenskollisionen und werden vorher aus dem Arbeitsdatensatz genommen.

Für die Aufbereitung braucht man beide Dokumente, denn sie beantworten unterschiedliche Fragen.

Das Codebuch führt je Variable und Antwortoption eine Zeile mit sechs Spalten: Kennung, Fragetitel, gespeicherter Zahlenwert, dessen Bedeutung, Skalenniveau und Fragetyp. Daraus lässt sich klären, welche Variablen zu einer Mehrfachauswahl gehören (Typ DICHOTOMOUS beziehungsweise CK), welche negativen Codes vorkommen und was sie bedeuten, und wie viele Stufen eine Skala hat. Ein Detail wird dabei leicht übersehen: Bei zweistufigen Fragen ist die Richtung der Kodierung nicht einheitlich. Mal gilt 1 = nein, 2 = ja, mal 1 = Ja, 2 = Nein. Eine pauschale Umkodierung mit x – 1 kehrt im zweiten Fall die Bedeutung um.

Das Codebuch gilt für das gesamte Projekt und enthält keine Spalte für den Fragebogen. Aus ihm ist deshalb nicht ersichtlich, welche Kennung zu welcher Erhebungswelle gehört.

Diese Information liefert die Variablenübersicht, die je Fragebogen abgerufen wird. Legt man die Übersichten mehrerer Wellen nebeneinander, lässt sich am identischen Fragetitel ablesen, welche Kennungen einander entsprechen. Genau diese Gegenüberstellung braucht man später für das Umbenennen der Spalten.

Welche Schritte sind erforderlich?

Der Umfang der Aufbereitung hängt davon ab, mit welchem Programm und mit welchem Verfahren ausgewertet werden soll. Hier wird die Aufbereitung bis zur Varianzanalyse mit Messwiederholung in R dargestellt.

Auswertung in SPSS. Deskriptive Statistik, t-Test und Varianzanalyse mit Messwiederholung benötigen in SPSS das Wide-Format. Da der Rohexport mehrere Zeilen je Person enthält, muss auch hier zunächst umstrukturiert werden. Grundlage dafür ist der gemeinsame Datensatz, den SoSci Survey für das gesamte Projekt exportiert; die Zeilen einer Person werden über SERIAL zusammengeführt, QUESTNNR. gibt die Welle an. Das Vorgehen dafür ist in der SPSS-Dokumentation unter „Daten umstrukturieren“ beschrieben.

Deskriptive Statistik und t-Test in R. siehe Teil 1.

Varianzanalyse mit Messwiederholung in R. Die in Luhmann Kapitel 14 verwendete Funktion aov_car() aus dem Paket afex setzt das Long-Format voraus.

Rücklauf oder Studienabbrüche berichten. Dafür ist ein eigener Zwischenschritt sinnvoll, der unabhängig von der eigentlichen Auswertung ist (siehe Teil 3).

Grundlage ist der CSV-Export aus SoSci Survey. Dieser ist tabgetrennt, weshalb als Trennzeichen "\t" angegeben wird. Anzupassen sind der Dateipfad und die Kennungen der eigenen Fragen; die Beispielkennungen AD03_01 und EM03_01 sind durch die eigenen zu ersetzen.

Zunächst werden die benötigten Pakete geladen. Die Installation ist nur einmal erforderlich, das Laden dagegen in jeder neuen R-Sitzung.

install.packages(c("readr", "dplyr", "tidyr"))

library(readr)
library(dplyr)
library(tidyr)

# Datensatz importieren
pfad <- "pfad/zur/datei.csv"
daten <- read_delim(pfad, delim = "\t", escape_double = FALSE,
                    na = "NA", trim_ws = TRUE)

# Erster Blick auf Umfang und Wertebereiche
nrow(daten)
summary(daten)

Fehlende Werte kennzeichnen

Beim CSV-Export bleiben die Codes für fehlende Werte als gewöhnliche Zahlen stehen. R erkennt sie nicht als fehlend und rechnet sie in alles ein: Aus -9 würde beim Umkodieren -10, beim Umpolen 15, und in den Skalenwert wird ein negativer Wert mitgezählt. Eine Fehlermeldung erscheint dabei nicht. Der Schritt gehört deshalb an den Anfang, vor alle weiteren Umformungen. Da in der Regel viele Variablen betroffen sind, werden deren Kennungen zunächst in einer Liste gesammelt und anschließend gemeinsam behandelt.

## Fehlende Werte kennzeichnen

# Kennungen der betroffenen Variablen sammeln
item_spalten <- c("AD03_01", "AD03_02", "EM03_01", "EM03_02")
daten <- daten %>%
  mutate(across(all_of(item_spalten), ~ na_if(.x, -9)))

# Kontrolle: Anzahl fehlender Werte
sum(is.na(daten$EM03_01))

Ausweichoptionen mit den Codes -1 bis -3 bleiben dabei erhalten. Ob sie als fehlende Werte gelten sollen, ist eine inhaltliche Entscheidung und je Frage unterschiedlich zu beantworten. Z.B. „keine, ich bin staatenlos“, „darüber habe ich noch nie nachgedacht“. Sollen einzelne davon ebenfalls fehlend werden, geschieht das gezielt für die betroffene Variable: z.B.: daten$RW01_01 <- na_if(daten$RW01_01, -1).

Antwortwerte umkodieren

Mehrfachauswahl und zweistufige Fragen sind mit 1 und 2 kodiert. Für Anteilswerte ist eine Kodierung mit 0 und 1 sinnvoll, weil der Mittelwert dann unmittelbar dem Anteil der Zustimmung entspricht. Häufigkeitsauszählungen mit table() funktionieren unabhängig davon. Die umkodierten Werte kommen in neue Variablen mit dem Zusatz r, damit die ursprünglichen erhalten bleiben und nachvollziehbar ist, was bereits behandelt wurde. - 1 setzt voraus, dass der zweite Code die zutreffende Antwort ist. Gilt umgekehrt 1 = Ja, 2 = Nein, kehrt diese Rechnung die Bedeutung um. In dem Fall lautet der Befehl daten$LP01r <- 2 - daten$LP01. Welche Reihenfolge gilt, steht im Codebuch in der Spalte Response Label.

## Antworten umkodiederen

# Mehrfachauswahl: 1 = nicht gewaehlt, 2 = gewaehlt
daten$AD03_01r <- daten$AD03_01 - 1

# Zweistufige Frage: 1 = nein, 2 = ja
daten$EM03_01r <- daten$EM03_01 - 1

# Umkodierung prüfen
table(daten$EM03_01, daten$EM03_01r)

**Achtung:** `- 1` setzt voraus, dass der zweite Code die zutreffende Antwort ist. Gilt umgekehrt 1 = Ja, 2 = Nein, kehrt diese Rechnung die Bedeutung um. In dem Fall lautet der Befehl daten$LP01r <- 2 - daten$LP01. Welche Reihenfolge gilt, steht im Codebuch in der Spalte *Response Label*.

Nach Messzeitpunkt aufteilen

Die Variable QUESTNNR gibt an, aus welchem Fragebogen eine Zeile stammt. Da auch das Basispaket stats eine Funktion namens filter enthält, wird dplyr:: vorangestellt.

## Nach Messzeitpunkt aufteilen

daten_t0 <- daten %>% dplyr::filter(QUESTNNR == "t0")
daten_t1 <- daten %>% dplyr::filter(QUESTNNR == "t1")
daten_t2 <- daten %>% dplyr::filter(QUESTNNR == "t2")

ID-Variable angleichen

## ID-Variable angleichen

daten_t0$SERIAL <- ifelse(is.na(daten_t0$SERIAL) | daten_t0$SERIAL == "",
                   daten_t0$R001, daten_t0$SERIAL)

daten_t0$SERIAL <- trimws(as.character(daten_t0$SERIAL))
daten_t1$SERIAL <- trimws(as.character(daten_t1$SERIAL))
daten_t2$SERIAL <- trimws(as.character(daten_t2$SERIAL))

Duplikate prüfen

Kommt eine Kennung innerhalb einer Welle mehrfach vor, vervielfacht das Zusammenführen die betroffenen Fälle ohne Warnung. Alle drei Befehle müssen den Wert 0 ergeben.

## Duplikate prüfen

sum(duplicated(daten_t0$SERIAL))
sum(duplicated(daten_t1$SERIAL))
sum(duplicated(daten_t2$SERIAL))

Technische Variablen sichern und entfernen

Die technischen Variablen heißen in allen Wellen gleich und führen beim Zusammenführen zu Namenskollisionen. Verworfen werden sollten sie trotzdem nicht, da sie für eine Qualitäts- oder Abbruchprüfung nützlich sind. Sie kommen deshalb zunächst in eigene Datensätze und werden danach aus den Arbeitsdatensätzen entfernt.

# Namen der technischen Variablen im Codebook erhalten

meta <- c("MODE", "MAILSENT", "LASTPAGE", "STARTED", "FINISHED",
          "Q_VIEWER", "MAXPAGE", "MISSING", "MISSREL", "STATUS", "QUESTNNR")

# In eigene Datensaetze sichern
meta_t1 <- daten_t1 %>% select(SERIAL, starts_with("TIME"), any_of(meta))
meta_t2 <- daten_t2 %>% select(SERIAL, starts_with("TIME"), any_of(meta))

# Aus den Arbeitsdatensaetzen entfernen
daten_t1 <- daten_t1 %>% select(-starts_with("TIME"), -any_of(meta))
daten_t2 <- daten_t2 %>% select(-starts_with("TIME"), -any_of(meta))
intersect(names(daten_t1), names(daten_t2))

# Außer `SERIAL` sollte hier nichts mehr erscheinen.

Zusammenführen zum Wide-Format

full_join() behält alle Personen aus beiden Datensätzen, auch solche, die nur an einer Welle teilgenommen haben. Sollen nur vollständige Fälle bleiben, wäre inner_join() zu verwenden.

## Zusammenführen zum Wide-Format

daten_wide <- daten_t1 %>%
  full_join(daten_t2, by = "SERIAL")

# Stichprobengroesse pruefen
nrow(daten_t1)
nrow(daten_t2)
nrow(daten_wide)

Bei drei inhaltlichen Wellen wird eine weitere Zeile angefügt: full_join(daten_t0, by = "SERIAL". Damit liegen die Daten im Wide-Format vor: eine Zeile pro Person, der Messzeitpunkt ist in den Variablennamen enthalten.

Spalten einheitlich benennen

Die Spalten tragen an dieser Stelle noch die Kennungen aus SoSci Survey. Daran ist weder erkennbar, welches Konstrukt gemeint ist, noch aus welcher Welle der Wert stammt. Für die deskriptive Statistik und den t-Test wird der Datensatz durch sprechende Namen deutlich übersichtlicher, und für eine spätere Umstrukturierung ins Long-Format sind sie Voraussetzung.

Welche Kennung in welcher Welle zu welcher Frage gehört, ist der Variablenübersicht des jeweiligen Fragebogens zu entnehmen; das Codebuch enthält diese Zuordnung nicht.

Die neuen Namen folgen dem Muster kompetenz_01_t1, also Konstruktname, Itemnummer und Messzeitpunkt, jeweils durch einen Unterstrich getrennt. Entscheidend ist, dass der Messzeitpunkt am Ende steht.

Bei rename() steht links der neue Name, rechts der bisherige. Alle Variablen, die nicht aufgeführt werden, behalten ihren Namen. Wurden Items zuvor umkodiert, müssen die Variablen mit dem Zusatz r genutzt werden.

## Variablen/Spalten einheitlich benennen

daten_wide <- daten_wide %>%
  rename(kompetenz_01_t1 = AD01_01,
         kompetenz_02_t1 = AD01_02,
         kompetenz_03_t1 = AD01_03,
         kompetenz_01_t2 = BD01_01,
         kompetenz_02_t2 = BD01_02,
         kompetenz_03_t2 = BD01_03)

# Kontrolle
names(daten_wide)  

Items umpolen

Negativ formulierte Items werden umgepolt, damit hohe Werte durchgehend eine hohe Merkmalsausprägung bedeuten. Dazu wird jeder Wert vom theoretischen Maximum plus 1 abgezogen – bei einer fünfstufigen Skala also von 6, bei einer siebenstufigen von 8. Gemeint ist der theoretisch mögliche Höchstwert, unabhängig davon, ob er in den Daten vorkommt.

Auch hier entsteht eine neue Variable mit dem Zusatz r. Im Wide-Format ist das je Messzeitpunkt einzeln vorzunehmen.

## Items umpolen

daten_wide$kompetenz_02r_t1 <- 6 - daten_wide$kompetenz_02_t1
daten_wide$kompetenz_02r_t2 <- 6 - daten_wide$kompetenz_02_t2

# Umpolung prüfen
table(daten_wide$kompetenz_02_t1, daten_wide$kompetenz_02r_t1)

#In der Tabelle muss aus 1 der Wert 5 werden, aus 2 der Wert 4 usw.

Skalenwerte berechnen

Der Skalenwert ist der zeilenweise Mittelwert über die Items eines Konstrukts. Dabei ist die umgepolte Variable einzusetzen, sonst bleibt die Umpolung wirkungslos. Der Skalenwert erhält denselben Namensaufbau wie die Items, endet also ebenfalls auf den Messzeitpunkt.

## Skalenwerte berechnen

daten_wide$kompetenz_t1 <- rowMeans(
  daten_wide[, c("kompetenz_01_t1", "kompetenz_02r_t1", "kompetenz_03_t1")],
  na.rm = TRUE)

daten_wide$kompetenz_t2 <- rowMeans(
  daten_wide[, c("kompetenz_01_t2", "kompetenz_02r_t2", "kompetenz_03_t2")],
  na.rm = TRUE)

Das Argument na.rm steuert den Umgang mit fehlenden Werten. Die Voreinstellung ist na.rm = FALSE; wird das Argument weggelassen, gilt sie. In diesem Fall erhält bereits eine Person, die ein einziges Item nicht beantwortet hat, keinen Skalenwert, sondern NA. Mit na.rm = TRUE wird der Mittelwert stattdessen über alle vorhandenen Werte gebildet. Welche Variante angemessen ist, ist inhaltlich zu entscheiden.

Damit ist der Datensatz für die deskriptive Statistik und den t-Test aufbereitet. Er sieht so aus (weitere Items ausgelassen):

SERIALkompetenz_01_t1kompetenz_01_t2kompetenz_t1kompetenz_t2
abc123353.334.67
xyz789232.333.00
def4564NA4.33NA
[Tab. 3: Aufbereiteter Datensatz im Wide-Format (Beispiel)]

Wer eine Welle ausgelassen hat, erhält dort fehlende Werte. Dass diese Personen überhaupt im Datensatz verbleiben, liegt an der vorherigen Verwendung von full_join().

Dieser Teil wird nur für die Varianzanalyse mit Messwiederholung benötigt. Für deskriptive Statistik und t-Test genügt der Datensatz aus Teil 1.

Der Grund für den zusätzlichen Schritt liegt in der Funktionsweise der Auswertungsverfahren: aov_car() aus dem Paket afex erwartet je Person und Messzeitpunkt eine eigene Zeile, eine gemeinsame Spalte je Konstrukt und eine weitere Spalte, die den Messzeitpunkt angibt. Der Datensatz aus Teil 1 ist anders aufgebaut — dort steht jede Person in einer Zeile, und die Messzeitpunkte sind in den Variablennamen.

Für die Umformung gibt es zwar auch eine Basis-R-Funktion (reshape), sie gilt jedoch als umständlich. Verwendet werden deshalb pivot_longer() und pivot_wider() aus dem Paket tidyr.

Umstrukturierung ins Long-Format

Die Umformung erfolgt in zwei Schritten. Zuerst zieht `pivot_longer()` alle Messwerte in eine einzige Spalte zusammen; die bisherigen Variablennamen wandern in eine zweite Spalte. Anschließend verteilt `pivot_wider()` die Merkmale wieder auf eigene Spalten, sodass je Konstrukt eine Spalte entsteht. Beide Schritte lassen sich mit der Pipe verketten.

Vier Angaben steuern den ersten Schritt: cols legt fest, welche Spalten umgeformt werden. Hier alle, die auf einen Messzeitpunkt enden. names_to benennt die beiden neuen Spalten für Merkmal und Messzeitpunkt. names_pattern beschreibt, wie der bisherige Name in diese beiden Teile zerlegt wird: Die erste Klammer steht für alles vor der Zeitpunktangabe, die zweite für den Zeitpunkt selbst. values_to benennt die Spalte, in der die Werte zwischengelagert werden.

## Umstrukturierung ins Long-Format

daten_long <- daten_wide %>%
  pivot_longer(
    cols          = ends_with(c("_t1", "_t2")),
    names_to      = c("varname", "mzp"),
    names_pattern = "(.+)_(t[0-9])$",
    values_to     = "wert") %>%
  pivot_wider(
    names_from  = varname,
    values_from = wert)

Das Ergebnis: eine Zeile je Person und Messzeitpunkt, SERIAL als Personenkennung, mzp als Messzeitpunkt.

SERIALmzpkompetenz_01kompetenz_02rkompetenz_03kompetenz
abc123t13433.33
abc123t25454.67
xyz789t12322.33
xyz789t23333.00
def456t14454.33
def456t2NANANANA
[Tab. 4: Datensatz im Long-Format (Beispiel)]

Die ersten drei Wertespalten enthalten die Einzelitems, kompetenz deren Mittelwert. Nur diese letzte Spalte geht als abhängige Variable in die Varianzanalyse ein. Da die Skalenwerte aus Teil 1 demselben Namensmuster folgen wie die Items, werden sie automatisch mit umgeformt.

Zwei Punkte sind dabei zu beachten. Erstens laufen alle erfassten Spalten vorübergehend in einer gemeinsamen Wertespalte zusammen. Sind darunter sowohl Zahlen als auch Text z.B. ein umbenanntes offenes Antwortfeld, bricht pivot_longer() mit einer Meldung über nicht vereinbare Variablentypen ab. Offene Antworten sollten deshalb gar nicht erst auf _t1 beziehungsweise _t2 enden oder vorher aus daten_wide entfernt werden. Zweitens werden nur Spalten erfasst, deren Name auf einen Messzeitpunkt endet. Alles andere SERIAL und weitere nicht messwiederholte Angaben bleiben als eigene Spalte stehen und wiederholen sich in jeder Zeile derselben Person. Das ist beabsichtigt und entspricht dem Aufbau, den die Auswertungsverfahren erwarten.

Vollständige Fälle prüfen

In die Varianzanalyse mit Messwiederholung gehen nur Personen ein, die zu allen betrachteten Messzeitpunkten einen Wert haben. aov_car() entfernt unvollständige Fälle selbstständig und meldet das, allerdings erst beim Rechnen. Wie groß die verbleibende Stichprobe ist, lässt sich vorher feststellen.

## Vollständige Fälle prüfen

# Wie viele Personen haben zu beiden Zeitpunkten einen Skalenwert?
sum(complete.cases(daten_wide[, c("kompetenz_t1", "kompetenz_t2")]))

# Zum Vergleich: Gesamtzahl der Personen
nrow(daten_wide)

Weichen beide Zahlen stark voneinander ab, lohnt sich ein Blick auf die Ausfälle, bevor gerechnet wird.

Varianzanalyse mit Messwiederholung

Die Formel liest sich so: Vor der Tilde steht die abhängige Variable, hier der Skalenwert. Im Error()-Term steht vor dem Schrägstrich die Personenkennung, dahinter die Variable mit den Messzeitpunkten. Erscheint beim Rechnen eine Warnmeldung über fehlende Werte, benennt sie die Kennungen der entfernten Fälle. Das ist kein Fehler, sondern der oben beschriebene Ausschluss unvollständiger Fälle.

## Varianzanalyse mit Messwiederholung 

# install.packages("afex")
library(afex)

anova_1 <- aov_car(kompetenz ~ Error(SERIAL/mzp), data = daten_long)
anova_1

FAQ

Warum heißen Spalten nach dem Zusammenführen .x und .y?
Dann gibt es außer SERIAL weitere Spalten, die in beiden Wellen identisch heißen. Meist sind es technische Variablen, die in der Liste meta noch fehlen. Finden lassen sie sich vorab:
intersect(names(daten_t1), names(daten_t2))
Außer SERIAL sollte hier nichts erscheinen. Häufige Variablen neben den bereits berücksichtigten sind CASE, REF, LANGUAGE, ISOCODE, EXPIRED und LASTDATA.
Warum hat der Datensatz nach dem Zusammenführen mehr Zeilen als Personen?
Dann kommt mindestens eine Kennung innerhalb einer Welle mehrfach vor. Beim Zusammenführen wird jede Zeile der einen Welle mit jeder passenden Zeile der anderen kombiniert: aus zwei mal zwei Zeilen werden dann vier. Eine Warnung erscheint dabei nicht.
Ursache sind meist Testaufrufe während der Programmierung oder doppelte Registrierungen. Die Duplikatprüfung aus Teil 1 muss deshalb fehlerfrei durchlaufen, bevor zusammengeführt wird:
sum(duplicated(daten_t1$SERIAL))

Ergibt der Befehl einen Wert größer 0, zeigt der folgende Aufruf die betroffenen Kennungen:
daten_t1$SERIAL[duplicated(daten_t1$SERIAL)]
Wofür sind die gesicherten technischen Variablen gut? Wie dokumentiere ich die Rücklaufquote?
Grundlage ist der Registrierungsdatensatz daten_t0 (siehe: Beispielstudie erster Teil) denn nur dort steht, wer überhaupt eingeladen wurde beziehungsweise sich angemeldet hat. Der Operator %in% prüft für jede Kennung, ob sie auch in einer späteren Welle vorkommt, und gibt TRUE oder FALSE zurück.
#alle registrierten Personen
teilnahme <- data.frame(SERIAL = daten_t0$SERIAL)
# Hat diese Person an t1 beziehungsweise t2 teilgenommen?
teilnahme$t1 <- teilnahme$SERIAL %in% daten_t1$SERIAL
teilnahme$t2 <- teilnahme$SERIAL %in% daten_t2$SERIAL
# Rücklaufquoten
mean(teilnahme$t1)
mean(teilnahme$t2)
# Teilnahmemuster: an beiden, nur einer oder keiner Welle
table(teilnahme$t1, teilnahme$t2)
Was tun, wenn ein Konstrukt nur in einer Welle erhoben wurde?
Das ist der Regelfall bei Zusatzfragen und stellt kein Problem dar. Beim Umbenennen entfällt die entsprechende Zeile einfach, und im Long-Format erscheinen für die übrigen Messzeitpunkte fehlende Werte was inhaltlich korrekt ist, da dort keine Erhebung stattfand.
Wie entferne ich Fälle mit fehlenden Werten?
Auf den gesamten Datensatz angewendet, entfernen na.omit() und drop_na() alle Personen, die auf irgendeiner Variable einen fehlenden Wert haben. Sinnvoller ist es, gezielt die benötigten Variablen anzugeben.
daten_ohne_na <- daten_long %>% drop_na(kompetenz)

Zum Auffinden fehlender Werte dient is.na(). Der folgende Befehl zählt sie je Variable:
colSums(is.na(daten_wide))

Literaturtipps

Luhmann, M. (2020). R für Einsteiger: Einführung in die Statistik-Software für die Sozialwissenschaften. Beltz.

Field, A. (2024). Discovering Statistics Using IBM SPSS Statistics. Sage.

Spickzettel zu den verwendeten R-Paketen:

Posit Software, PBC. Datentransformation mit dplyr (deutsche Übersetzung). https://rstudio.github.io/cheatsheets/translations/german/data-transformation_de.pdf

Posit Software, PBC (2023). Data tidying with tidyr. https://rstudio.github.io/cheatsheets/html/tidyr.html

Kontakt: Bei weiteren Fragen bezüglich der Umsetzung von Umfragen kontaktieren Sie bitte: befragungssysteme@studiumdigitale.uni-frankfurt.de

Aktualisiert am 31. Juli 2026
War dieses Tutorial für Sie hilfreich?

Ähnliche Artikel

BRAUCHEN SIE UNTERSTÜTZUNG?
Keine Antwort auf gesuchte Frage? Wir beraten Sie gerne.
BERATUNG