invisible header

link zum pdf

In dieser zweiten Wiederholungssitzung widmen wir uns dem Management von Daten nach dem Einlesen. Mit R können Variablen rekodiert, neu erstellt, gelöscht oder umbenannt werden - Prozeduren, die zur Vorbereitung der Datenanalyse wichtig sind.

Wir arbeiten wiederum mit dem Datensatz European Social Surveys (ESS8e02_1.dta).

# Statistik 2: R Tutorat
# Übungsskript zum Thema Datenmanagement
# Datum: XX.XX.XXXX
# AutorIn: XXX

 

Vorbereitung: Einlesen der Daten und Aktivieren der nötigen Packages

# Working directory setzen
setwd("C:/mein_laufwerk/mein_datenverzeichnis")
# oder bei Mac usern: 
setwd("~/daten") 
# Daten einlesen
library(haven)
ess8 <- read_dta("ESS8e02_2.dta")
# install.packages("tidyverse")
library(tidyverse)

 

1. Aufräumen und Überblick

Zu Beginn räumen wir das Environment auf und löschen Objekte, die wir nicht mehr brauchen. Mit rm(list=ls()) löschen wir alle Objekte, mit remove() können wir einzelne auswählen.

rm(list=ls())
remove(Irrelevantes Objekt)

Alternativ kann im Environment auch das Besen-Symbol zum Löschen sämtlicher Objekte angeklickt werden.

Das Entfernen von Objekten, die im Arbeitsprozess nicht mehr benötigt werden, dient der Übersichtlichkeit. Wenn ein Objekt entfernt wurde, kann es über erneutes Einlesen des Datensatzes bzw. erneuter Ausführung des Skriptes wieder eingefügt/erstellt werden.

library(labelled)
varlist <- look_for(ess8)
View(varlist)

Gerade bei grösseren Datensätzen wie dem ESS kann es sinnvoll sein, initial vor jeder Session ein Codebook anzulegen, um dann bei Bedarf schnell nach Merkmalen oder deren Attributen zu suchen.

 

2. Datenauswahl: Variablen Selektieren

Eine typische analysevorbereitende Operation ist die Reduktion des Datensatzes auf die für die Analyse wichtigen Variablen:

ess8_ss <- select(ess8, idno, cntry, ctzcntr, eduyrs, trstplc, trstplt)  

Hier wurde mithilfe des select()-Befehls ein Teildatensatz “ess8_ss” mit den für die folgenden Analysen relevanten Variablen (Staatsbürgerschaft im Aufenthaltsland ja/nein, Bildungsjahre, Vertrauen in Polizei/Politiker) erstellt. Einer Konvention folgend schliessen wir auch die Identifier (hier idno und cntry) mit ein.

Mit select() kann man also den Datensatz auf die akut relevanten Variablen begrenzen und so mehr Übersichtlichkeit gewinnen.

 

3. Datenauswahl: Merkmalsträger Filtern

Ebenfalls eine wichtige Operation: den Datensatz auf bestimmte Merkmalsträger beschränken bzw. ausprägungsabhängige Teilgruppen (z.B. eine Schweizer Teilstichprobe) des Datensatzes bilden:

ess8_ss_CH <- filter(ess8_ss, cntry == "CH")

Wir wollen zusätzlich zwei Teilgruppen separat analysieren: Personen mit und ohne Schweizer Staatsbürgerschaft:

citizen <- filter(ess8_ss_CH, ctzcntr == 1)

Gemäss Codebook wurde Personen mit Staatsbürgerschaft im Befragungsland der Wert 1 zugewiesen und Personen ohne Staatsbürgerschaft im Befragungsland der Wert 2. Mit dem filter() Befehl haben wir nun also Personen mit der Ausprägung 1 herausgefiltert und damit eine neue Teilstichprobe namens “citizen” erstellt, die ausschliesslich Personen mit Schweizer Staatsbürgerschaft enthält.

Die “Gegenteilstichprobe” aller Personen ohne Staatsbürgerschaft ergibt sich entsprechend durch:

