Diese Lerneinheit widmet sich dem Management von Daten. Mit R können Variablen rekodiert, neu erstellt, gelöscht, umbenannt werden - Prozeduren, die zur Vorbereitung der Datenanalyse wichtig sind.
Wir arbeiten wiederum mit dem Datensatz kursdata_anon, der im Kurs erhoben wurde. Die Übung basiert dann auf Daten des European Social Surveys.
# Statistik 1: R Tutorat
# Übungsskript zum Datenmanagement
# Datum: 24.10.2024
# AutorIn: XXX
…alternativ könnt ihr wieder über “Import Dataset” im Environment gehen. Oder einfach den Syntaxfile mit Importcode aus der vorherigen Session verwenden!
# Working directory setzen
setwd("C:/mein_laufwerk/mein_datenverzeichnis")
# oder bei Mac usern:
setwd("~/daten")
# Daten einlesen
library(haven)
kursdata_anon <- read_dta("kursdata_anon.dta")
# install.packages("tidyverse")
library(tidyverse)
Mit remove() können einzelne Objekte aus dem Environment gelöscht werden:
remove(irrelevantes_objekt) # löscht Objekt "irrelevantes Objekt"
Mit rm() werden alle Objekte aus dem Environment gelöscht:
rm(list = ls())
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 Befehls wieder eingefügt/erstellt werden.
Eine Variable rekodieren heisst, einige ihrer Ausprägungen mit neuen Werten zu belegen. Manchmal ist es z.B. sinnvoll, mehrere Ausprägungen einer metrischen Variable in Klassen zusammenfassen. Dies ist etwa der Fall, wenn ihr euch für Generationen statt einzelne Altersstufen interessiert. Ihr würdet dann in der Altersvariable z.B. die Ausprägungen 25 bis 40 mit dem Wert “Millenial” rekodieren.
Hier wollen wir zu Übungszwecken die Variable fach mit neuen Werten belegen.
attributes(kursdata_anon$fach)
## $label
## [1] "studiertes hauptfach"
##
## $format.stata
## [1] "%10.0g"
##
## $class
## [1] "haven_labelled" "vctrs_vctr" "double"
##
## $labels
## Soziologie Sonstiges
## 1 2
table(kursdata_anon$fach)
##
## 1 2
## 47 7
Dabei soll die Ausprägung ‘2’ zur Ausprägung ‘0’ umkodiert werden. Studierende mit Hauptfach Soziologie tragen dann weiterhin die Ausprägung ‘1’, Studierende mit einem anderen Hauptfach sind dann aber mit ‘0’ codiert.
Meistens ist es sinnvoll, nicht die ursprüngliche Variable, sondern eine Kopie von ihr umzukodieren. Deshalb replizieren wir im ersten Schritt zunächst die Ausgangsvariable:
kursdata_anon$fach_neu <- kursdata_anon$fach
Hier wurde die Variable fach_neu gebildet und mit den Werten der Variable fach angereichert.
Nun nutzen wir den schon bekannten Pfeil <- als Rekodierungsanweisung:
kursdata_anon$fach_neu <- 0
Hier wurde die neu gebildete Variable überschrieben - allerdings so, dass alle Ausprägungen gleich ‘0’ sind. Das ist nicht in unserem Sinne! Deshalb noch mal von vorn:
kursdata_anon$fach_neu <- kursdata_anon$fach
Der Clou ist nun, zusätzlich zur Rekodierungsanweisung <-2 eine Bedingung in den Befehl einzufügen, so dass nur bestimmte Werte rekodiert bzw. überschrieben werden. Solche Bedingungen werden in R über eckige Klammern ([…]) gesetzt:
kursdata_anon$fach_neu[kursdata_anon$fach == 2] <- 0
Die Ausprägung ‘2’ der Variable fach_neu wurde hier,
wie intendiert, mit dem Wert ‘0’ überschrieben. Genau genommen wurden in
all jenen Messreihen die Variablenkopie
fach_neu mit dem Wert ‘0’ belegt, in denen die
Originalvariable fach den Wert ‘2’ aufweist.
Wir hätten in diesem Beispiel innerhalb der Bedingungen auch auf die
Variablenkopie statt die Ursprungsvariable verweisen können
(kursdata_anon$fach_neu[kursdata_anon$fach_neu == 2] <- 0
führt zum exakt identischen Ergebnis), oder die Rekodierung direkt in
der Ausgangsvariable vornehmen können - allerdings führen solche
internen Rekodierungen (bei der Ausgangs- und
Bedingungsvariable identisch sind) leicht zu Zirkelrekodierungen und
entsprechenden Codierungsfehlern. Die kugelsichere, extern
bedingte Befehlsstruktur (bei der Ausgangs- und Bedingungsvariable
nicht identisch sind), die exakt dem oben eingeführten Vorgehen
entspricht, lautet daher:
Daten$Neu <-
Daten$Original
Daten$Neu[Daten$Original
== Alte Ausprägung] <- Neue
Ausprägung
Oft erstellen wir in der Praxis die neue Variable nicht vorab als Kopie der Ausgangsvariable, sondern legen die neue, rekodierte Variable im ersten Rekodierungsschritt direkt an. Die Befehlsstruktur ist dann entsprechend:
Daten$Neu[Daten$Original == Alte Ausprägung] <- Neue Ausprägung
Für Rekodierungsoperationen gibt es wie angedeutet verschiedene wichtige Anwendungen, z.B.:
Gelegentlich sind Variablen in Datensätzen nicht stimmig zur Polung codiert: Höhere Werte stehen dann für niedrige Ausprägungen und kleinere Werte für höhere Ausprägungen. Dies ist kontraintuitiv und erschwert die Interpretation von Analyseergebnissen. In unserem Datensatz trifft dies z.B. auf die beiden Interessensvariablen intbild und intmig zu:
attributes(kursdata_anon$intmig)
## $label
## [1] "interesse: Migration und Integration"
##
## $format.stata
## [1] "%9.0g"
##
## $class
## [1] "haven_labelled" "vctrs_vctr" "double"
##
## $labels
## sehr etwas gar nicht
## 1 2 3
Daher nehmen wir hier - wiederum in einer neuen Variable, allerdings ohne vorher eine Kopie anzulegen - eine Umpolung durch Rekodierung vor:
kursdata_anon$intmig_neu[kursdata_anon$intmig == 1] <- 3
kursdata_anon$intmig_neu[kursdata_anon$intmig == 2] <- 2
kursdata_anon$intmig_neu[kursdata_anon$intmig == 3] <- 1
Hier wurde die Variable intmig zur Variablen
intmig_neu mit umgepolten Werten rekodiert. Der höchste
Wert (3) zeigt nun auch das grösste Interesse am Thema der Migration an,
während der tiefste Wert (1) das geringste Interesse ausdrückt.
Alternativ wäre es hier nicht möglich gewesen,
intern-bedingte Rekodierungen vorzunehmen, also dieselbe Variable für
Bedingung und Rekodierung, ohne Anlage einer neuen Variable, zu
verwenden. Grund: Innerhalb der Befehlsreihe gäbe es dann im dritten
Schritt einen Rückgriff auf eine nach dem ersten Schritt nicht mehr
existente Kategorie.
Achtung: Die Label der Variable gehen bei
solchen Rekodierungen verloren, manchmal werden sie sogar falsch
übertragen. Ihr solltet die neue Bedeutung der Variablenwerte mindestens
im Skript dokumentieren, besser aber noch die neue Variable neu
labeln.
attributes (kursdata_anon$intmig_neu)
## NULL
library(labelled)
val_labels(kursdata_anon$intmig_neu) <- c("gar nicht" = 1, "etwas" = 2, "sehr" = 3)
Checken ob’s passt:
attributes(kursdata_anon$intmig_neu)
## $labels
## gar nicht etwas sehr
## 1 2 3
##
## $class
## [1] "haven_labelled" "vctrs_vctr" "double"
summary(kursdata_anon$lezufr)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -99.00 61.50 71.00 66.37 80.75 98.00
In R müssen fehlende Werte als NA kodiert sein, damit sie in weiterführenden Befehlen und Analysen auch als solche erkannt werden. Häufig allerdings sind fehlende Werte in bereitgestellten Daten durch numerische Angaben kodiert. Dies ist ein Problem, weil dann insb. der Durchschnittswert, sonstige Lagemasse und Streuungsangaben verfälscht werden können.
kursdata_anon$lezufr[kursdata_anon$lezufr == -99] <- NA
summary(kursdata_anon$lezufr)
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 10.00 63.00 71.00 69.49 81.00 98.00 1
Da es sich in diesem Fall um eine einfache Variablenbereinigung handelt, haben wir auf die Anlage einer neuen Variable verzichtet.
Eine Klassifizierung ergibt vor allem dann Sinn, wenn metrischen Variablen gruppenbildende Grenzen aufweisen: Klassifizierungen erlauben Gruppenvergleiche wischen “armen” und “nicht-armen” Haushalten, zwischen Ländern mit über- oder unterdurchschnittlichem Wachstum oder zwischen Studierenden mit eher links- oder rechtsorientierter politischer Haltung. So könnte man die verschiedenen Werte der “leftright”-Variable in die Kategorien “links”, “mitte” und “rechts” kodieren. Auch hier nehmen wir die Kodierung nicht in der Ursprungsvariable vor, sondern legen eine neue Variable an:
kursdata_anon$leftright_kat[kursdata_anon$leftright <= 33] <- "links"
kursdata_anon$leftright_kat[kursdata_anon$leftright >= 34 & kursdata_anon$leftright <= 66] <- "mitte"
kursdata_anon$leftright_kat[kursdata_anon$leftright >= 67] <- "rechts"
Hier wurde eine neue (kategoriale) Variable mit dem Namen leftright_kat erstellt. Allen Personen mit Selbsteinschätzungen von 0 bis einschliesslich 33 wurde in der neuen Variable der Wert ‘links’ zugewiesen, von 34 bis einschliesslich 66 der Wert ‘mitte’ und ab 67 der Wert ‘rechts’. Alternativ wäre es hier auch möglich gewesen, wie im ersten Beispiel vorzugehen und zunächst die neue Variable als Kopie der alten anzulegen, um dann anschliessend sequentiell die Klassen zu definieren.
attributes(kursdata_anon$rauchen)
## $label
## [1] "letzte Woche geraucht?"
##
## $format.stata
## [1] "%18.0g"
##
## $class
## [1] "haven_labelled" "vctrs_vctr" "double"
##
## $labels
## ja nein, aber früher nein, noch nie
## 1 2 3
Variablen werden auch dann rekodiert, wenn wir Kategorien gleicher Tendenz zusammenfassen wollen. Dies ist beispielsweise der Fall, wenn wir alle Personen, die jemals geraucht haben, in einer Variablenkategorie vereinigen wollen - gleich, ob sie aktuell rauchen oder dies in der Vergangenheit getan haben:
kursdata_anon$rauchen_binary[kursdata_anon$rauchen <= 2] <- "Smoker"
kursdata_anon$rauchen_binary[kursdata_anon$rauchen == 3] <- "NonSmoker"
Hier wurde eine neue Variable mit dem Namen rauchen_binary erstellt. Allen Personen mit Werten bis einschliesslich ‘2’ in der Ursprungsvariable wurde nun der Wert ‘Smoker’ zugewiesen, Personen mit Werten gleich ‘3’ der neue Wert ‘NonSmoker’.
table(kursdata_anon$rauchen_binary, kursdata_anon$rauchen, useNA = "ifany")
##
## 1 2 3
## NonSmoker 0 0 27
## Smoker 17 10 0
# Alle Einheiten, die in der Ausgangsvariable die Werte 1 oder 2 aufweisen, tragen in der recodierten Variable den Wert "Smoker" - korrekt!
# Alle Einheiten, die in der Ausgangsvariable den Wert 3 aufweisen, tragen in der recodierten Variable den Wert "Non-Smoker" - korrekt
table(kursdata_anon$intmig_neu, kursdata_anon$intmig, useNA = "ifany")
##
## 1 2 3
## 1 0 0 1
## 2 0 22 0
## 3 31 0 0
# Die ausschliesslich in der Nebendiagonalen besetzte Kreuztabelle zeigt an, dass sämtliche Werte umgepoolt wurden
# Die Option "useNA = "ifany"" stellt sicher, dass auch ggf. vorhande Missings in der Kreuztabelle als Kategorie auftauchen und so in den Check der Rekodierung einbezogen werden können.
library(dplyr)
kursdata_anon <- rename(kursdata_anon, "soz_hf" = "fach_neu")
Mittels rename() aus dplyr lassen sich die Namen der Variablen verändern. Dies kann hilfreich sein, wenn die Namen inhaltlich nicht interpretierbar oder zu lang sind. Bei der neu benannten Variable soz_hf ist nun am Namen erkennbar, dass gefragt wird, ob man Soziologie oder ein anderes Fach als Hauptfach hat.
Eine typische analysevorbereitende Operation ist die Reduktion des Datensatzes auf die für die Analyse wichtigen Variablen:
kursdata_anon <- select(kursdata_anon, id, rauchen_binary, lezufr)
Hier wurde, mithilfe des select()-Befehls, ein Teildatensatz mit den Variablen rauchen_binary und lezufr sowie - immer dabei - der ID erstellt. Der Datensatz ist nun auf die akut relevanten Variablen begrenzt und übersichtlich.
Da die ausgeschlossen Variablen üblicherweise in den weiteren Operationen der Syntax nicht mehr aufgegriffen werden, wird bei Anwendung von “select” meist kein neuer Datensatz angelegt, sondern einfach der Ausgangsdatensatz reduziert
Ebenfalls eine wichtige Operation: Den Datensatz auf bestimmte Merkmalsträger beschränken bzw. ausprägungsabhängige Teilgruppen des Datensatzes bilden:
smokers <- filter(kursdata_anon, rauchen_binary == "Smoker")
Mit filter() haben wir nun Merkmalsträger mit der Ausprägung “Smoker” herausgefiltert und damit eine neue Teilstichprobe namens “smokers” erstellt, die ausschliesslich Personen enthält die aktuell rauchen oder früher geraucht haben.
Die “Gegenteil-Stichprobe” aller NichtraucherInnen ergibt sich entsprechend durch:
no_smokers <- filter(kursdata_anon, rauchen_binary == "NonSmoker")
Übrigens: Anstatt mit == (gleich), könnten wir auch mit != (ungleich) alle Merkmalsträger, die nicht die entsprechende Ausprägung haben, herausfiltern.
Gruppierungen mit filter() werden häufig vorgenommen, um Mittelwerte verschiedener Teilgruppen miteinander zu vergleichen. Zum Beispiel um die Frage zu beantworten, ob RaucherInnen oder NichtraucherInnen zufriedener mit ihrem Leben sind.
mean(smokers$lezufr, na.rm = TRUE)
## [1] 67.96296
mean(no_smokers$lezufr, na.rm = TRUE)
## [1] 71.07692
Die Variable Lebenszufriedenheit ist von ‘’0’ bis ‘100’ kodiert, wobei ‘100’ für die höchste Lebenszufriedenheit steht. Die beiden Durchschnittswerte lassen erkennen wie sich die Lebenszufriedenheit der Raucher im Mittel von der der Nichtraucher unterscheidet.
Merkmalsträger mit Missings auf analyserelevanten Variablen werden vor der Analyse in der Regel ausgeschlossen. Wir können die NAs einzelner Variablen nun gezielt mit dem filter() Befehl entfernen:
kursdata_noNA <- filter(kursdata_anon,!is.na(rauchen_binary),!is.na(lezufr))
Hier wurden Merkmalsträger mit NAs in den Variablen rauchen_binary und lezufr entfernt. Du siehst im Environment, dass das neu erstellte Objekt kursdata_noNA nun weniger observations hat als der Teildatensatz kursdata_anon.
BCP Kapitel 3: Beckerman, A.P., Childs, D.Z., Petchey, O.L. (2017): Getting Started with R. Oxford: University Press.
GW Kapitel 5: Wickham, Hadley und Garrett Grolemund (2018): R for Data Science. Import, Tidy, Transform, Visualize, and Model Data.