-
Notifications
You must be signed in to change notification settings - Fork 5
/
08-Datenimport.Rmd
335 lines (230 loc) · 16.8 KB
/
08-Datenimport.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
---
editor_options:
chunk_output_type: console
---
# Datenimport
Im Laufe eures Studiums (und vermutlich darüberhinaus) werdet ihr sehr viel Zeit damit verbringen Daten aus verschiedenen Quellen in die Statistiksoftware eurer Wahl (oder auch nicht eurer Wahl, aber der eurer Arbeitstselle) zu quetschen.
Das funktioniert mal mehr und mal weniger einfach, denn je nachdem wie die Originaldaten aussehen, kann das mitunter anstrengend bis deprimierend werden.
Saubere (*tidy*) Daten sehen immer gleich aus, aber unsaubere Daten sind alle auf ihre eigene Art unsauber. Mal fehlen Variablenbeschriftungen, mal sind da Umlaute durch Encoding kaputtgegangen, manchmal werden numerische Werte als *character* interpretiert und manchmal sind fehlende Werte mit irgendwelchen willkürlichen Werten kodiert (z.B. `-99` anstatt `NA`).
Vielleicht wundert ihr euch auch, wieso dieses Kapitel erst so spät in dieser Einführung auftaucht. Das liegt primär daran, dass ihr unter Umständen ein ausreichend großes Repertoire an Grundlagen braucht, um Daten auf alle Fälle sauber eingelesen zu bekommen.
In vielen Fällen, und besonders in QM, ist das Ganze noch relativ überschaubar und eure TutorInnen können entsprechende Hilfestellung bieten, aber *irgendwann* seid ihr auf euch allein gestellt, und dann macht ein bisschen Bonus-Wissen hier und da den Unterschied zwischen einem anstrengenden Nachmittag voller Leid und Schmerz oder 10 Minuten Probiererei und schnellem Erfolg.
Wenn ihr Daten von eurer Festplatte einlesen wollt, und ihr keine Ahnung habt wie Dateipfade funktionieren, was euer *Home Ordner* ist, was beispielsweise `~/Documents` sein soll oder wie ihr rausfindet, *wo* ihr gerade auf euren Computern seid, [dann lest euch das bitte selber an](https://de.wikipedia.org/wiki/Pfadname).
Auch hier liefert RStudio jedenfalls im "Files"-Tab entsprechende Orientierungshilfe:
```{r, echo=FALSE, fig.cap="RStudio Filebrowser im Projekt dieser Einführung", out.width="50%"}
knitr::include_graphics("images/data_import_rstudio_filesystem.png")
```
Das rot umrandete ist der Pfad zum Projektordner, in R würde ich den also so eingeben müssen:
```sh
"~/repos/tadaadata/r-intro-book"
```
Wobei die Tilde `~` eine Abkürzung für das Home-Verzeichnis ist.
## Quellen
Da in QM nur SPSS und R benutzt werden, werdet ihr vermutlich meistens auf Datensätze aus SPSS (`.sav`) stoßen. R kann zwar SPSS-Daten einlesen, aber SPSS kann mit R-Daten nichts anfangen. Außerdem beinhalten SPSS-Datensätze auch ein bisschen Metadaten, wie zum Beispiel Labels für eure Variablen oder nominalskalierte Variablen, die wir in R dann für bessere Optik benutzen können — andere Formate wie Textdateien (`.csv`, `.txt`, *plain text*) sind spartanischer und haben sowas nicht.
Die einfachste Option ist meistens die RStudio-Funktio zum Datenimport, aber auch hier solltet ihr erstmal wissen, wo eure Daten herkommen und ggf. über die ein oder andere Eigenart bescheid wissen.
```{r, echo=FALSE, fig.cap="RStudio Import-Tool", out.width="50%"}
knitr::include_graphics("images/data_import_rstudio.png")
```
Bei den Textdateien sind mit `base` und `readr` die beiden unterschiedlichen Möglichkeiten gemeint, mit denen wir Daten einlesen können, aber mehr dazu im entsprechenden Abschnitt.
Eine Sache noch zum Encoding: Um kaputte Umlaute und andere Krämpfe zu vermeiden bietet es sich an, **überall alles immer** auf Unicode bzw. **UTF-8** zu stellen wenn ihr _irgendwo_ nach Encoding gefragt werdet.
### Roher Text (`.csv`, `.txt`)
- Benötigte packages: `readr`
- Anstrengend? Entweder alles super oder Riesenkrampf
Einfacher Text (*plain text*) ist die einfachste Möglichkeit Datensätze zu speichern bzw. zu übertragen, da Text so ziemlich der kleinste gemeinsame Nenner jeder gängigen Software ist. **CSV** heißt auch nur *"comma separated values"*, und wird euch vermutlich noch häufiger begegnen. Eine CSV-Datei könnt ihr mit jedem beliebigen Texteditor öffnen (ihr müsst dafür kein Office rauskramen, auf Windows tut es auch das Notepad), und ihr seht dann vermutlich sowas in der Art:
```csv
"extra","group","ID"
0.7,"1","1"
-1.6,"1","2"
-0.2,"1","3"
-1.2,"1","4"
-0.1,"1","5"
3.4,"1","6"
```
Das Prinzip ist ziemlich einfach: In der ersten Zeile stehen die Variablennamen, und in jeder folgenden Zeile steht jeweils der Wert der zugehörigen Variable, getrennt durch ein Komma.
Die Schwierigkeit kommt dann, wenn die Werte zum Beispiel Text enthalten, der wiederum ein Komma enthalten kann, und der Wert nicht richtig in Anführsungszeichen gesetzt ist. Es gibt auch noch Varianten mit Tabs statt Kommata als Trennzeichen, das wäre dann strenggenommen *TSV* (ihr dürft raten wofür das *T* steht).
Textformate sind also ziemlich einfach um eure Daten zu speichern oder zu verschicken, aber es ist auch sehr fragil, sobald mal irgendwo ein `"` fehlt oder zu viel ist, wird's kompliziert.
Zum lesen und schreiben empfehle ich herzlichst das `readr`-package mit den Funktionen `read_csv`, `write_csv` etc. zu benutzen, die sind weniger anfällig für Murks als die base-Standardfunktionen mit gleichem Namen aber `.` statt `_` (`read.csv`, `write.csv`).
Als Beispiel laden wir mal [diesen schönen *Game of Thrones*-Datensatz](https://data.world/aendrew/game-of-thrones-deaths):
```{r, eval=FALSE, message=FALSE, error=FALSE, warning=FALSE}
library(readr)
gotdeaths <- read_csv("data/got_deaths.csv")
head(gotdeaths)
```
Hier habe ich `col_types = cols()` nur benutzt, um das Output zu unterdrücken. Ihr könnt über dieses Argument aber auch manuell spezifizieren, welchen Typ jede Spalte haben soll, damit eure Daten explizit so eingelesen werden, wie ihr sie erwartet.
Die schmutzigen Details gibt's natürlich in der Hilfe: `?read_csv` und [online](http://readr.tidyverse.org/).
### SPSS (`.sav`)
- Benötigte packages: `haven` oder `sjmisc`
- Anstrengend? Manchmal.
```r
library(haven)
ngo <- read_spss("data/NGO.SAV")
```
Die Funktionen `read_sav` und `read_spss` sind identisch.
### R (`.rds`, `.rda` & `.RData`)
- Benötigte packages: Keins (Base R reicht, optional `readr` als Alternative)
- Anstrengend? Nope, alles tutti.
Der wohl einfachste und dankbarste Anwendungsfall: Von R zu R.
Hier habt ihr zwei Möglichkeiten: `.rds` und `.rda` (auch `.RData`): Generell scheint `.rds` die präferierte Option zu sein.
#### `.rds`
Daten einlesen ist simpel:
```{r}
qmsurvey <- readRDS("data/qm_survey_ss2017.rds")
tibble::as_tibble(qmsurvey)
```
Wir benutzen hier das `tibble` package nur, damit der Datensatz kompakter angezeigt wird. Das ist für euch keine Notwendigkeit, aber ich empfehle es in der Regel gerne, weil euch so nicht die Konsole vollgeklatscht wird, wenn ihr euch euren Datensatz mal schnell anschauen wollt.
Daten speichern auch:
```r
saveRDS(datensatz, "pfad/zur/datei.rds")
```
Hier zum Beispiel der Datensatz zur Tutoriumsteilnahme, den ihr von <https://public.tadaa-data.de/data/participation.rds> runterladen könnt:
```r
participation <- readRDS("~/Downloads/participation.rds")
```
Alternativ könnt ihr das `readr`-package benutzen. Die Funktion daraus sieht fast gleich aus, und macht auch exakt das gleiche wie `readRDS`. Der einzige Grund für `read_rds` ist die Konsistenz der Funktionsnamen.
```r
library(readr)
participation <- read_rds("~/Downloads/participation.rds")
```
#### `.rda`, `.RData`
**Nein, ihr benutzt nicht `save` und `load` für einzelne Datensätze.**
Bei `.rda` bzw. `.RData`-Dateien ist zu beachten, dass diese den Namen des Objekts gleich mitspeichern, das heißt ihr müsst den eingelesenen Datensatz keinen Namen geben — der kommt schon mit der Datei.
Theoretisch kann so eine Datei auch mehrere Variablen enthalten, und wenn ihr zum Beispiel RStudio schließt und wieder öffnet, dann werden in der Zwischenzeit auch eure Variablen der aktuellen Session in Form einer `.RData`-Datei im Projektordner abgelegt und beim nächsten Start wieder eingelesen.
```r
load("pfad/zur/datei.rda")
# Oder…
load("pfad/zur/datei.RData")
```
Speichern:
```r
save(datensatz, file = "pfad/zur/Datei.rda")
```
### Excel (`.xlsx`)
- Benötigte packages: `readxl`
- Anstrengend? Manchmal. Aber wenn, dann *richtig*.
Wenn ihr ein sauberes (i.e. ohne Schnickschnak) Spreadsheet habt in dem auch wirklich nur eure Werte drinstehen, dann ist das Ganze recht simpel und ihr seid mit `readxl` auch gut bedient.
Wenn ihr einen dreckigen Haufen dampfender Menschenverachtung vor euch habt, dann… viel Spaß.
Es gibt da [das ein oder andere Projekt](https://github.com/rsheets/rexcel#rexcel) für die komplexeren Fälle, aber wenn ihr die Möglichkeit habt, macht es euch so einfach (und rechteckig) wie möglich.
### Google Sheets
- Benötigte packages: `googlesheets`
- Anstrengend? Meistens geht's ganz gut.
Wenn euch Excel zu unpraktisch ist, dann bietet sich [Google Sheets](https://www.google.com/sheets/about/) an. Es ist kostenlos, einfach und ausreichend mächtig für alles, was ihr so vorhaben könnten — mitunter weil ihr für alle komplexeren Sachen sowieso R benutzen wollt. Sheets ist praktisch wie Excel, nur halt in der Cloud<sup>TM</sup> und von Google, aber für überschaubare Datensammlungen reicht's auf alle Fälle. Die [Tutoriumsteilnahmedaten haben wir da auch gesammelt](https://qmparticipation.tadaa-data.de/), und da das Sheet immer an der selben Stelle ist muss man einfach nur den Code zum einlesen und auswerten erneut ausführen und schon hat man eine mehr oder weniger selbstupdatende Analyse. Nett.
In besagtem Projekt sieht das zum Beispiel so aus:
```r
participation_1 <- gs_title("Tutoriumsteilnehmer") %>%
gs_read(ws = "WS1516", range = cellranger::cell_cols(1:7))
```
Zuerst müsst ihr aber die Authentifizierung mit eurem Google-Account abhandeln:
```r
library(googlesheets)
gs_ls()
```
Mit diesem Befehl zeigt euch das package all eure Google Sheets an nachdem es euch nach einem Login gefragt hat, von da aus könnt ihr dann weiterarbeiten.
Mehr Informationen und Beispiele [gibt's in der Vignette](https://rawgit.com/jennybc/googlesheets/master/vignettes/basic-usage.html).
## Daten angucken & sauber machen
> Happy families are all alike; every unhappy family is unhappy in its own way.
>
> --- Leo Tolstoy
> and every messy data is messy in its own way - it's easy to define the characteristics of a clean dataset
> (rows are observations, columns are variables, columns contain values of consistent types).
> If you start to look atreal life
> data you'll see every way you can imagine data being messy (and many that you can't)!
>
> --- Hadley Wickham (answering 'in what way messy data sets are messy') R-help (January 2008)
Um festzustellen, ob eure frisch eingelesenen Daten auch brauchbar sind, empfiehlt sich ein Blick in die Daten via `View(daten)` bzw. Über einen Klick auf den Datensatz im *Environment*-Tab von RStudio (das da oben rechts).
Zusätzlich ist auch hier natürlich `str()` praktisch, um zum Beispiel schnell zu überprüfen, ob eure Variablen auch alle die Klasse haben, die ihr erwartet (alle Zahlen sind *numeric* und Nominaldaten sind *factor* oder wenigstens *character*).
Es gibt da kein one-size-fits-all Rezept zur Datenbereinigung, denn jeder Datensatz ist auf seine eigene Art dreckig. Ihr könnt nur darauf hoffen, dass euer konkreter Anwendungsfall gut googlebar ist, oder ihr sowas ähnliches schonmal gemacht habt.
Die gängigsten Probleme sind recoding, umbenennen oder zusammenfassen, und das meiste lässt sich entweder mit `dplyr`, `sjmisc` oder ggf. `tidyr` erledigen. Versucht es erstmal innerhalb des *tidyverse*, das ist vermutlich angenehmer als zusammengehackte Google-Lösungen. Aber auch hier, wie gesagt: Je nachdem was ihr vorhabt. Mehr dazu findet sich in [Data Munging].
Datenbereinigung ist entweder sehr einfach oder sehr komplex, oder irgendwo dazwischen. In diesem Sinne: Learning by example und so.
### Der NGO Datensatz
Der **NGO**-Datensatz aus dem *Kähler* ist seit längere _der_ default Übungsdatensatz und dementsprechend auch unfassbar langweilig für VeteranInnen. Zudem haben wir den Datensatz in sauber auch schon in der `tadaatoolbox`, das heißt, wenn ihr die toolbox ladet könnt ihr `ngo` direkt benutzen.
In der Vorlesung schwirrt darüberhinaus vermutlich eine SPSS (`.sav`)-Version des Datensatzes rum, die wir hier mal beispielshalber einlesen und bearbeiten, bis sie identisch zur `tadaatoolbox`-Version ist.
```{r ngo_einlesen}
library(haven)
ngo <- read_sav("data/NGO.SAV")
head(ngo)
```
Zuerst wollen wir mal die Variablen rauskicken, die wir nicht brauchen. In diesem Fall sind das die Variablen, die wir zu Übungszwecken sowieso selber erstellen wollen: `ZENG`, `ZDEUTSCH`, `ZMATHE`, `INDEX`, `LEIST`
```{r ngo_select}
library(dplyr)
ngo <- ngo %>%
select(-ZENG, -ZDEUTSCH, -ZMATHE, -INDEX, -LEIST)
head(ngo)
```
Besser. Als nächstes stört mich, dass die Variablennamen alle *UPPER CASE* sind. Ich will die alle in *lower case* haben. Dafür können wir die Funktion `tolower` benutzen.
```{r ngo_names}
names(ngo) <- tolower(names(ngo))
head(ngo)
```
Besser. Als nächstes wollen wir unsere Variablen labeln, zum Beispiel soll `geschl` nicht `1` oder `2` sagen, sondern `Männlich` und `Weiblich`.
```{r ngo_recode}
# Falls NA noch nicht korrekt kodiert:
ngo$hausauf <- ifelse(ngo$hausauf == 0, NA, ngo$hausauf)
ngo$abschalt <- ifelse(ngo$abschalt == 0, NA, ngo$abschalt)
ngo$geschl <- factor(ngo$geschl, labels = c("Männlich", "Weiblich"))
ngo$jahrgang <- factor(ngo$jahrgang, labels = c("11", "12", "13"), ordered = TRUE)
ngo$abschalt <- factor(ngo$abschalt, labels = c("Ja", "Nein"))
head(ngo)
```
Besser.
Hier haben wir `jahrgang` auch gleich zu einem `ordered factor` gemacht, damit die Reihenfolge der Merkmalsausprägungen immer intakt bleibt. Gegebenenfalls müssen wir das beachten, falls wir damit mal 'ne [ANOVA](#ANOVA) machen wollen, aber erstmal finden wir das so gut.
Zusätzlich solltet ihr beachten, dass Umlaute wie das `ä` in `Männlich` zwar auf eurem Computer lokal kein Problem sein sollten, solange ihr euch immer brav an **UTF-8** haltet, aber Windows handhabt Dinge da leider etwas anders als Linux und macOS, von daher könnte es sinnvoll sein für `"Männlich"` lieber `"M\\u00e4nnlich"` einzusetzen. Das ist der selbe Text, allerdings mit explizitem Unicode-Encoding. Es gibt Funktionen wie `stringi::stri_escape_unicode("Männlich")`, die die Konvertierung für euch machen, aber ich wünsche euch, dass ihr euch nie im Detail damit befassen müsst.
Als nächstes können wir noch *value labels* setzen, die dann in `sjPlot`-Plots und Tabellen angezeigt werden. Bei unseren frisch erstellten `factor`-Variablen ist das nicht mehr nötig, aber `hausauf` könnte welche gebrauchen:
```{r ngo_label_sj}
library(sjlabelled)
ngo$hausauf <- set_labels(ngo$hausauf,
labels = c("gar nicht", "weniger als halbe Stunde",
"halbe Stunde bis Stunde", "1 bis 2 Stunden",
"2 bis 3 Stunden", "3 bis 4 Stunden",
"mehr als 4 Stunden"))
ngo$hausauf
```
Als letztes können wir noch ein paar Variablen-Labels verteilen:
```{r ngo_var_labs}
ngo$geschl <- set_label(ngo$geschl, "Geschlecht")
ngo$abschalt <- set_label(ngo$abschalt, "Abschalten")
ngo$jahrgang <- set_label(ngo$jahrgang, "Jahrgang")
ngo$hausauf <- set_label(ngo$hausauf, "Hausaufgaben")
```
...Wir könnten noch mehr Labels verteilen, aber das sind so die Variablen, die am ehesten in Kontingenztabellen auftauchen, von daher reicht mir das so.
Fertig.
Sauber.
Wenn ihr den Datensatz so als Datei wegspeichern wollt, geht das einfach mit:
```r
saveRDS(ngo, "ngo.rds")
```
Der ganze Code zum Saubermachen in einem großen Blob:
```r
library(haven)
library(sjlabelled)
library(tibble)
library(dplyr)
# Einlesen
ngo <- read_sav("data/NGO.SAV")
# Variablen rauskicken
ngo <- ngo %>%
select(-ZENG, -ZDEUTSCH, -ZMATHE, -INDEX, -LEIST)
# Variablennamen in lower case
names(ngo) <- tolower(names(ngo))
# Recoding
# Falls NA noch nicht korrekt kodiert:
ngo$hausauf <- ifelse(ngo$hausauf == 0, NA, ngo$hausauf)
ngo$abschalt <- ifelse(ngo$abschalt == 0, NA, ngo$abschalt)
ngo$geschl <- factor(ngo$geschl, labels = c("Männlich", "Weiblich"))
ngo$jahrgang <- factor(ngo$jahrgang, labels = c("11", "12", "13"), ordered = TRUE)
ngo$abschalt <- factor(ngo$abschalt, labels = c("Ja", "Nein"))
# Value labelling
ngo$hausauf <- set_labels(ngo$hausauf,
labels = c("gar nicht", "weniger als halbe Stunde",
"halbe Stunde bis Stunde", "1 bis 2 Stunden",
"2 bis 3 Stunden", "3 bis 4 Stunden",
"mehr als 4 Stunden"))
# Variable labelling
ngo$geschl <- set_label(ngo$geschl, "Geschlecht")
ngo$abschalt <- set_label(ngo$abschalt, "Abschalten")
ngo$jahrgang <- set_label(ngo$jahrgang, "Jahrgang")
ngo$hausauf <- set_label(ngo$hausauf, "Hausaufgaben")
# Speichern als Datei
saveRDS(ngo, "ngo.rds")
```
```{r include=FALSE}
rm(ngo)
```