non_citizen <- filter(ess8_ss_CH, ctzcntr == 2)
Übrigens: Anstatt mit == (gleich), könnten wir auch mit != (ungleich) alle Merkmalsträger, die nicht die entsprechende Ausprägung haben, herausfiltern.

 

3.1 Teilgruppenvergleich, Mittelwertdifferenz

Gruppierungen mit filter() werden häufig vorgenommen, um Mittelwerte verschiedener Teilgruppen miteinander zu vergleichen. Zum Beispiel um die Frage zu beantworten, ob Personen mit oder ohne Schweizer Staatsbürgerschaft grösseres Vertrauen in die Polizeit haben.

mean(citizen$trstplc, na.rm = TRUE)
## [1] 7.181745
mean(non_citizen$trstplc, na.rm = TRUE)
## [1] 7.469751
sd(ess8_ss_CH$trstplc, na.rm = TRUE)
## [1] 1.92807
Personen ohne Schweizer Staatsbürgerschaft haben also im Mittel ein um etwa 0.3 Skalenpunkte grösseres Vertrauen in die Polizei. Dieser Mittelwertunterschied entspricht etwa 0.15 Standardabweichungseinheiten (berechnet aus 0.3/1.93) und drückt somit einen kleinen, aber nicht unbedeutenden Unterschied aus: Immerhin entspricht die Mittelwertdifferenz zugunsten der Nicht-Staatsbürger einem Siebtel der typischen Abweichung.

 

3.2 Mittelwertdifferenz als t-test mit ungepaarten Beobachtungen

Der per Hand durchgeführte Mittelwertvergleich erlaubt nur eine inhaltliche, keine inferenzsstatistische Einordnung der ermittelten Mittelwertdifferenz: Ist diese überzufällig oder nicht? Diese Ermittlung erfolgt in der vorliegenden Variablenkonstellation (UV kategorial, AV metrisch) im Rahmen eines sog. t-tests. Der Begriff t-test beschreibt also die Durchführung eines Mittelwertvergleichs und dessen Anreicherung mit inferenzstatistischen Parametern.

t.test(formula=trstplc~ctzcntr, 
       data=ess8_ss_CH, 
       var.equal=TRUE)
## 
##  Two Sample t-test
## 
## data:  trstplc by ctzcntr
## t = -2.2636, df = 1517, p-value = 0.02374
## alternative hypothesis: true difference in means between group 1 and group 2 is not equal to 0
## 95 percent confidence interval:
##  -0.53757700 -0.03843528
## sample estimates:
## mean in group 1 mean in group 2 
##        7.181745        7.469751
Die Nullhypothese, dass es in der Population keinen Unterschied im Vertrauen in die Polizei zwischen Personen mit und ohne Schweizer Staatsbürgerschaft gibt, kann also abgelehnt werden.

 

3.3 Mittelwertdifferenz als t-test mit gepaarten Beobachtungen

Auch ein Mittelwertgleich mit gepaarten Beobachtungen wird, sofern er mit inferenzstatistischen Parametern angereichert wird, t-test genannt. Wenn wir beispielsweise fragen, ob die Polizei oder die Politik in der Schweiz höheres Vertrauen geniessen, korrespondiert dies zur Logik eines Mittelwertvergleichs mit gepaarten Beobachtungen - weil von jeder befragten Person sowohl für den einen, als auch den anderen Mittelwert eine Messung vorliegt.

mean(ess8_ss_CH$trstplc, na.rm = TRUE)
## [1] 7.235023
mean(ess8_ss_CH$trstplt, na.rm = TRUE)
## [1] 5.37027
t.test(ess8_ss_CH$trstplc, 
       ess8_ss_CH$trstplt, 
       paired=TRUE, 
       var.equal=TRUE)
## 
##  Paired t-test
## 
## data:  ess8_ss_CH$trstplc and ess8_ss_CH$trstplt
## t = 35.008, df = 1477, p-value < 2.2e-16
## alternative hypothesis: true mean difference is not equal to 0
## 95 percent confidence interval:
##  1.744871 1.952016
## sample estimates:
## mean difference 
##        1.848444

