-
Notifications
You must be signed in to change notification settings - Fork 0
/
tidyverse_1.qmd
332 lines (233 loc) · 11.6 KB
/
tidyverse_1.qmd
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
---
title: "Tidyverse and NHANES"
format:
html:
toc: true
---
Vorlesung "Datenanalyse in der Biologie"
# Einführung zu Tidyverse
## Geschichte von R
R ist alt: Die erste Version wurde 1993 veröffentlicht, und war anfangs eine
"Kopie" von S, das seit 1976 entwickelt wurde. Viele Konstrukte sind daher
schon lange nicht mehr "state of the art". Andererseits wurde R immer wieder
modernisiert, und es wurden neue, bequemer zu benutzende Funktionen eingeführt,
um ältere, umständlichere oder weniger leistungsfähige Funktionen und Pakete zu
ersetzen -- ohne aber die alten Funktionen zu entfernen. Wenn man R-Code verstehen
will, hilft es daher oft, zu wissen, in welcher "geschichtlichen Schicht" man
sich bewegt.
## Tidyverse
Die "aktuelle Schicht" ist das "Tidyverse", entwickelt von Hadley Wickham, seit
ca. 2014 und weit verwendet seit ca. 2017.
"Tidyverse" ist ein Versuch, das "unordentlich" gewordene "Universum" der vielen
R-Funktionen aus verschiedenen Zeiten zu ersetzen. "Tidyverse" besteht aus einer
Reihe von Paketen, die einer einheitlichen und logischen Design-Philosophie
folgen.
Zentraler Datentyp in Tidyverse ist die Tabelle, die aber oft nicht (wie in "base R")
Data Frame genannt wird, sondern "tibble" (Kunstwort für "tidy table").
Das Buch "[R for Data Science](https://r4ds.hadley.nz/)" ("r4ds") dient als
Lehrbuch zur Datenanalyse mit R und Tidyverse.
Wir werden von nun an so weit wie möglich nur Tidyverse verwenden.
Um Tidyverse zu verwenden, muss es stets erst geladen werden:
```{r}
library( tidyverse )
```
## NHANES
Als Beispieldaten werden wir in der Vorlesung oft Ergebnisse der NHANES-Studie
des CDC nutzen. NHANES führt alle 2 Jahre eine Erhebung zur VOlksgesundheit durch, bei der
eine repräsentante Stichprobe von knapp 10,000 Einwohnern der USA befragt und
medizinisch untersucht werden. Näheres hier: https://www.cdc.gov/nchs/nhanes
Wir verwenden den Durchgang 2017/18 ("J"), spezifisch die Tabellen "DEMO_J" und
"BMX_J" mit demoghraphischen Daten und den Körpermaßen (Body Measures) der Probanden.
Ich habe einige Spalten ausgewählt und zusammengestellt in dieser Tabelle:
https://papagei.bioquant.uni-heidelberg.de/simon/Vl2021/nhanes.csv
Wir laden diese Datei mit der Tidyverse-Fuktion `read_csv`:
```{r}
nhanes <- read_csv( "Downloads/nhanes.csv")
```
Wir sehen uns die Tabelle an:
```{r}
nhanes
```
Eine Erklärung der Spalten findet sich hier: https://wwwn.cdc.gov/Nchs/Nhanes/2017-2018/BMX_J.htm
## Aufgabe
Laden Sie die Tabelle vom o.g. Link herunter und laden Sie sie in Ihre R-Sitzung.
Lassen Sie sich die Tabelle in RStudio anzeigen.
## Tidyverse-Verb "mutate"
In Tidyverse wandelt jeder ARbeitsschritt eine Tabelle in eine andere Tabelle um.
Zu jedem Schritt gehört ein "Tidyverse-Verb", d.h. eine Funktion, die eine Tibble als
erstes Argument verlangt und eine abgeänderte Tibble zurückgibt.
Das Tidyverse-Verb `mutate` ändert eine Spalte ab oder fügt eine neue Spalte hinzu.
### BMI
Wir möchten der Tabelle eine Spalte `bmi` mit dem Body Mass Index (BMI) hinzufügen. Der BMI ist wie folgt definiert:
$$ \text{BMI}=\frac{\text{Körpergewicht in kg}}{\text{(Körpergröße in m)}^2}. $$
Unsere Tabelle enthält die Größe in cm, daher müssen wir durch 100 teilen.
Wir schreiben also:
```{r}
mutate( nhanes, bmi = weight / (height/100)^2 )
```
## Piping
Den vorstehenden Befehl kann man auch so schreiben:
```{r}
nhanes %>% mutate( bmi = weight / (height/100)^2 )
```
Das Pipe-Zeichen `%>%` bedeutet hierbei: Nimm die Daten links vom Pfeil und füge sie in dem Funktionsaufruf rechts vom Pfeil als erstes Argument ein.
## Tidyverse-Verb "filter"
Die Tabelle hat 8704 Zeilen, enthält also Daten von 8704 Probanden. Wie viele davon sind erwachen, also min. 18 Jahre alt? Mit der tidyverse-Funktion filter können wir die Tabelle filtern, d.h. nur die Zeilen behalten, die eine gegebene Bedingung erfüllen, hier: Alter mindestens 18 Jahre.
```{r}
nhanes %>% filter( age >= 18 )
```
Die gefilterte Tabelle hat noch 5533 Zeilen. Der Anteil Erwachsener an der Gesamtzahl von Probanden beträgt also in Prozent:
```{r}
5533 / 8704 * 100
```
## Eine einfache Pipeline
Nun können wir fragen, wie viele dieser 5366 Erwachsenen übergewichtig sind. Wir verwenden hierzu die WHO-Definition, die Übergewicht als BMI>25 definiert.
```{r}
nhanes %>%
filter( age >= 18 ) %>%
mutate( bmi = weight / (height/100)^2 ) %>%
filter( bmi > 25 )
```
Hier habven wir nun eine kurze “Pipeline” gebaut, in der die Daten mit dem
**Pipe-Pfeil** `%>%` durch drei Arbeitsschritte hindurch geschoben werden:
- Wir beginnen mit der Tabelle, so wir sie geladen haben
- Dann filtern wir, um nur die Erwachsenen zu behalten
- Dann fügen wir die Spalte mit dem BMI hinzu
- Zuletzt filtern wir nochmals, um nur die Übergewichtigen zu behalten
Nun hat die Tabelle noch 3952 Zeilen
Der Anteil Übergewichtiger unter den erwachsenen Probanden ist also
```{r}
3952 / 5533
```
## Zuweisen einer Tabelle zu einer Variable
Wir haben uns eine Tabelle aller Erwachsenen Probanden erstellt
und diese durch eine BMI-Spalte ergänzt. Wir können diese modifizierte
Tabelle wieder in eine neue Variable zurückschreiben, indem wir den
Zuweisungs-Pfeil `->` verwenden:
```{r}
nhanes %>%
filter( age >= 18 ) %>%
mutate( bmi = weight / (height/100)^2 ) -> nhanes_adults
```
**Merke:** Wenn nichts anderes verlangt ist, gibt R das Ergebnis auf dem
Bildschirm aus und verwirft es dann. Wenn man es behalten will, muss man
es ausdrücklich eienr Variable zuweisen. Dann wird es aber nicht mehr
ausgegeben. Um den Inhalt der Variablen auszugeben, gibt man einfach
den Namen der Variablen ein und drückt Enter (oder Strg-Enter).
### Aufgabe
Bei einem BMI über 30 spricht wird Übergewicht als Krankheit (Adipositas,
Fettsucht, *obesity*) angesehen. Wie viele der Frauen und wie viele der
Männer sind adipös? Berechnen Sie die Prozentsätze, indem Sie die Tabelle
so filtern, dass Sie jeweils alle Männer, alle Frauen, alle adipösen Männer, alle
adipösen Frauen erhalten, notieren Sie die Anzahl der Zeilen und berechnen Sie
die Anteile in Prozent.
## Plots mit ggplot
In R gibt es verschiedene Pakete, um Daten zu visualisieren. Wir werden
"ggplot2" verwenden, dass wir Tidyverse von H. Wickham entwickelt wurde
und nun Teil des Tidyverse ist.
Der folgende Code erzeugt zwei Histogramme:
```{r}
nhanes_adults %>%
ggplot( aes( x=bmi ) ) +
geom_histogram( bins=50 ) +
facet_grid( rows="gender" ) +
scale_x_continuous( breaks=seq( 15, 80, 5 ) )
```
Hier erkennen Sie schon die allgemeine Form eines typischen `ggplot`-Aufrufs:
```r
tibble %>%
ggplot( aes( x=..., y=..., ... ) ) +
geom_...( ... ) +
...
```
- Am Anfang steht eine Tabelle, entweder aus einer Variablen gelesen, oder mit
einer Tidyverse-Pipeline erzeugt.
- Diese wird mit dem Pipe-Pfeil `%>%` zur Funktion `ggplot` gesandt.
- Die ggplot-Funktion hat ein Argument, das mit `aes` erzeugt wird.
- Innerhalb des `aes`-Blocks wird festgelegt, aus welchen Tabellenspalten
die Plot-Aspekte (z.B. x- und y-Koordinaten) entnommen werden sollen.
- Darauf folgen ggplot-Komponenten, die mit `+` hinzugefügt werden und Details
über den Plot spezifizieren.
- Mindestens eine Koponente muss eine `geom_`-Funktion sein. Die Geoms wandeln
Daten in Plot-Element um. Für jede Art von Plot gibt es ein zugehöriges Geom.
- Neben `geoms` gibt es noch weitere Dinge, die man mit `+` hinzufügen kann.
In unserem Beispiel:
- Wir möchten ein Histogramm, daher haben wir `+ geom_histogram` geschrieben.
- Für Histogramme brauch man nur eine `aes`-Spezifikation, nämlich, was die
x-Achse sein soll. Wir haben `x=bmi` gewählt, d.h. die Tabellenspalte `bmi`
soll durch die x-Achse repräsentiert werden.
- Der Wertebereich der x-Achse soll in 50 "Bins" aufgeteilt werden.
Als Besonderheit haben wir *Facetting* verwendet:
- Der Plot wird auf zwei Facets aufgeteilt, die untereinander (d.h. in zwei
"rows" angeordnet sind).
- Jede "row" ist für einen Teil der Daten zuständig, und zwar sollen die Daten
gemäß der Spalte "gender" auf die Facet-Rows aufgeteilt werden.
- Deshalb ist jede der beiden Rows am rechten rand mit einem der beiden Werte
in "gender", also "male" und "female" beschriftet.
## Viele Arten von Plots
Die [R Graph Gallery](https://r-graph-gallery.com/) zeigt anhand vieler Beispiele,
welche Art von Plots mit ggplot2 erzeugt werden können
## Streudiagramme
Streudiagramme (engl. scatte plots) stellen jeden Datenpunkt (jede Tabellenzeile)
durch einen Punkt dar. Da nun x- und y-Koordinate verfügbar sind, können wir
zwei Tabellen-Zeilen *gegeneinander* auftragen. Die Farbe des Punktes können
wir für eine dritte Spalte nutzen
Hier ein Beispiel:
```{r}
nhanes %>%
ggplot( aes( x=age, y=height, color=gender ) ) +
geom_point( size=.2 )
```
Können Sie hier wieder die Elemente eines ggplot-Aufrufs sehen?
Das Geom `geom_point` erwartet zwwi Zuweisungen im `aes`-Block, nämlich `x` und `y`.
Falls vorhanden, beachtet es auch noch weitere, z.B. `colour`.
## Hausaufgaben
### Experimentieren mit dem Histogramm
Betrachten Sie nochmal das Histogramm mit den BMI-Werten.
- Vergleichen Sie die beiden Histogramme. Was können Sie über die Unterschiede
zwischen Männern und Frauen in der Untersuchung ablesen?
- Was geschieht, wenn Sie das `+ facet_grid(...)` weglassen?
- Was geschieht, wenn Sie `+ scale_x_continuous( breaks=seq( 15, 80, 5 ) )`
anfügen?
- Was geschieht, wenn Sie statt `geom_histogram( bins = 50 )` einfach nur
`geom_histogram()` schreiben?
- Experimentieren Sie mit der Anzahl der Bins. Wie sieht das Histogramm mit nur
10 Bins, oder mit vielleicht 200 Bins aus? Was halten Sie für eine gute Anzahl?
### Non-finite values
Vielleicht haben Sie bemerkt, dass R beim Zeichnen des Histogramms warnt:
"Removed 99 rows containing non-finite values." Sehen Sie sich die Tabelle
an (z.B. in dem Sie sie in der Environment-Pane anklicken). Können Sie die 99
fehlerhaften Werte finden? Wo liegt das Problem?
Wenn Sie sie nicht finden: Schauen Sie sich z.B. den Probanden mit der
SubjectID 93935 an. Können Sie mit `filter` diese Zeile aus der Tabelle isolieren?
### Noch ein Streudiagramm
Hier sehen Sie zwei Darstellung der Daten aus der `murders`-Tabelle vom Dienstag.
Zunächst ein einfaches Streudiagramm:
```{r echo=FALSE}
library( dslabs )
murders %>%
mutate( cases_per_100k = total / population * 1e5 ) %>%
ggplot( aes( x=population, y=cases_per_100k, col=region, label=abb ) ) +
geom_point()
```
Nun eine verbesserte version desselben Plots:
```{r echo=FALSE}
library( dslabs )
murders %>%
mutate( cases_per_100k = total / population * 1e5 ) %>%
ggplot( aes( x=population, y=cases_per_100k, col=region, label=abb ) ) +
geom_text( size=3 ) + scale_x_log10() + xlab( "Einwohner" ) +
ylab( "Morde pro 100.000 Einwohner" ) + ggtitle( "Morde durch Feuerwaffen, 2010")
```
Versuchen Sie zunächst, den ersten Plot selbst zu erzeugen.
Wenn Sie wollen, können Sie versuchen, den Plot zu verschönern, um zum zweiten Diagramm zu kommen:
- Statt Punkten habe ich die Abkürzungen der Staaten verwendet (die in der Spalte `abb` stehen).
Hierzu habe ich `geom_point` durch `geom_text` ersetzt. Letzteres erwartet neben `x` und
`y` noch eine dritte `aes`-Angabe, nämlich `label`, d.h., die Spalte, aus der
die Beschriftungen entnommen werden sollen.
- Die Achsenbeschriftungen kann man mit `... + xlab( "Beschriftung" ) + ylab( "Bescriftung" )`
ändern. Mit `+ ggtitle( "Beschriftung" )` legt man eine Überschrift fest.
- Durch `+ scale_x_log10()` macht man die x-Achse logarithmisch.
Sehen Sie, wie weit Sie kommen und **laden Sie Ihren Plot auf Moodle hoch**. Benutzen
Sie dazu den "Export"-Button in der Plot-Pane, um Ihren Plot in eine Datei zu speichern,
die Sie auf Moodle hoch laden können.