-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy path050_Daten_visualisieren.Rmd
771 lines (477 loc) · 32.6 KB
/
050_Daten_visualisieren.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
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
# Daten visualisieren
```{r echo = FALSE, out.width = "30%", fig.align = "center"}
knitr::include_graphics("images/FOM.jpg")
```
```{r echo = FALSE, out.width = "10%", fig.align = "center"}
knitr::include_graphics("images/licence.png")
```
```{block2, ziele-vis, type='rmdcaution', echo = TRUE}
Lernziele:
- An einem Beispiel erläutern können, warum/ wann ein Bild mehr sagt, als 1000 Worte.
- Häufige Arten von Diagrammen erstellen können.
- Diagramme bestimmten Zwecken zuordnen können.
```
In diesem Kapitel werden folgende Pakete benötigt:
```{r libs_visualisieren}
library(tidyverse) # Zum Plotten
library(ggplot2movies) # Daten 'movies'
# library(prada) # optional: Daten 'wo_men', 'stats'test'
# library(AER) # optional: Daten 'Affairs'
# library(okcupiddata) # optional: Daten 'profiles'
```
```{r libs-hidden-vis, echo = FALSE}
library(gridExtra)
```
```{r plot-vis, echo = FALSE}
knitr::include_graphics("images/visualisieren/Visualisieren.png")
```
Dieses Kapitel erläutert das Daten visualisieren anhand des R-Pakets `ggplot2`.
## Ein Bild sagt mehr als 1000 Worte
Ein Bild sagt bekanntlich mehr als 1000 Worte. Schauen wir uns zur Verdeutlichung das berühmte Beispiel von Anscombe^[https://de.wikipedia.org/wiki/Anscombe-Quartett] an. Es geht hier um vier Datensätze mit zwei Variablen (Spalten; X und Y). Offenbar sind die Datensätze praktisch identisch: Alle X haben den gleichen Mittelwert und die gleiche Varianz; dasselbe gilt für die Y. Die Korrelation zwischen X und Y ist in allen vier Datensätzen gleich. Allerdings erzählt eine Visualisierung der vier Datensätze eine ganz andere Geschichte.
```{r fig-anscombe, echo = FALSE, fig.cap = "Das Anscombe-Quartett"}
knitr::include_graphics("images/visualisieren/anscombe.png")
```
Offenbar "passieren" in den vier Datensätzen gänzlich unterschiedliche Dinge. Dies haben die Statistiken nicht aufgedeckt; erst die Visualisierung erhellte uns... Kurz: Die Visualisierung ist ein unverzichtbares Werkzeug, um zu verstehen, was in einem Datensatz (und damit in der zugrunde liegenden "Natur") passiert.
Eine coole Variante mit der gleichen Botschaft findet sich [hier](https://www.autodeskresearch.com/publications/samestats) bzw. mit einer Animation [hier](https://d2f99xq7vri1nk.cloudfront.net/DinoSequentialSmaller.gif); vgl. -@matejka2017same.
Es gibt viele Möglichkeiten, Daten zu visualisieren (in R). Wir werden uns hier auf einen Weg bzw. ein Paket konzentrieren, der komfortabel, aber mächtig ist und gut zum Prinzip des Durchpfeifens passt: `ggplot2`^["gg" steht für "grammer of graphics" nach einem Buch von Wilkinson[-@wilkinson2006grammar]; "plot" steht für "to plot", also ein Diagramm erstellen ("plotten"); vgl. https://en.wikipedia.org/wiki/Ggplot2].
## Die Anatomie eines Diagramms
`ggplot2` unterscheidet folgende Bestandteile ("Anatomie") eines Diagramms (vgl. Abb. \@ref(fig:fig-anatomie)):
- Daten
- Abbildende Aspekte (Achsen, Farben, ...)
- Geome (statistische Bilder wie Punkte, Linien, Boxplots, ...)
```{r fig-anatomie, echo = FALSE, fig.cap = "Anatomie eines Diagramms"}
knitr::include_graphics("images/visualisieren/anatomie_diagramm_crop.jpg")
```
Bei *Daten* muss ein Dataframe angegeben werden. Zu den *abbildenden Aspekte* (in `ggplot2` als "aesthetics" bzw. `aes` bezeichnet) zählen vor allem die Achsen, aber auch Farben u.a. Was ist mit abbildend gemeint? Weist man einer Achse einen Variable zu, so wird jede Ausprägung der Variablen einer Ausprägung der Achse zugeordnet (welcher Wert genau entscheidet `ggplot2` für uns, wenn wir es nicht explizieren). Mit *Geom* ist das eigentlich Art von "Bild" gemeint, wie Punkt, Linie oder Boxplot (vgl. Abschnitt \@ref(geome)).
> Erstellt `ggplot2` ein Diagramm, so ordnet es Spalten den Bestandteilen des zu erzeugenden Diagramms zu (auch "mapping" genannt).
## Einstieg in `ggplot2` - `qplot`
Los geht's! Laden wir zuerst den Datensatz `movies`.
```{r}
data(movies, package = "ggplot2movies")
```
Betrachten Sie zum Einstieg das Diagramm \@ref(fig:figmovies):
1. Welche Variable steht auf der X-Achse?
2. Welche Variable steht auf der Y-Achse?
3. Was wird gemalt? Linien, Boxplots, Punkte?
4. Wie heißt der Datensatz, aus dem die Daten gezogen werden?
Der Befehl, der dieses Diagramm erzeugte, heißt `qplot`. Es ist ziemlich genau die Antwort auf die Übungsfragen von gerade eben:
```{r figmovies, message = FALSE, fig.cap = "Mittleres Budget pro Jahr"}
qplot(x = year,
y = budget,
geom = "point",
data = movies)
```
Schauen wir uns den Befehl `qplot` etwas näher an. Wie ist er aufgebaut?
```{block2, qplot-syntax, type='rmdpseudocode', echo = TRUE}
`qplot`: Erstelle schnell (q wie quick in `qplot`) mal einen Plot (engl. "plot": Diagramm).
`x`: Der X-Achse soll die Variable "year" zugeordnet werden.
`y`: Der Y-Achse soll die Variable "budget" zugeorndet werden.
`geom`: ("geometriches Objekt") Gemalt werden sollen Punkte und zwar pro Beobachtung (hier: Film) ein Punkt; nicht etwa Linien oder Boxplots.
`data`: Als Datensatz bitte `movies` verwenden.
```
Offenbar geht die Schwere in den Budgets auseinander; außerdem scheint das Budget größer zu werden. Genau kann man es aber schlecht erkennen in diesem Diagramm. Besser ist es vielleicht die Daten pro Jahr zusammenzufassen in einem Geom und dann diese Geome zu vergleichen:
```{r}
qplot(x = factor(year),
y = budget,
geom = "boxplot",
data = movies)
```
Übrigens: `factor(year)` wird benötigt, um aus `year` eine nominalskalierte Variable zu machen. Nur bei nominalskalierten Variablen auf der X-Achse zeichnet `qplot` mehrere Boxplots nebeneinander. `qplot` bzw. `ggplot2` denkt sich: "Hey, nur wenn es mehrere Gruppen gibt, macht es Sinn, die Gruppen anhand von Boxplots zu vergleichen. Also brauchst du eine Gruppierungsvariable - Faktor oder Text - auf der X-Achse!".
Es sind zu viele Jahre, das macht das Diagramm unübersichtlich. Besser wäre es, Jahrzehnte dazustellen. Ein Jahrzehnt ist so etwas wie eine Jahreszahl, von der die letzte Ziffer abgeschnitten (d.h. durch 10 teilen und runden) und dann durch eine Null ersetzt wurde (d.h. mit 10 multiplizieren):
```{r}
movies %>%
mutate(Jahrzehnt = year / 10) %>%
mutate(Jahrzehnt = trunc(Jahrzehnt)) %>% # trunkieren, abrunden
mutate(Jahrzehnt = Jahrzehnt * 10) -> movies
```
Schauen Sie sich die ersten Werte von `Jahrzehnt` mal an:
`movies %>% select(Jahrzehnt) %>% head`.
Ok, auf ein neues Bild (Abb. \@ref(fig:fig-movies-jahrzehnt)):
```{r fig-movies-jahrzehnt, fig.cap = "Film-Budgets über die die Jahrzehnte"}
qplot(x = factor(Jahrzehnt),
y = budget,
geom = "boxplot",
data = movies)
```
Aha, gut. Interessanterweise sanken die Budgets gegen Ende unserer Datenreihe; das ist aber vielleicht nur ein Zufallsrauschen.
"q" in `qplot` steht für "quick". Tatsächlich hat `qplot` einen großen Bruder, `ggplot`^[Achtung: Nicht `qqplot`, nicht `ggplot2`, nicht `gplot`...], der deutlich mehr Funktionen aufweist - und daher auch die umfangreichere (komplexere) Syntax. Fangen wir mit `qplot` an.
Diese Syntax des letzten Beispiels ist recht einfach, nämlich:
```{r, eval = FALSE}
qplot (x = X_Achse,
y = Y_Achse,
data = mein_dataframe,
geom = "ein_geom")
```
Wir definieren mit `x`, welche Variable der X-Achse des Diagramms zugewiesen werden soll, z.B. `month`; analog mit Y-Achse. Mit `data` sagen wir, in welchem Dataframe die Spalten "wohnen" und als "geom" ist die Art des statistischen "*geom*etrischen Objects" gemeint, also Punkte, Linien, Boxplots, Balken...
## Häufige Arten von Diagrammen
Unter den vielen Arten von Diagrammen und vielen Arten, diese zu klassifizieren greifen wir uns ein paar häufige Diagramme heraus und schauen uns diese der Reihe nach an.
### Eine kontinuierliche Variable
Schauen wir uns die Verteilung von Filmbudgets aus `movies` an (s. Abb. \@ref(fig:fig-budget-movies)).
```{r fig-budget-movies, fig.cap = "Verteilung des Budgets von Filmen"}
qplot(x = budget, data = movies)
```
Weisen wir nur der X-Achse (aber nicht der Y-Achse) eine kontinuierliche Variable zu, so wählt `ggplot2` automatisch als Geom automatisch ein Histogramm; wir müssen daher nicht explizieren, dass wir ein Histogramm als Geom wünschen (aber wir könnten es hinzufügen).
```{block2, euler, type='rmdcaution', echo = TRUE}
Was heißt das kleine 'e', das man bei wissenschaftlichen Zahlen hin und wieder sieht (wie im Diagramm \@ref(fig:fig-budget-movies))?
Zum Beispiel: `5.0e+07`. Das $e$ sagt, wie viele Stellen im Exponenten (zur Basis 10) stehen: hier $10^{07}$. Eine große Zahl - eine $1$ gefolgt von *sieben* Nullern: 10000000. Die schöne Zahl soll noch mit 5 multipliziert werden: also 50000000. Bei so vielen Nullern kann man schon mal ein Flimmern vor den Augen bekommen... Daher ist die "wissenschaftliche" Notation ganz praktisch, wenn die Zahlen sehr groß (oder sehr klein) werden. Sehr kleine Zahlen werden mit dieser Notation so dargestellt: `5.0e-07` heißt $frac{1}{10^7}$. Eine Zahl sehr nahe bei Null. Das Minuszeichen zeigt hier, dass wir den Kehrwert der großen Zahl nehmen sollen.
```
Alternativ wäre ein Dichtediagramm hier von Interesse:
```{r echo = FALSE}
wo_men <- read.csv("data/wo_men.csv")
```
```{r}
qplot(x = budget, data = movies, geom = "density")
```
Was man sich merken muss, ist, dass hier nur das Geom mit Anführungsstrichen zu benennen ist, die übrigen Parameter *ohne*.
Vielleicht wäre es noch schön, beide Geome zu kombinieren in einem Diagramm. Das ist etwas komplizierter; wir müssen zum großen Bruder `ggplot` umsteigen, da `qplot` nicht diese Funktionen anbietet.
```{r}
ggplot(data = movies) +
aes(x = budget) +
geom_histogram(aes(y = ..density..), alpha = .7) +
geom_density(color = "blue")
```
Zuerst haben wir mit dem Parameter `data` den Dataframe benannt. `aes` definiert, welche Variablen welchen Achsen (oder auch z.B. Füllfarben) zugewiesen werden. Hier sagen wir, dass die Schuhgröße auf X-Achse stehen soll. Das `+`-Zeichen trennt die einzelnen Bestandteile des `ggplot`-Aufrufs voneinander. Als nächstes sagen wir, dass wir gerne ein Histogram hätten: `geom_histogram`. Dabei soll aber nicht wie gewöhnlich auf der X-Achse die Häufigkeit stehen, sondern die Dichte. `ggplot` berechnet selbständig die Dichte und nennt diese Variable `..density..`; die vielen Punkte sollen wohl klar machen, dass es sich nicht um eine "normale" Variable aus dem eigenen Datenframe handelt, sondern um eine "interne" Variable von `ggplot` - die wir aber nichtsdestotrotz verwenden können. `alpha` bestimmt die "Durchsichtigkeit" eines Geoms; spielen Sie mal etwas damit herum. Schließlich malen wir noch ein blaues Dichtediagramm *über* das Histogramm.
Wünsche sind ein Fass ohne Boden... Wäre es nicht interessant, einzelne Zeiträume (Jahrzehnte) zu vergleichen? Schauen wir uns die letzten Jahrzehnte im Vergleich an.
```{r}
movies2 <- filter(movies, Jahrzehnt > 1980)
movies2 %>%
mutate(Jahrzehnt = factor(.$Jahrzehnt)) -> movies2
qplot(x = budget,
data = movies2,
geom = "density",
fill = Jahrzehnt,
alpha = I(.7))
```
`qplot` erwartet immer *Variablen* als Parameter; wollen wir mal keine Variable, sondern eine fixen Wert, wie 0.7, übergeben, so können wir das mit dem Befehl `I` (wie "identity") tun.
Hier sollten vielleicht noch die Extremwerte entfernt werden, um den Blick auf das Gros der Werte nicht zu verstellen:
```{r}
movies2 %>%
filter(budget < 1e08) -> movies2
qplot(x = budget,
data = movies2,
geom = "density",
fill = Jahrzehnt,
alpha = I(.7))
```
Besser. Man kann das Durchpfeifen auch bis zu `qplot` weiterführen:
```{r}
movies %>%
filter(budget < 1e+08, Jahrzehnt >= 1990) %>%
mutate(Jahrzehnt = factor(Jahrzehnt)) %>%
qplot(x = budget, data = ., geom = "density",
fill = Jahrzehnt, alpha = I(.7))
```
Die Pfeife versucht im Standard, das Endprodukt des letzten Arbeitsschritts an den *ersten* Parameter des nächsten Befehls weiterzugeben. Ein kurzer Blick in die Hilfe von `qplot` zeigt, dass der erste Parameter nicht `data` ist, sondern `x`. Daher müssen wir explizit sagen, an welchen Parameter wir das Endprodukt des letzen Arbeitsschritts geben wollen. Netterweise müssen wir dafür nicht viel tippen: Mit einem schlichten Punkt `.` können wir sagen "nimm den Dataframe, so wie er vom letzten Arbeitsschritt ausgegeben wurde".
Mit `fill = Jahrzehnt` sagen wir `qplot`, dass er für jedes Jahrzehnt jeweils ein Dichtediagramm erzeugen soll; jedem Dichtediagramm wird dabei eine Farbe zugewiesen (die uns `ggplot2` im Standard voraussucht). Mit anderen Worten: Die Werte von `Jahrzehnt` werden der *Füllfarbe* der Histogramme zugeordnet. Anstelle der Füllfarbe hätten wir auch die Linienfarbe verwenden können; die Syntax wäre dann: `color = sex`. Man beachte, dass die Variable für `fill` oder `color` eine nominale Variable (`factor` oder `character`) sein muss, damit `ggplot2` tut, was will wollen.
### Zwei kontinuierliche Variablen
Ein Streudiagramm ist die klassische Art, zwei metrische Variablen darzustellen. Das ist mit `qplot` einfach:
```{r}
p <- qplot(x = budget, y = rating, data = movies2)
p
```
Wir weisen wieder der X-Achse und der Y-Achse eine Variable zu; handelt es sich in beiden Fällen um Zahlen, so wählt `ggplot2` automatisch ein Streudiagramm - d.h. Punkte als Geom (`geom = "point"`).
Es ist nicht wirklich ein Trend erkennbar: Teuere Filme sind nicht unbedingt beliebter bzw. besser bewertet. Zeichnen wir eine Trendgerade ein.
```{r}
p + geom_smooth(method = "lm")
```
Synonym könnten wir auch schreiben:
```{r eval = FALSE}
wo_men %>%
filter(height > 150, height < 210, shoe_size < 55) %>%
ggplot() +
aes(x = height, y = shoe_size) +
geom_point() +
geom_smooth(method = "lm")
```
Da `ggplot` als *ersten* Parameter die Daten erwartet, kann die Pfeife hier problemlos durchgereicht werden. *Innerhalb* eines `ggplot`-Aufrufs werden die einzelne Teile durch ein Pluszeichen `+` voneinander getrennt. Nachdem wir den Dataframe benannt haben, definieren wir die Zuweisung der Variablen zu den Achsen mit `aes` ("aes" wie "aesthetics", also das "Sichtbare" eines Diagramms, die Achsen etc., werden definiert). Ein "Smooth-Geom" ist eine Linie, die sich schön an die Punkte anschmiegt, in diesem Falls als Gerade (lineares Modell, `lm`).
Bei sehr großen Datensätze, sind Punkte unpraktisch, da sie sich überdecken ("overplotting"). Ein Abhilfe ist es, die Punkte nur "schwach" zu färben. Dazu stellt man die "Füllstärke" der Punkte über `alpha` ein: `geom_point(alpha = 1/100)`. Um einen passablen Alpha-Wert zu finden, bedarf es häufig etwas Probierens. Zu beachten ist, dass es mitunter recht lange dauert, wenn `ggplot` viele (>100.000) Punkte malen soll.
Probieren Sie auch Folgendes aus: Fügen Sie bei `aes` den Parameter `color = sex` hinzu.
Bei noch größeren Datenmengen bietet sich an, den Scatterplot als "Schachbrett" aufzufassen, und das Raster einzufärben, je nach Anzahl der Punkte pro Schachfeld; zwei Geome dafür sind `geom_hex()` und `geom_bin2d()`.
```{r flights_hexbin}
nrow(movies) # groß, ein bisschen wenigstens
ggplot(movies) +
aes(x = year, y = budget) +
geom_hex()
```
Wenn man dies verdaut hat, wächst der Hunger nach einer Aufteilung in Gruppen.
```{r fig-aes-color}
wo_men %>%
dplyr::filter(height > 150, height < 210, shoe_size < 55) -> wo_men2
wo_men2 %>%
qplot(x = height, y = shoe_size, color = sex, data = .)
```
Mit `color = sex` sagen wir, dass die Linienfarbe (der Punkte) entsprechend der Stufen von `sex` eingefärbt werden sollen. Die genaue Farbwahl übernimmt `ggplot2` für uns.
Alternativ kann man auch zwei "Teil-Bildchen" ("facets") erstellen, eines für Frauen und eines für Männer:
```{r}
wo_men %>%
dplyr::filter(height > 150, height < 210, shoe_size < 55) %>%
qplot(x = height, y = shoe_size, facets = "~sex", color = sex, data = .)
```
Man beachte die Tilde `~`, die vor die "Gruppierungsvariable" `sex` zu setzen ist.
### Eine nominale Variable
Bei nominalen Variablen, geht es in der Regel darum, Häufigkeiten auszuzählen. Ein Klassiker: Wie viele Männer und Frauen finden sich in dem Datensatz? Wie viele Studenten haben (nicht) bestanden?
```{r}
stats_test <- read.csv("data/stats_test.csv")
qplot(x = bestanden, data = stats_test)
```
Falls nur die X-Achse definiert ist und dort eine Faktorvariable oder eine Textvariable steht, dann nimmt `qplot` automatisch ein Balkendiagramm als Geom (es steht uns frei, trotzdem `geom = bar` anzugeben).
Wir könnten uns jetzt die Frage stellen, wie viele Nicht-Interessierte und Hoch-Interessierte es in der Gruppe, die bestanden hat (`bestanden == "yes"`) gibt; entsprechend für die Gruppe, die nicht bestanden hat.
```{r}
qplot(x = bestanden, fill = factor(interest), data = stats_test)
```
Hier haben wir `qplot` gesagt, dass der die Balken entsprechend der Häufigkeit von `interest` füllen soll. Damit `qplot` (und `ggplot`) sich bequemt, die Füllung umzusetzen, müssen wir aus `interet` eine nominalskalierte Variablen machen - `factor` macht das für uns.
Schön wäre noch, wenn die Balken Anteile (Prozentwerte) angeben würden. Das geht mit `qplot` (so) nicht; wir schwenken auf `ggplot` um. Und, um die Story zuzuspitzen, schauen wir uns nur die Extremwerte von `interest` an.
```{r}
stats_test %>%
filter(interest == 1 | interest == 6) %>%
ggplot() +
aes(x = bestanden, fill = factor(interest)) +
geom_bar(position = "fill")
```
Der Lehrer freut sich: In der Gruppe, die bestanden hat, ist der Anteil der ~~freaks~~ Hoch-Interessierten größer als bei den Durchfallern.
Schauen wir uns die Struktur des Befehls `ggplot` näher an.
```{block2, ggplot-syntax, type='rmdpseudocode', echo = TRUE}
`stats_test`: Hey R, nimm den Datensatz `stats_test` UND DANN...
`ggplot()` : Hey R, male ein Diagramm von Typ `ggplo`t (mit dem Datensatz aus dem vorherigen Pfeifen-Schritt, d.h. aus der vorherigen Zeile, also `stats_test`)!
`filter`: wir wollen nur Zeilen (Studenten), für die gilt `interest == 1` oder `interest == 6`. Der horizontale Strich heißt 'oder'.
`+`: Das Pluszeichen grenzt die Teile eines ggplot-Befehls voneinander ab.
`aes`: von "aethetics", also welche Variablen des Datensatzes den sichtbaren Aspekten (v.a. Achsen, Farben) zugeordnet werden.
`x`: Der X-Achse (Achtung, `x` wird klein geschrieben hier) wird die Variable `bestanden` zugeordnet.
`y`: gibt es nicht??? Wenn in einem ggplot-Diagramm *keine* Y-Achse definiert wird, wird ggplot automatisch ein Histogramm bzw. ein Balkendiagramm erstellen. Bei diesen Arten von Diagrammen steht auf der Y-Achse keine eigene Variable, sondern meist die Häufigkeit des entsprechenden X-Werts (oder eine Funktion der Häufigkeit, wie relative Häufigkeit).
`fill` Das Diagramm (die Balken) sollen so gefüllt werden, dass sich die Häufigkeit der Werte von `interest` darin widerspiegelt.
`geom_XYZ`: Als "Geom" soll ein Balken ("bar") gezeichnet werden. Ein Geom ist in ggplot2 das zu zeichnende Objekt, also ein Boxplot, ein Balken, Punkte, Linien etc. Entsprechend wird gewünschte Geom mit `geom_bar`, `geom_boxplot`, geom_point` etc. gewählt.
`position = fill`: `position_fill` will sagen, dass die Balken alle eine Höhe von 100% (1) haben, d.h. gleich hoch sind. Die Balken zeigen also nur die Anteile der Werte der `fill`-Variablen.
```
Die einzige Änderung in den Parametern ist `position = "fill"`. Dieser Parameter weist `ggplot` an, die Positionierung der Balken auf die Darstellung von Anteilen auszulegen. Damit haben alle Balken die gleiche Höhe, nämlich 100% (1). Aber die "Füllung" der Balken schwankt je nach der Häufigkeit der Werte von `groesse_gruppe` pro Balken (d.h. pro Wert von `sex`).
Wir sehen, dass die Anteile von großen bzw. kleinen Menschen bei den beiden Gruppen (Frauen vs. Männer) *unterschiedlich hoch* ist. Dies spricht für einen *Zusammenhang* der beiden Variablen; man sagt, die Variablen sind *abhängig* (im statistischen Sinne).
> Je unterschiedlicher die "Füllhöhe", desto stärker sind die Variablen (X-Achse vs. Füllfarbe) voneinander abhängig (bzw. desto stärker der Zusammenhang).
### Zwei nominale Variablen
Arbeitet man mit nominalen Variablen, so sind Kontingenztabellen Täglich Brot. Z.B.: Welche Produkte wurden wie häufig an welchem Standort verkauft? Wie viele Narzissten gibt es in welcher Management-Stufe? Wie ist die Verteilung von Alkoholkonsum und Körperform bei Menschen einer Single-Börse?. Bleiben wir bei letztem Beispiel.
```{r}
data(profiles, package = "okcupiddata")
profiles %>%
dplyr::count(drinks, body_type) %>%
ggplot +
aes(x = drinks, y = body_type, fill = n) +
geom_tile() +
theme(axis.text.x = element_text(angle = 90))
```
Was haben wir gemacht? Also:
```{block2, fliesen-plot, type='rmdpseudocode', echo = TRUE}
Nehme den Datensatz "profiles" UND DANN
Zähle die Kombinationen von "drinks" und "body_type" UND DANN
Erstelle ein ggplot-Plot UND DANN
Weise der X-Achse "drinks" zu, der Y-Achse "body_type" und der Füllfarbe "n" UND DANN
Male Fliesen UND DANN
Passe das Thema so an, dass der Winkel für Text der X-Achse auf 90 Grad steht.
```
Diese Art von Diagramm nennt man auch 'Mosaicplot', weil es an ein Mosaic erinnert (wer hätt's gedacht).
Was sofort ins Auge sticht, ist dass "soziales Trinken", nennen wir es mal so, am häufigsten ist, unabhängig von der Körperform. Ansonsten scheinen die Zusammenhäng nicht sehr stark zu sein.
### Zusammenfassungen zeigen
Manchmal möchten wir *nicht* die Rohwerte einer Variablen darstellen, sondern z.B. die Mittelwerte pro Gruppe. Mittelwerte sind eine bestimmte *Zusammenfassung* einer Spalte; also fassen wir zuerst die Körpergröße zum Mittelwert zusammen - gruppiert nach Geschlecht.
```{r}
stats_test %>%
group_by(bestanden) %>%
summarise(interest_mw = mean(interest, na.rm = TRUE)) -> stats_test_summary
stats_test_summary
```
Diese Tabelle schieben wir jetzt in `ggplot2`; natürlich hätten wir das gleich in einem Rutsch durchpfeifen können.
```{r}
stats_test_summary %>%
qplot(x = bestanden, y = interest_mw, data = .)
```
Das Diagramm besticht nicht durch die Tiefe und Detaillierung. Bereichern wir das Diagramm um die Frage, wie viel (jeder Student gelernt hat (`study_time`). Schauen wir uns aber der Einfachheit halber nur die Studenten an, die ganz viel oder ganz wenig gelernt haben.
```{r}
stats_test %>%
group_by(bestanden, study_time) %>%
summarise(interest_mw = mean(interest, na.rm = TRUE)) %>%
qplot(x = bestanden, y = interest_mw, data = ., color = factor(study_time)) +
geom_line(aes(group = factor(study_time)))
```
In Pseudosyntax:
```{block2, summary-plot, type='rmdpseudocode', echo = TRUE}
Nehme den Datensatz "stats_test" UND DANN
gruppiere nach den Variablen `bestanden` und `study_time` UND DANN
fasse für diese Gruppen jeweils die Spalte `interest` zum Mittelwert zusammen UND DANN
male einen schnellen Plot mit diesen Daten UND DANN
füge ein Liniendiagramm dazu, wobei jede Stufe von `study_time` eine Gruppe ist. Und Punkte einer Gruppe sollen verbunden werden.
```
Warum steht der arme pinkfarbene Punkt bei 'ja' und ~4.5 so für sich alleine oder Linie?^[es gibt kein `study_time == 5` bei den Durchfallen, d.h. bei `bestanden == nein`.]
Alternativ, und deutlich informationsreicher (besser) sind hier Boxplots.
```{r}
qplot(x = bestanden,
y = interest,
data = stats_test,
geom = "boxplot")
```
Hm, wie Sie sehen, sehen Sie nix. Kein Unterschied im Median zwischen den Gruppen. Vergleichen wir mal die Punkte zwischen den einzelnen Interessenstufen.
```{r}
qplot(x = factor(interest),
y = score,
data = stats_test,
geom = "boxplot")
```
Das `factor(interest)` brauchen wir, weil `ggplot2` nur dann mehrere Boxplots malt, wenn es Gruppen zum Vergleichen (auf der X-Achse) gibt - sprich wenn auf der X-Achse eine Faktor- oder Textvariable steht.
### Überblick zu häufigen Diagrammtypen
Die Tabelle \@ref(tab:diagrammtypen) und Abbildung \@ref(fig:fig-diagrammtypen) fassen die gerade besprochenen Diagrammtypen zusammen.
```{r diagrammtypen, echo = FALSE}
df <- read_csv("includes/Diagrammtypen.csv")
# library(pander)
# pander::cache.off()
# panderOptions("table.alignment.default", "left")
# pander::pander(df, caption = "Häufige Diagrammtypen")
knitr::kable(df, caption = "Häufige Diagrammtypen")
```
```{r fig-diagrammtypen, echo = FALSE, fig.cap = "Überblick zu häufigen Diagrammtypen", out.width = "100%"}
p1 <- qplot(x = score, geom = "histogram", data = stats_test, main = "Histogramm") + theme(legend.position = "none")
p2 <- qplot(x = score, geom = "density", data = stats_test, main = "Dichte-D.") + theme(legend.position = "none")
p3 <- qplot(y = score, x = self_eval, geom = "point", data = stats_test, main = "Streu-D.") + theme(legend.position = "none")
p4 <- qplot(y = score, x = self_eval, fill = bestanden, geom = "tile", data = stats_test, main = "Fliesen-D.") + theme(legend.position = "none")
p5 <- qplot(x = bestanden, geom = "bar", data = stats_test, main = "Balken-D.") + theme(legend.position = "none")
p6 <- stats_test %>%
mutate(interessiert = stats_test$interest > 3) %>%
count(bestanden, interessiert) %>%
qplot(x = bestanden, y = interessiert, fill = n, geom = "tile", data = ., main = "Fliesen-D.") + theme(legend.position = "none")
p7 <- stats_test %>%
mutate(interessiert = stats_test$interest > 3) %>%
group_by(bestanden, interessiert) %>%
summarise(score_median_gruppe = median(score)) %>%
qplot(data = ., x = bestanden, y = score_median_gruppe, color = interessiert, size = I(4), shape = interessiert, main = "Punkte-D.") + theme(legend.position = "none")
p8 <- qplot(x = bestanden, y = score, geom = "boxplot", data = stats_test, main = "Boxplot") + theme(legend.position = "none")
grid.arrange(p1, p2, p3, p4, p5, p6, p7, p8, nrow = 3)
```
## Die Gefühlswelt von `ggplot2`
- Geben Sie eine *diskrete X-Achs*e an und *keine Y-Achse*, so greift `qplot` im Standard auf das Geom `bar` zurück (Balkendiagramm), falls Sie *kein* Geom angeben:
```{r eval = FALSE}
qplot(x = score, data = stats_test) # identisch zu
qplot(x = score, data = stats_test, geom = "bar")
```
- Geben Sie eine *kontinuierliche X-Achse* an und *keine Y-Achse*, so greift qplot im Standard auf das Geom `histogram` zurück (Histogramm).
```{r eval = FALSE}
qplot(x = score, data = stats_test) # identisch zu
qplot(x = score, data = stats_test, geom = "histogram")
```
- Geben Sie eine *kontinuierliche X-Achse* an und eine *kontinuierliche Y-Achse* an, so greift qplot im Standard auf das Geom `point` zurück (Streudiagramm).
```{r eval = FALSE}
qplot(x = score, y = self-eval, data = stats_test) # identisch zu
qplot(x = score, y= self-eval, data = stats_test, geom = "point")
```
- Möchten Sie mehrere Geome für eine Variable darstellen, so muss die Gruppierungs-Variable diskret sein:
```{r eval = FALSE}
#oh no:
qplot(x = rating, y = affairs, geom = "boxplot", data = Affairs)
#oh yes:
qplot(x = factor(rating), y = affairs, geom = "boxplot", data = Affairs)
#oh yes:
qplot(x = gender, y = affairs, geom = "boxplot", data = Affairs)
```
## Aufgaben
1. Erzählen Sie einer vertrauenswürdigen Person jeweils eine "Geschichte", die das Zustandekommen der vier Plots von Anscombe (Abb. \@ref(fig:fig-anscombe)) erklärt!
1. Abb. \@ref(fig:fig-movies-jahrzehnt) stellt das mittlerer Budget von Filmen dar; als "Geom" wird ein Boxplot verwendet. Andere Geome wären auch möglich - aber wie sinnvoll wären sie?
1. Erstellen Sie ein Diagramm, welches Histogramme der Verspätung verwendet anstelle von Boxplots! Damit das Diagramm nicht so groß wird, nehmen Sie zur Gruppierung nicht `carrier` sondern `origin`.
1. Ist das Histogramm genauso erfolgreich wie der Boxplot, wenn es darum geht, viele Verteilungen vergleichend zu präsentieren? Warum?
1. Erstellen Sie ein sehr grobes und ein sehr feines Histogramm für die Schuhgröße!
1. Vertiefung: Erstellen Sie ein Diagramm, das sowohl eine Zusammenfassung (Mittelwert) der Körpergrößen nach Geschlecht darstellt als auch die einzelnen Werte darstellt!
## Lösungen
1. :-)
2. :
```{r movies-histogram, fig.cap = "Film-Budgets mit Histogrammen"}
qplot(x = budget, geom = "histogram", data = movies, facets = ~factor(Jahrzehnt))
```
Der Boxplot ist besser geeignet als das Histogramm, um mehrere Verteilungen vergleichend zu präsentieren (vgl. Abb. \@ref(fig:movies-histogram)). Durch die gleiche Ausrichtung der Boxplots ist es dem Auge viel einfacher, Vergleiche anzustellen im Vergleich zu den Histogrammen. Einen optisch schöneren Effekt könnte man mit `geom_jitter` anstelle von `geom_point`erreichen. Auch die Reihenfolge der beiden Geome könnte man umdrehen. Natürlich ist auch an Form, Größe und Farbe der Geome noch zu feilen.
3. :
```{r}
qplot(x = shoe_size, data = wo_men, bins = 10)
qplot(x = shoe_size, data = wo_men, bins = 50)
```
4. :
```{r}
wo_men2 %>%
group_by(sex) %>%
summarise(height = mean(height)) -> wo_men3
wo_men3 %>%
ggplot() +
aes(x = sex, y = height) +
geom_point(color = "red", size = 8) +
geom_point(data = wo_men2, color = "grey80")
```
Der "Trick" ist hier, erst die zusammengefassten Daten in ein Geom zu stecken (`wo_men3`). Dann werden die Rohdaten (`wo_men2`) ebenfalls in ein Geom gepackt. Allerdings muss die Achsen-Beschriftung bei beiden Geomen identisch sein, sonst gibt es eine Fehlermeldung.
## Richtig oder Falsch^[R, R, F, F, R]
```{block2, exercises-visualisieren, type='rmdexercises', echo = TRUE}
Richtig oder Falsch!?
1. Diese Geome gehören zum (Standard-) ggplot2: bar, histogram, point, density, jitter, boxplot.
1. `qplot` ist eine Funktion im Paket `ggplot2`.
1. Mi `aes` definiert man, wie "ästethisch" das Diagramm sein soll (z.B. grauer Hintergrund vs. weißer Hintergrund, Farbe der Achsen etc.).
1. Diese Geome gehören zum (Standard-) ggplot2: smooth, line, boxwhisker, mosaicplot.
1. Möchte man ein Diagramm erstellen, welches auf der X-Achse `total_bill`, auf der Y-Achse `tip` darstellt, als Geom Punkte verwendet und die Daten aus der Tabelle `tips` bezieht, so ist folgende Syntax korrekt: `qplot(x = total, bill, y = tip, geom = "point", data = tips)
```
## Befehlsübersicht
Tabelle \@ref(tab:befehle-vis) fasst die R-Funktionen dieses Kapitels zusammen.
```{r befehle-vis, echo = FALSE}
df <- readr::read_csv("includes/Befehle_Vis.csv")
knitr::kable(df,
caption = "Befehle des Kapitels 'Daten visualisieren'")
```
## Vertiefung: Geome bei ggplot2 {#geome}
Einen guten Überblick über Geome bietet das Cheatsheet von ggplot2^[https://www.rstudio.com/wp-content/uploads/2015/03/ggplot2-cheatsheet.pdf].
Verschiedenen Taxonomien von statistischen "Bildchen" sind denkbar; eine einfache ist die folgende; es wird nur ein Teil der verfügbaren Geome dargestellt.
1. Eine kontinuierliche Variable
```{r echo = FALSE}
p1 <-
ggplot(wo_men2) +
aes(x = height) +
geom_histogram() +
labs(title = "geom_histogram")
p2 <-
ggplot(wo_men2) +
aes(x = height) +
geom_density() +
labs(title = "geom_density")
library(gridExtra)
grid.arrange(p1, p2, ncol = 2)
```
2. Zwei kontinuierliche Variablen
```{r echo = FALSE}
p1 <-
ggplot(wo_men2) +
aes(x = height, y = shoe_size) +
geom_point() +
labs(title = "geom_point")
p2 <-
ggplot(wo_men2) +
aes(x = height, y = shoe_size) +
geom_point() +
labs(title = "geom_jitter -\nverwackelt")
p3 <-
ggplot(wo_men2) +
aes(x = height, y = shoe_size) +
geom_smooth() +
labs(title = "geom_smooth")
grid.arrange(p1, p2, p3, ncol = 3)
```
3. Eine diskrete Variable (X-Achse)
```{r}
ggplot(wo_men2) +
aes(x = sex) +
geom_bar()
```
4. Eine diskrete Variable auf der X-Achse und eine kontinuierliche Y-Achse
```{r echo = FALSE}
p1 <-
ggplot(wo_men2) +
aes(x = sex, y = height) +
geom_boxplot() +
labs(title = "geom_boxplot")
p2 <-
ggplot(wo_men2) +
aes(x = sex, y = height) +
geom_violin() +
labs(title = "geom_violin")
grid.arrange(p1, p2, ncol = 2)
```
## Verweise
- Einen Befehlsüberblick zu `ggplot2` findet sich hier: http://ggplot2.tidyverse.org/reference/.
- Edward Tufte gilt als Grand Seigneur der Datenvisualisierung; er hat mehrere lesenswerte Bücher zu dem Thema geschrieben [@1930824130; @1930824165; @1930824149].
- William Cleveland, ein amerikanischer Statistiker ist bekannt für seine grundlegenden, und weithin akzeptierten Ansätze für Diagramme, die die wesentliche Aussage schnörkellos transportieren [@Cleveland].
- Die (graphische) Auswertung von Umfragedaten basiert häufig auf Likert-Skalen. Ob diese metrisches Niveau aufweisen, darf bezweifelt werden. Hier findet sich einige vertiefenden Überlegungen dazu und zur Frage, wie Likert-Daten ausgewertet werden könnten: https://bookdown.org/Rmadillo/likert/.
- Es finden sich viele Tutorials online zu `ggplot2`; ein deutschsprachiger Tutorial findet sich hier: http://md.psych.bio.uni-goettingen.de/mv/unit/ggplot2/ggplot2.html.