Wir sehen, dass in diesem Beispiel die händisch berechnete Mittelwertdifferenz nicht der im Rahmen des t-tests ausgewiesenen entspricht. Dies lässt sich darauf zurückführen, dass im Rahmen des gepaarten t-tests nur solche Einheiten verrechnet werden, die in beiden Konditionen einen gültigen Wert haben bzw. in beide Mittelwertberechnungen mit einfliessen können. Ausserdem gibt der Befehl zum gepaarten t-test direkt die konkrete Mittelwertdifferenz statt die beiden Mittelwerte aus.

Das Vertrauen gegenüber der Polizei ist im Mittel deulich (und statistisch signifikant) stärker ausgeprägt als das Vertrauen gegenüber der Politik.

 

3.4 Visualisierung der Mittelwertdifferenz

Typische Visualisierungsform des Mittelwertvergleichs (und somit der Zusammenhangskonstellation UV: Kategorial, AV: Metrisch) ist der Differenzierte Boxplot, der im folgenden Beispiel noch mit einem Punktmuster angereichert wurde.

# Umwandlung der Variablen in ggplot-kompatible Formate
ess8_ss_CH$trstplc <- as.numeric(ess8_ss_CH$trstplc)  # Entfernt Haven-Labels
ess8_ss_CH$ctzcntr <- as_factor(ess8_ss_CH$ctzcntr)  # Stellt sicher, dass es eine kategoriale Variable ist

box <- ggplot(ess8_ss_CH, 
              aes(y = trstplc, x = ctzcntr, fill = ctzcntr)) + 
  geom_boxplot(outlier.shape = NA) + 
  labs(y = "Vertrauen in die Polizei",
       x = "Schweizer Staatsbürgerschaft",
       title = "Verteilung: Vertrauen in die Polizei nach Staatsbürgerschaft",
       caption = "Quelle: ESS08") + 
  ylim(0, 10) + 
   scale_y_continuous(breaks = seq(0, 10, by = 2)) +  
  geom_jitter(alpha = 0.1, position = position_jitter(0.08)) +  # Jitter-Punkte transparenter
    stat_summary(fun = mean, geom = "point", shape = 23, size = 3, 
               color = "magenta3", fill = "white") +  
  theme_bw() + 
  theme(legend.position = "none")
box

Eine ausführliche Übersicht zu den Visualisierungsmöglichkeiten dieser Variablenkonstellation findet ihr auf den Seiten der Statistik 1

 

4. Bereinigen: Rekodieren

Eine Variable rekodieren heisst, ihre Ausprägungen mit neuen Werten zu überschreiben bzw. umzuwandeln. Manchmal ist es z.B. sinnvoll, mehrere Ausprägungen einer metrischen Variable in Klassen zusammenzufassen. Dies ist etwa der Fall, wenn ihr euch für Generationen statt einzelne Altersstufen interessiert. Ihr würdet dann in der Altersvariable die Ausprägungen 25 bis 40 mit dem Wert ‘Millenial’ überschreiben wollen.

Hier wollen wir zu Übungszwecken die Variable rlgblg mit neuen Werten belegen. Konkret: Wir wollen sie in eine sog. “Dummy-Variable” mit den Kategorien “0” (für “Merkmal liegt nicht vor”) und “1” (“Merkmal liegt vor”) transformieren. Als erstes können wir über den Befehl attributes() die Ausprägungen und Labels der Ausgangsvariable ermitteln:

attributes(ess8$rlgblg)
## $label
## [1] "Belonging to particular religion or denomination"
## 
## $format.stata
## [1] "%12.0g"
## 
## $class
## [1] "haven_labelled" "vctrs_vctr"     "double"        
## 
## $labels
##        Yes         No    Refusal Don't know  No answer 
##          1          2         NA         NA         NA

Alternativ hätten wir zur Variableninspektion auch das oben per look_for angelegte Codebook konsultieren können.

Erster Schritt der Rekodierung ist (meist) die Generierung einer neuen Variable:

# Generiere neue Variable für Rekodierung
ess8$rlgblg_neu <- NA

Hier wurde eine neue Variable rlgblg_neu angelegt und vollständig mit “NA” belegt. Hintergrund: Es gibt verschiedene Strategien zur Modifikation bzw. Rekodierung einer Variable, die jeweils mit bestimmten Vor- und Nachteilen verbunden sind. Wir haben uns hier zur Dokumentation derjenigen Variante entschieden, die in den meisten von uns durchprobierten Szenarien gut funktioniert. So beugt die Anlage einer neuen, typneutralen Variable späteren Typkonflikten vor, und die Belegung mit “NA” (statt mit leeren Werten) sorgt dafür, dass viele potentielle Rekodierungsfehler später schneller auffallen.

Den schon bekannten Pfeil (<-) nutzen wir auch als Rekodierungsanweisung:

# Rekodiere "rlgblg" als Dummy-Variable
ess8$rlgblg_neu[ess8$rlgblg == 2] <- 0
ess8$rlgblg_neu[ess8$rlgblg == 1] <- 1

Der Clou ist nun, dass zusätzlich zur Rekodierungsanweisung <-0 eine Bedingung in den Befehl eingebunden wird, damit jeweils nur bestimmte Ausgangswerte der Variable mit einem bestimmten neuen Wert kodiert werden. Solche Bedingungen werden in R über eckige Klammern ([…]) gesetzt. Die Befehlsstruktur zum Rekodieren lautet dementsprechend:

# Kontrolle mit table 
table(ess8$rlgblg)
## 
##     1     2 
## 26314 17772
table(ess8$rlgblg_neu)
## 
##     0     1 
## 17772 26314
attributes(ess8$rlgblg_neu)
## NULL

Die ausgewiesenen Fallzahlen von alter und neuer, recodierter Variable zeigen:

Achtung: Die Wertelabel der Ausgangsvariable wurden bei der Rekodierung nicht mit übertragen - siehe “attributes” oben. Diese können bei Bedarf (z.B. auf Basis des Packages “labelled”) neu angelegt werden:

library (labelled)
## Warning: Paket 'labelled' wurde unter R Version 4.3.3 erstellt
ess8$rlgblg_neu <- labelled::labelled(ess8$rlgblg_neu, c(no = 0, yes = 1))
attributes(ess8$rlgblg_neu)
## $labels
##  no yes 
##   0   1 
## 
## $class
## [1] "haven_labelled" "vctrs_vctr"     "double"

ps: Das “labelled”-Package muss für diese Funktionalität aktiviert sein, sonst greift R an dieser Stelle auf einen “falschen”, gleichlautenden Befehl aus dem “haven”-package zu.

Die Notwendigkeit, Rekodierungen vorzunehmen, begegnet uns in der Datenpraxis oft. Einige weitere typische Anwendungen:

 

4.1 Variablenwerte Rekodieren: Missings

summary(ess8$eisced)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   1.000   2.000   4.000   4.109   5.000  55.000     129
attributes(ess8$eisced)
## $label
## [1] "Highest level of education, ES - ISCED"
## 
## $format.stata
## [1] "%51.0g"
## 
## $class
## [1] "haven_labelled" "vctrs_vctr"     "double"        
## 
## $labels
##             Not possible to harmonise into ES-ISCED 
##                                                   0 
##              ES-ISCED I , less than lower secondary 
##                                                   1 
##                        ES-ISCED II, lower secondary 
##                                                   2 
##           ES-ISCED IIIb, lower tier upper secondary 
##                                                   3 
##           ES-ISCED IIIa, upper tier upper secondary 
##                                                   4 
##        ES-ISCED IV, advanced vocational, sub-degree 
##                                                   5 
##     ES-ISCED V1, lower tertiary education, BA level 
##                                                   6 
## ES-ISCED V2, higher tertiary education, >= MA level 
##                                                   7 
##                                               Other 
##                                                  55 
##                                             Refusal 
##                                                  NA 
##                                          Don't know 
##                                                  NA 
##                                           No answer 
##                                                  NA
ess8$eisced[ess8$eisced == 55] <- NA

In R müssen fehlende Werte als NA kodiert sein, damit sie auch als solche erkannt werden. Entsprechende Rekodierungen sind oft notwendig, da fehlende Werte in den bereitgestellten Daten häufig durch numerische Angaben kodiert sind. Dies ist ein Problem, weil dann Statistiken verfälscht werden. Bei einfachen Rekodierungen kann, wie hier, die Umbildung oft auch direkt in der Ausgangsvariable erfolgen. Das heisst: Ausgangs- und Zielvariable des Rekodierungsbefehls sind dann identisch. Aber Achtung: das funktioniert nicht immer!

 

4.2 Variablenwerte Rekodieren: Umpolung

Auch wenn es meist nicht zwingend ist, kann es gelegentlich sinnvoll sein, Variablen umzupolen.

# Inspiziere "polintr"
attributes(ess8$aesfdrk)
## $label
## [1] "Feeling of safety of walking alone in local area after dark"
## 
## $format.stata
## [1] "%12.0g"
## 
## $class
## [1] "haven_labelled" "vctrs_vctr"     "double"        
## 
## $labels
##   Very safe        Safe      Unsafe Very unsafe     Refusal  Don't know 
##           1           2           3           4          NA          NA 
##   No answer 
##          NA
table (ess8$aesfdrk)
## 
##     1     2     3     4 
## 12995 22393  7082  1522

Bei einer Variable wie aesfdrk, die den Grad an Sicherheitsempfingen abfragt, erschiene beispielsweise eine Belegung nach dem Leitbild “je höher der Wert, desto höher das Sicherheitsempfingen” naheliegender und intuitiver:

# Umpolung
ess8$aesfdrk_new<-NA
ess8$aesfdrk_new[ess8$aesfdrk == 1] <- 4
ess8$aesfdrk_new[ess8$aesfdrk == 2] <- 3
ess8$aesfdrk_new[ess8$aesfdrk == 3] <- 2
ess8$aesfdrk_new[ess8$aesfdrk == 4] <- 1


# Inspiziere die umgepolte Variable
table (ess8$aesfdrk_new)
## 
##     1     2     3     4 
##  1522  7082 22393 12995
class (ess8$aesfdrk_new)
## [1] "numeric"
attributes (ess8$aesfdrk_new)
## NULL

Achtung: Auch hier wurden Label (Hauptlabel und Wertelabel) bei Anlage der neuen Variable und der bedingten Belegung nicht übernommen. Sie müssen ggf. auf Basis eines einschlägigen Packages bzw. Kommandos (siehe oben) neu angelegt werden.

4.3 Variablenwerte Rekodieren: Klassifizieren

Variablen werden auch dann rekodiert, wenn wir Kategorien gleicher Tendenz zusammenfassen bzw. die Variable “klassifizieren”. Im folgenden Beispiel werden z.B. generelle Tendenzen in der politischen Positionierung zusammengefasst:

# Inspiziere "lrscale"
table (ess8$lrscale)
## 
##     0     1     2     3     4     5     6     7     8     9    10 
##  1463   846  2121  3754  3780 12389  4105  4269  3265   999  1592
class (ess8$lrscale)
## [1] "haven_labelled" "vctrs_vctr"     "double"
# Klassifiziere "lrscale" zu Basistendenzen
ess8$lrscale_kat<-NA
ess8$lrscale_kat[ess8$lrscale <= 3] <- "links" 
ess8$lrscale_kat[ess8$lrscale >= 4 & ess8$lrscale <= 6] <- "mitte"
ess8$lrscale_kat[ess8$lrscale >= 7] <- "rechts"

Hier wurde eine neue (kategoriale) Variable mit dem Namen lrscale_kat erstellt. Allen Werten von 0 bis einschliesslich 3 wurde der Wert ‘links’ zugewiesen, Werten von 4 bis einschliesslich 6 der Wert ‘mitte’ und ab 7 der Wert ‘rechts’. Interessant: Durch die Belegung der neuen Variable mit Schriftzeichen statt Zahlen wird ihr automatisch die Klasse “character” zugewiesen.

Auf Basis von Häufigkeitsauszählungen und insb. einer einfachen Kreuztabellierung könnt Ihr nun noch prüfen, ob (a) sich die Fallzahlen in der neuen Variable korrekt aufaddieren und (b) alle Zuordnungen dem Verkodungsschlüssel entsprechen:

# Inspiziere die klassierte Variable
table (ess8$lrscale_kat)
## 
##  links  mitte rechts 
##   8184  20274  10125
table (ess8$lrscale)
## 
##     0     1     2     3     4     5     6     7     8     9    10 
##  1463   846  2121  3754  3780 12389  4105  4269  3265   999  1592
table(ess8$lrscale_kat, ess8$lrscale, useNA = "always")
##         
##              0     1     2     3     4     5     6     7     8     9    10
##   links   1463   846  2121  3754     0     0     0     0     0     0     0
##   mitte      0     0     0     0  3780 12389  4105     0     0     0     0
##   rechts     0     0     0     0     0     0     0  4269  3265   999  1592
##   <NA>       0     0     0     0     0     0     0     0     0     0     0
##         
##           <NA>
##   links      0
##   mitte      0
##   rechts     0
##   <NA>    5804

Klassifizierungen können sinnvoll sein für Gruppenvergleiche (siehe das Beispiel zu den Alterskohorten oben) oder wenn es entscheidende Grenzen der Variable gibt (z.B. arm vs. nicht arm bei der Einkommensvariable). Zu beachten ist aber, dass mit Klassifizierungen immer ein Informationsverlust einhergeht - deswegen wägt vorher immer gut ab, ob dieser auch gerechtfertigt ist.

# Alternative mit case_when
ess8$lrscale_kat2 <- case_when(
  ess8$lrscale <= 3 ~ "links",
  ess8$lrscale >= 4 & ess8$lrscale <= 6 ~ "mitte",
  ess8$lrscale >= 7 ~ "rechts",
  TRUE ~ NA)
table(ess8$lrscale_kat2, ess8$lrscale_kat, useNA = "always")
##         
##          links mitte rechts  <NA>
##   links   8184     0      0     0
##   mitte      0 20274      0     0
##   rechts     0     0  10125     0
##   <NA>       0     0      0  5804

 

4.4 Variablenwerte Rekodieren: Reskalierungen

Wir können - wie in der vorigen Sitzung bereits angedeutet - auch Rechenoperationen an Variablen durchführen um diese umzuformen.

In diesem Fall rekodieren wir die Einheiten der Variable netustm von «Minuten pro Tag» in «Stunden pro Tag»:

ess8$netusth <- ess8$netustm/60

 

5. Bereinigen: Variablen Umbenennen

library(dplyr)
ess8 <- rename(ess8, "citizen" = "ctzcntr")

Mittels rename() Befehl aus dplyr lassen sich die Namen der Variablen verändern. Dies kann hilfreich sein, wenn die Namen inhaltlich nicht interpretierbar oder zu lang sind. Die allgemeine Befehlsstruktur lautet:

rename(daten, neuer Name = alter Name)

 

Die Variable Lebenszufriedenheit ist von (0) bis (54) kodiert, wobei (54) den Maximalwert in der Stichprobe darstellt (54 Jahre formelle Bildung). Somit haben Personen ohne Staatsbürgerschaft im Durchschnitt eine längere Schullaufbahn von 13.27 Jahre im Vergleich zu Personen mit Staatsbürgerschaft, wobei letztere eine durchschnittliche Schullaufbahn von 13.02 Jahren aufweisen.

Hier gehts weiter zur Übung II

 

logo.knit

Conforti, E., Siefart, F., De Min, N., Dürr, R., Hofer, L., Rauh, S., Senn, S., Strassmann Rocha, D., Giesselmann, M. (2023): “Regressionsanalysen mit R”