-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy path07_datentransformation.Rmd
489 lines (394 loc) · 32 KB
/
07_datentransformation.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
---
title: "Datentransformation Basics"
author: CorrelAid e.V.
date: "`r Sys.Date()`"
authors:
- Zoé Wolter
- Jonas Lorenz
output:
html_document:
toc: true
toc_depth: 2
toc_float: true
theme: flatly
css: www/style.css
includes:
after_body: ./www/favicon.html
language: de
runtime: shiny_prerendered
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message = FALSE, warning = FALSE)
library(learnr)
library(gradethis)
library(forcats)
library(tidyr)
source("R/setup/gradethis-setup.R")
source("R/setup/tutorial-setup.R")
# Read app parameters
params <- yaml::yaml.load_file("www/app_parameters.yml")
# Benötigte Daten laden
source("R/setup/functions.R")
data_raw <- get_data_raw()
community <- get_community()
plastics_processed <- get_pl_proc()
audit <- get_audit()
wb_areas <- get_wb_areas()
wb_processed <- process_wb_areas(wb_data = wb_areas)
```
```{r results='asis'}
cat(get_license_note(rmarkdown::metadata$title, rmarkdown::metadata$authors))
```
![*Video: Datentransformation mit Tidyverse (30min)*](https://youtu.be/YWFLSovbha0)
# **Das Tidyverse-Package**
<left>
![](https://www.tidyverse.org/images/hex-tidyverse.png){#id .class width=20% height=100%}
</left>
<br>
## **Zusammenfassung**
- **Sammlung verschiedener R-Packages**, die aufeinander abgestimmt sind und dabei derselben Logik folgen ([tidyverse.org](https://www.tidyverse.org/){target="_blank"}).
- Die Packages können einzeln installiert und aufgerufen werden, aber auch gesammelt über `install_packages('tidyverse')` bzw. `library(tidyverse)`.
- Einige der Packages und Funktionen kennen wir bereits aus den letzten Wochen!
- "tidy" Datensätze sind die Voraussetzung, um mit dem Tidyverse arbeiten zu können:
<div style="text-align: center;">
<img src="https://github.com/CorrelAid/rlernen_umwelt/blob/main/abbildungen/07_datentransformation/tidy-data.jpeg?raw=true" alt="Beschreibung des Bildes" style="max-width: 100%; height: auto;">
<p style="margin-top: 0.5em; font-style: italic;">Illustrations from the Openscapes blog Tidy Data for reproducibility, efficiency, and collaboration by Julia Lowndes and Allison Horst</p>
</div>
## **Die Bestandteile**
Hier nochmal ein kurzer Überblick, welche Packages alle im `Tidyverse`enthalten sind und was wir ungefähr mit diesen anstellen können, denn das ist eine ganze Menge:
- **`ggplot2`**: Ermöglicht das Erstellen von komplexen und ästhetisch ansprechenden Grafiken basierend auf der Grammatik der Grafiken. Ideal für Datenvisualisierung in einer Vielzahl von Formaten.
- **`dplyr`**: Bietet eine Reihe von Funktionen zur Datenmanipulation, wie z. B. Filtern, Sortieren, Gruppieren und Summarieren von Daten. Es ist besonders nützlich für die Arbeit mit DataFrames.
- **`tidyr`**: Hilft dabei, Daten in ein „tidy“ Format zu bringen, bei dem jede Variable eine Spalte und jede Beobachtung eine Zeile ist. Es ermöglicht das Aufbereiten und Umformen von Daten.
- **`readr`**: Dient dem schnellen und effizienten Einlesen von Daten in R, insbesondere von textbasierten Dateiformaten wie CSV, TSV und anderen strukturierten Textdateien.
- **`purrr`**: Stellt Funktionen zur Verfügung, die das funktionale Programmieren in R ermöglichen und erleichtern, insbesondere das Arbeiten mit Listen und deren Daten.
- **`tibble`**: Eine moderne Alternative zu den traditionellen DataFrames in R, die verbesserte Ausdruckskraft und Benutzerfreundlichkeit bietet. Tibbles zeigen Daten auf eine kontrollierte und übersichtliche Weise an.
- **`stringr`**: Bietet eine konsistente und einfache Schnittstelle zur Manipulation und Analyse von Zeichenketten (Strings) in R. Ideal für Textverarbeitung und Mustererkennung.
- **`forcats`**: Speziell für die Arbeit mit Faktoren entwickelt, die eine spezielle Datenstruktur in R für kategorische Daten sind. Es vereinfacht das Sortieren, Reordnen und Zusammenfassen von Faktorebenen.
Alle weiteren Informationen, Links, etc. findet Ihr auch [hier](https://www.tidyverse.org/packages/){target="_blank"}.
## **Wiederholung: Die Pipe `%>%`**
Bei der ersten Einführung in R haben wir bereits mit der Funktion `nrow()` Bekanntschaft gemacht. Diese können wir nutzen, um die Zeilenanzahl unseres Datensatzes herauszufinden. In der Zwischenzeit haben wir eine Menge R-Erfahrung gesammelt und sind einen Schritt weiter: Wir haben verschiedene Packages und darin enthaltene Funktionen kennengelernt. So auch die **Pipe-Operator `(%>%)`** aus dem `tidyverse`! Das ist ein sehr nützliches Tool mit dem wir die Lesbarkeit und Nachvollziehbarkeit unseres Codes verbessern können. Wir können den Output einer Funktion direkt als Input für die nächste Funktion weitergeben, d.h. mehrere Funktionen mit einer „Pipeline“ verknüpft. Unser Code wird strukturierter und nachvollziehbarer, Fehler können wir weiterhin anpassen oder korrigieren und insgesamt wird unsere Datenbearbeitung dadurch deutlich „flüssiger".
Wir können nun also den **Pipe-Operator** anstatt der Funktion `ncol(plastics)` verwenden, um die Spaltenanzahl zu bestimmen:
``` {r 07pipebeispiel, exercise = TRUE}
# Berechnung der Spaltenanzahl
data_raw %>%
ncol()
```
Das Gleiche gilt für die Anzahl der Zeilen. Nutzt auch hier die Pipe, um Euch die Anzahl der Beobachtungen (Zeilen, engl.: rows) im Datensatz ausgeben zu lassen:
``` {r exercise_07pipe, exercise = TRUE}
# Hier Euer Code!
```
```{r exercise_07pipe-solution}
# Berechnung der Zeilenanzahl
data_raw %>%
nrow()
```
```{r exercise_07pipe-check}
grade_this_code()
```
<br>
## **Quiz**
```{r 07quiz_datenbereinigung1}
quiz(caption = NULL,
question("Was macht einen Datensatz tidy?",
answer("Jede Variable hat eine eigene Spalte", correct = TRUE),
answer("Jede Beobachtung hat eine eigene Zeile", correct = TRUE),
answer("Jeder Wert hat eine eigene Zelle", correct = TRUE),
correct = "Richtig, bei einem 'tidy' Datensatz sprechen wir auch von einem 'aufgeräumten' Datensatz. Das Chaos, das möglicherweise einmal geherrscht hat, ist beseitigt und es herrscht Ordnung: eine Variable pro Spalte, eine Beobachtung pro Zeile und ein Wert pro Zelle!",
incorrect = "Leider falsch, bei einem 'tidy' Datensatz sprechen wir auch von einem 'aufgeräumten' Datensatz. Was könnte man darunter verstehen? Versuche es nochmal oder schaue im Video nach!",
allow_retry = TRUE,
try_again_button = "Nochmal versuchen"
),
question("Was ist der Pipe-Operator (%>%)?",
answer("Eine Funktion", correct = TRUE),
answer("Ein Werkzeug zur Strukturierung von mehrfachen Operationen in R", correct = TRUE),
answer("Ein Werkzeug zur verbesserten Lesbarkeit von Code in R", correct = TRUE),
answer("Syntax des ggplot2-Packages"),
answer("Eine Besonderheit des tidyverse-Packages", correct = TRUE),
correct = "Richtig, der Pipe-Operator ist eine kleine Sache, die eine große Wirkung zeigt und uns das Leben sehr viel leichter macht! Mit diesem Ausdruck können wir verschiedene Funktionen miteinander verknüpfen. Dadurch werden unsere Daten automatisch durch diese Funktionen geleitet, wodurch unser Code deutlich strukturierter und lesbarer wird.",
incorrect = "Leider falsch, versuche es nochmal oder schaue im Video nach!",
allow_retry = TRUE,
try_again_button = "Nochmal versuchen"
),
question("Wofür steht NA?",
answer("Not accessible"),
answer("Not available", correct = TRUE),
answer("Not attainable"),
correct = "Richtig, NA steht für not available (nicht verfügbar)!",
incorrect = "Leider falsch, NA steht für not available (nicht verfügbar).",
allow_retry = TRUE,
try_again_button = "Nochmal versuchen"
)
)
```
<br>
# **Interaktive Übung**
Springen wir direkt weiter in unsere praktische Übung und schauen uns an, welche verschiedenen Operationen mit unseren Daten so möglich sind. Ihr werdet merken, dass wir einige der Funktionen bereits kennengelernt haben!
## **1. Schritt: Import der Rohdaten**
Wie immer starten wir damit, unseren Datensatz zu laden. Hier ziehen wir uns über den Hyperlink einen Rohdatensatz, aus dem wir gemeinsam zwei bereinigte Datentabellen (`community` und `audit`) generieren.
``` {r 07load_data, exercise = TRUE}
# Laden des Datensatzes
data_raw <- rio::import('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2021/2021-01-26/plastics.csv')
```
## **2. Schritt: Definition der Bereinigungsschritte**
Wir werfen einen ersten Blick in unseren Datensatz und stellen fest, dass dieser ganz schön unordentlich aussieht! Wir müssen aufräumen und die Daten bereinigen. Bevor wir einfach wild drauf los coden, überlegen wir uns erst einmal, welche Informationen am Ende des Bereinigungsprozesses existieren sollen und wie wir dieses Ziel erreichen.
*Hinweis: Unser Rohdatensatz enthält Daten aus den Jahren 2019 und 2020. Da wir uns an dieser Stelle erst einmal mit den grundlegenden Funktionen beschäftigen und keinen komplexen Zeitvergleich durchführen wollen, werden wir uns auf die Daten aus dem Jahr 2019 beschränken. Aufgrund der Covid-19-Pandemie stehen uns für das Jahr 2020 nämlich nur sehr wenige Daten zur Verfügung.*
Einerseits möchten wir das Verhalten der #Breakfreefromplastic-Community in den verschiedenen Ländern vergleichen, weshalb wir einen Datensatz **`community`** erstellen. Unsere Beobachtungseinheiten sind die Länder (= jede Zeile steht für ein Land) und als relevante "communitybezogene" Variablen identifizieren wir **Kontinent, Land, Countrycode, Anzahl Plastikteile, Events und Freiwillige**. Diese werden in unseren Spalten abgetragen.
Andererseits interessieren wir uns auch für Daten, die die verantwortlichen Firmen betreffen. Da wir deren Müllproduktion einer Prüfung (engl. Audit) unterziehen wollen, erstellen wir einen zweiten Datensatz mit dem Namen **`audit`**. Weil wir uns neben der herstellenden Firma auch für die Art des Plastikmülls (Plastiktyp) und das Land interessieren, in dem der Müll gefunden wurde, bildet **jede Zeile eine einzigartige Kombination aus Hersteller und Plastiktyp pro Land**. Als "auditbezogene" Variablen identifizieren wir **Kontinent, Land, Countrycode, Hersteller und die Anzahl der Plastikstücke**. Diese werden wieder in unseren Spalten abgetragen.
Folgende Datensätze wollen wir also im Laufe dieser Session erstellen:
<ul>
<li><strong>Datensatz `community`</strong>:
<ul>
<li><strong>Eine Zeile:</strong> Ein Land</li>
<li><strong>Variablen:</strong> Kontinent, Land, Countrycode, Anzahl Plastikstücke, Events und Freiwillige.</li>
</ul>
</li>
<li><strong>Datensatz `audit`</strong>:
<ul>
<li><strong>Eine Zeile:</strong> Eine einzigartige Kombination aus Hersteller und Plastiktyp pro Land</li>
<li><strong>Variablen:</strong> Kontinent, Land, Countrycode, Hersteller, Anzahl Plastikstücke.</li>
</ul>
</li>
</ul>
<div style="margin-left: 0;">
<p>Wir müssen uns überlegen, wie wir diese Ziele erreichen können. Da wir ausschließlich "vollständige" Daten betrachten wollen, sortieren wir Fälle aus, bei denen zum Beispiel kein Land angegeben ist ("EMPTY") oder die Beobachtung aus dem jahr 2020 stammt (s. Hinweis). Auch die Ländernamen müssen wir bearbeiten, weil diese nicht immer einheitlich angegeben wurden (z.B. ECUADOR, Ecuador) - manche Namen müssen auch erst einmal übersetzt werden (z.B. Cote D_ivoire). Abschließend müssen wir die "community- bzw- auditbezogenen" Variablen auswählen und den Datensatz entsprechend umformen. Wir entscheiden und also für folgendes Vorgehen: <p>
1. Zeilen, in denen das Land "EMPTY" ist, Sammelzeilen und Beobachtungen aus dem Jahr 2020 aussortieren. <br>
2. Ländernamen bereinigen und übersetzen. <br>
3. Entsprechende Variablen auswählen und ggf. Datensatz umformen. <br>
</div>
## **3. Schritt: Die Datenbereinigung mit dem `dplyr`-Package**
Für die Basics der Datenbereinigung, werden wir in dieser Woche vor allem das **`dplyr`**-Package verwenden. Dieses ist speziell für die Datenmanipulation entwickelt worden und liefert uns verschiedene Funktionen, mit denen wir unsere Daten verändern können. An dieser Stelle wollen wir uns einmal die **sechs Grundverben** dieses Packages anschauen.
Hier eine kurze Übersicht über die Funktionen:
| Funktion | Wofür? |
|:----------------|:--------------------------------------------------------|
| `dplyr::filter()` | **Auswahl von Zeilen** bzw. Beobachtungen nach bestimmten Kriterien |
| `dplyr::mutate()` | **Erstellung neuer Spalten/Variablen** auf Basis bereits vorhandener Spalten/Variablen bzw. **Veränderung von Variablen**
|
| `dplyr::group_by()` | **Gruppierung** von Beobachtungen |
| `dplyr::summarise()` | **Zusammenfassen** von Beobachtungen mit statistischen Kennzahlen |
| `dplyr::select()` | **Auswahl von Spalten** bzw. Variablen |
| `dplyr::arrange()` | **Sortierung** von Zeilen im Datensatz nach bestimmten Kriterien |
<br>
### **Die `filter()`-Funktion**
![Graphische Veranschaulichung der filter()-Funktion](https://github.com/CorrelAid/rlernen_umwelt/blob/main/abbildungen/07_datentransformation/filter.png?raw=true){#id .class width=60% height=60%}
Beginnen wir also einmal mit der Funktion **`dplyr::filter()`** mit der wir - wie der Name bereits vermuten lässt - **Zeilen bzw. Beobachtungen filtern** können. Wir betrachten also zunächst den gesamten Datensatz und lesen dann mithilfe der Funktion die Zeilen aus, die wir behalten wolllen. Dazu definieren wir bestimmte Bedingung(en), die die entsprechenden Zeilen erfüllen müssen.
Für unseren geplanten Ländervergleich, wollen wir alle Beobachtungen aussortieren, für die kein Land hinterlegt wurde bzw. bei denen die Firmen "aufsummiert" und/oder vermischt wurden. Wenn kein Land hinterlegt ist, ist die Zeile `country` leer. Im Falle der Firmen hat die Zeile `parent_company` den Wert "Grand Total". Mithilfe des Ausdrucks **`variable != wert`** (*Sprich: "Variable ist ungleich Wert X."*) können wir die entsprechenden Beobachtungen aussortieren:
``` {r 07overview_data, exercise = TRUE}
# Ihr nehmt Euren Datensatz...
data_raw %>%
# ..filtert "EMPTY" und "Grand Total" heraus
dplyr::filter(country != "EMPTY",
parent_company != "Grand Total")
```
Der erste Schritt ist geschafft! Wie bereits erwähnt, müssen wir aufgrund der Covid-19-Pandemie auch die Daten für das Jahr 2020 von unseren Analysen ausschließen, da diese unsere Ergebnisse verfälschen würden. Versucht das doch einmal selbst und ergänzt dazu den Code um die entsprechende Bedingung:
``` {r exercise_07filter_data_exercise, exercise = TRUE}
# Ihr nehmt Euren Datensatz...
data_raw %>%
# ..filtert "EMPTY", "Grand Total" und alle Jahre außer 2019 heraus
dplyr::filter(country != "EMPTY",
parent_company != "Grand Total",
# Hier Euer Code!
)
```
```{r exercise_07filter_data_exercise-solution}
# Ihr nehmt Euren Datensatz...
data_raw %>%
# ..filtert "EMPTY", "Grand Total" und alle Jahre außer 2019 heraus
dplyr::filter(country != "EMPTY",
parent_company != "Grand Total",
year != 2020
)
```
```{r exercise_07filter_data_exercise-check}
grade_this_code()
```
<br>
### **Die `mutate()`-Funktion**
![*Graphische Veranschaulichung der mutate()-Funktion*](https://github.com/CorrelAid/rlernen_umwelt/blob/main/abbildungen/07_datentransformation/mutate.png?raw=true){#id .class width=60% height=60%}
Nun wollen wir die die Variable `country` (zu dt. Land) bereinigen, denn es herrscht wieder einmal Unordnung: Die Länderbezeichnungen für Großbritannien und die USA sind nicht standardisiert, die Groß- und Kleinschreibung ist vollkommen durcheinander und außerdem wollen wir die deutschen Bezeichnungen verwenden, sowie Kontinent und Countrycode ergänzen. Klingt erstmal nach ganz schön viel Arbeit.... Zum Glück bietet uns das `dplyr`-Package mit der Funktion **`mutate`** die Möglichkeit, Berechnungen auf Spaltenebene durchzuführen, d.h. wir können unserem Datensatz neue **Variablen hinzufügen** oder bestehende **Variablen bearbeiten**. Dafür geben wir den Namen der neuen Spalte und die Berechnung an, die durchgeführt werden soll - nach folgender Logik: `dplyr::mutate(datensatz, name_der_neuen_spalte = x + y)`.
In diesem fall brauchen wir allerdings noch zwei weitere Funktionen, die wir mit der `mutate()`-Funktion kombinieren können. Zunächst einmal möchten wir die Ländernamen vereinheitlichen ("United Kingdom" und "United States"). Dafür verwenden wir die Funktion **`case_when()`** aus dem `dplyr` Package. Mit dieser Funktion können wir bestimmte Werte in einen anderen Wert transformieren - das Einzige, was wir dafür festlegen müssen, ist die entsprechende Wenn-Dann-Bedingung *(Sprich: "Wenn die Variable 'country' den Wert X hat, dann weise dieser Variable den Wert Y zu.")*.
In einem zweiten Schritt können wir mithilfe des **`stringr`**-Packages (ebenfalls im Tidyverse enthalten), Zeichenketten (engl. Strings) relativ einfach manipulieren und analysieren. Mit der darin enthaltenen Funktion **`str_to_title()`** können wir "Titel" (= großer Anfangsbuchstabe) erzeugen und somit die Ländernamen vereinheitlichen. Mithilfe des Packages **`countrycode`** können wir ebenfalls die deutschen Bezeichnungen verwenden.
**Wichtig:** Welche Funktionen Ihr am Ende für Eure Bereinigungsschritte braucht, hängt auch immer vom Datensatz ab. Gerade am Anfang kann das etwas unübersichtlich werden - vor allem mit den verschiedenen Funktionen aus unterschiedlichen Packages. Keine Sorge, mit etwas mehr Erfahrung und einer Googlerecherche lassen sich für die meisten Herausforderungen wirklich tolle Hilfsmittel finden!
Nun wollen wir das Ganze aber auch selbst einmal ausprobieren! Der Code ist bereits schon geschrieben, allerdings fehlen an manchen Stellen (gekennzeichnet durch: ???) Funktionen und Variablennamen. Ergänzt diese an den entsprechenden Stellen, um alle Stellen zu finden, müsst Ihr etwas scrollen.
```{r exercise_07mutate_data_exercise, exercise = TRUE}
# Ihr nehmt Euren Datensatz...
data_raw %>%
# ..filtert "EMPTY", "Grand Total" und Jahr 2020 heraus
dplyr::???(
country != "EMPTY",
parent_company != "Grand Total",
year == 2019
) %>%
# ..bereinigt die Ländernamen, indem Ihr...
dplyr::???(
# ..die UK und USA umbenennt
country =
dplyr::case_when(
country == "United Kingdom of Great Britain & Northern Ireland" ~ "United Kingdom",
country == "United States of America" ~ "United States",
TRUE ~ country # falls keine der beiden Zeilen zutrifft, dann nehmen wir diese Zeile und schreiben wieder den Wert aus `country` in die neue Variable
),
# ..nur den Anfangsbuchstaben der Länder großschreibt
??? = stringr::str_to_title(country),
# ..Kontinent und Land übersetzt
continent = countrycode::countrycode(country,
origin = "country.name",
destination = "continent"),
??? = dplyr::case_when(continent == "Africa" ~ "Afrika",
continent == "Americas" ~ "Amerika",
continent == "Asia" ~ "Asien",
continent == "Europe" ~ "Europa",
continent == "Oceania" ~ "Ozeanien"),
countrycode = countrycode::countrycode(country,
origin = "country.name",
destination = "iso3c"),
country = countrycode::countrycode(country,
origin = "country.name",
destination = "country.name.de")
)
```
```{r exercise_07mutate_data_exercise-solution}
# Ihr nehmt Euren Datensatz...
data_raw %>%
# ..filtert "EMPTY", "Grand Total" und Jahr 2020 heraus
dplyr::filter(
country != "EMPTY",
parent_company != "Grand Total",
year == 2019
) %>%
# ..bereinigt die Ländernamen, indem Ihr...
dplyr::mutate(
# ..die UK und USA umbenennt
country =
dplyr::case_when(
country == "United Kingdom of Great Britain & Northern Ireland" ~ "United Kingdom",
country == "United States of America" ~ "United States",
TRUE ~ country
),
# ..nur den Anfangsbuchstaben der Länder großschreibt
country = stringr::str_to_title(country),
# ..Kontinent und Land übersetzt
continent = countrycode::countrycode(country,
origin = "country.name",
destination = "continent"),
continent = dplyr::case_when(continent == "Africa" ~ "Afrika",
continent == "Americas" ~ "Amerika",
continent == "Asia" ~ "Asien",
continent == "Europe" ~ "Europa",
continent == "Oceania" ~ "Ozeanien"),
countrycode = countrycode::countrycode(country,
origin = "country.name",
destination = "iso3c"),
country = countrycode::countrycode(country,
origin = "country.name",
destination = "country.name.de")
)
```
```{r exercise_07mutate_data_exercise-check}
grade_this_code()
```
Ein Großteil unserer Datenbereinigung ist nun abgeschlossen - das Ergebnis steht Euch unter `plastics_processed` zur Verfügung! Da wir uns für community- **und** auditbezogene Daten interessieren, schauen wir uns nun an, wie wir den Datensatz in zwei Tabellen aufteilen.
### **Die `group_by()`- und `summarise()`-Funktion**
![*Graphische Veranschaulichung der group_by()-Funktion*](https://github.com/CorrelAid/rlernen_umwelt/blob/main/abbildungen/07_datentransformation/groupby.png?raw=true){#id .class width=60% height=60%}
![*Graphische Veranschaulichung der summarise()-Funktion*](https://github.com/CorrelAid/rlernen_umwelt/blob/main/abbildungen/07_datentransformation/summarize.png?raw=true){#id .class width=60% height=60%}
Wir möchten weiterhin herausfinden, in welchen Ländern die meisten Plastikteile gesammelt, die meisten Events durchgeführt und die meisten Freiwilligen aktiv sind. Dazu müssen wir innerhalb des `community` Datensatzes eine Struktur erschaffen, in dem eine Beobachtung pro Land vorhanden ist - wir müssen unsere bereinigten Daten also pro Land **gruppieren**.
Dafür verwenden wir zwei neue Funktionen, die häufig miteinander kombiniert werden: **`group_by()`** und **`summarise()`** (auch: `summarize()`). Zusammen sind sie besonders nützlich für das Erstellen von Zusammenfassungen und die Berechnung von Statistiken auf Gruppenebene.
Die Funktion `group_by()` wird dabei verwendet, um Daten nach einer oder mehreren Variablen zu gruppieren, damit wir im Anschluss mit der `summarise()`-Funktion die bereits bekannten zusammenfassenden **Statistiken** berechnen können.
In der Praxis gruppieren wir also zuerst entsprechend der Kontinente und Länder. Danach müssen wir entscheiden, wie die anderen Variablen zusammengefasst werden. In diesem Fall addieren wir die Plastikteile und wählen für die Anzahl der Events und Freiwilligen genau einen Wert aus. Diese sind im Originaldatensatz mehrfach vorhanden - etwas, das typischerweise beim Zusammenfügen von Datensätzen entsteht. Aber schauen wir uns das ganze Vorgehen doch einmal direkt in unserem R-Code an:
``` {r 07group_by_summarise1, exercise = TRUE}
# Ihr nehmt Euren Datensatz, ...
community <- plastics_processed %>%
# … gruppiert die Beobachtungen pro Land
dplyr::group_by(continent, country, countrycode) %>% # Pro Kontinent und Land gruppieren
# … entscheidet, wie die anderen Variablen zusammengefasst werden sollen
dplyr::summarise(
n_pieces = sum(grand_total, na.rm = TRUE), # Summe
n_volunteers = unique(volunteers), # Einzigartige Werte (da Duplikate)
n_events = unique(num_events) # Einzigartige Werte (da Duplikate)
)
```
Und jetzt Ihr: Verwendet an dieser Stelle die neuen Funktionen `dplyr::group_by()` und `dplyr::summarise()` und versucht einmal die Gesamtzahl der Plastikstücke, die pro Kontinent gesammelt wurden zu berechnen - nutzt dafür den `community`-Datensatz.
```{r 07group_by_summarise2, exercise = TRUE}
# Hier Euer Code
```
```{r 07group_by_summarise2-solution}
# Ihr nehmt Euren Datensatz, ...
community %>%
# … gruppiert die Beobachtungen pro Kontinent
dplyr::group_by(continent) %>%
# … entscheidet, wie die anderen Variablen zusammengefasst werden sollen
dplyr::summarise(n_pieces = sum(n_pieces, na.rm = TRUE)) # Summe
```
```{r 07group_by_summarise2-check}
grade_this_code()
```
## **Die `select()`-Funktion**
![*Graphische Veranschaulichung der select()-Funktion*](https://github.com/CorrelAid/rlernen_umwelt/blob/main/abbildungen/07_datentransformation/select.png?raw=true){#id .class width=60% height=60%}
Bislang haben wir Zeilen bzw. Beobachtungen gefiltert, aber dabei soll es nicht bleiben. Denn mithilfe der **`select()`**-Funktion können wir auch **Spalten bzw. Variablen filtern** und somit (große) Datensätze auf die **relevanten Spalten reduzieren**. Dabei können wir bestimmte Spalten nach verschiedenen Kriterien (z.B. Namen, Typ oder Position) auswählen oder umbenennen. Entweder wählen wir die Variablen aus, die im Datensatz enthalten bleiben sollen oder bestimmen mit einem `-` die Variablen, die aus unserem Datensatz gelöscht werden sollen. Der folgende Code löscht so zum Beispiel die Variable `grand_total` aus dem `data_raw`-Datensatz:
``` {r 07select_data1, exercise = TRUE}
# Spalte "grand_total" NICHT auswählen
data_raw %>%
dplyr::select(-grand_total) %>%
head()
```
Um die Bereinigung des `audit`-Datensatzes zu finalisieren, wählen wir also in einem letzten Schritt noch alle relevanten Variablen aus:
*Anmerkung: Pivoting beschreibt ein Verfahren mit dem wir unsere Datensätze lesbarer machen können, indem wir die Anordnung der Zeilen und Spalten verändern. In der kommenden Sitzung werden wir uns auch noch einmal anschauen, wie wir selbst unsere Daten pivotieren können!*
```{r 07select_data2, exercise = TRUE}
# Ihr nehmt Euren Datensatz ...
audit <- plastics_processed %>%
# …pivotiert die Plastikarten
tidyr::pivot_longer(
cols = c(hdpe, ldpe, o, pet, pp, ps, pvc), # Betroffene Variablen
names_to = "plastic_type", # Zielspalte
values_to = "n_pieces", # Wertspalte
) %>%
# … faktorisiert sicherheitshalber die anderen Variablen (nicht immer notwendig)
dplyr::mutate(dplyr::across( # Zu Faktor konvertieren
.cols = c(country, continent, countrycode, year, plastic_type),
.fns = as_factor
)) %>%
# … und wählt die richtigen Spalten aus, da manche Variablen mit der Pivotierung nicht aussagekräftig sind.
dplyr::select(continent, country, countrycode, parent_company, plastic_type, n_pieces)
```
Schon ist ein großer Schritt getan und unsere beiden Datensätze sind bereinigt! Was meint Ihr, sind die enthaltenen Werte richtig? Können wir diese Frage überhaupt einfach so beantworten? Schwierig, das auf den ersten Blick zu sagen - aber wir können mit R eine Art **Qualitätsprüfung** durchführen. Schauen wir uns also für beide Datensätze einige Informationen an:
```{r sanitycheck, exercise = TRUE}
# Anzahl Plastikstücke
sum(community$n_pieces, na.rm = TRUE) == sum(plastics_processed$grand_total)
sum(audit$n_pieces, na.rm = TRUE) == sum(plastics_processed$grand_total)
# Länder
sort(unique(community$country)) == sort(unique(audit$country))
```
Das sieht doch sauber aus - gut gemacht! <br>
Unsere Daten sind bereinigt und wir haben einen großen Schritt nach vorne gemacht, denn häufig ist dieser Teil tatsächlich aufwändiger als die späteren Visualisierungen oder Berechnungen.
<br>
## **Die `arrange()`-Funktion**
![*Graphische Veranschaulichung der arrange()-Funktion*](https://github.com/CorrelAid/rlernen_umwelt/blob/main/abbildungen/07_datentransformation/arrange.png?raw=true){#id .class width=60% height=60%}
Eine letzte Funktion aus dem `dplyr` wollen wir Euch dennoch nicht vorenthalten: Die **`arrange()`**-Funktion. Diese wird eher zur Transformation unserer Daten als für deren Bereinigung genutzt und hilft uns dabei, Zeilen eines Datensatzes nach den Werten einer oder mehrerer Spalten zu sortieren bzw. **Ranglisten auszugeben**. Sie ist also eine große Hilfe, wenn wir Daten in einer bestimmten Reihenfolge analysieren und präsentieren oder für einen Bericht vorbereiten möchten. Wir können beispielsweise eine Rangliste der zehn Firmen erstellen, die am meisten Plastikmüll produzieren. Dafür wählen wir alle Firmen aus und gruppieren diese. Anschließend erstellen eine Zusammenfassung und beschränken uns dann auf die ersten zehn Firmen, die wir mit `dplyr::arrange()` in absteigender Reihenfolge sortieren:
```{r arrange, exercise = TRUE}
# Ihr nehmt Euren Datensatz...
audit %>%
# ..wählt relevante Spalten aus
dplyr::select(parent_company, n_pieces) %>%
# ..gruppiert pro Hersteller
dplyr::group_by(parent_company) %>%
# ..berechnet die Zusammenfassung (hier: Summe)
dplyr::summarise(total_pieces = sum(n_pieces, na.rm = TRUE)) %>%
# ..filtert unnütze Werte heraus
dplyr::filter(! parent_company %in% c("Unbranded", "Inconnu", "Assorted")) %>%
# ..begrenzt die Anzahl auf 10
dplyr::slice_max(total_pieces, n = 10) %>%
# ..und sortiert die Werte absteigend
dplyr::arrange(desc(total_pieces))
```
Nun können wir das gefundene Plastik den verschiedenen Firmen zuordnen: LaDoo, Coca-Cola und Barna sind dabei offensichtlich die drei Firmen, die mit 15.221, 9.988 bzw. 6.225 gefundenen Plastikteilen in hohem Maße für die Umweltverschmutzung durch Plastikmüll verantwortlich sind. Diese Ergebnisse können wir nun vielleicht für unsere nächste Kampagne verwenden?
Ihr kennt alle `dplyr`-Verben und seid fit für die Datentransformation! Mit dem neuen Wissen können wir direkt in die Übungsaufgabe einsteigen und nochmal alles ausprobieren. Vorher aber noch einmal ein kleiner Hinweis: Auf einige Themen sind wir hier nur am Rande eingegangen (z.B. den Umgang mit fehlenden Werte (NAs, die Umformung von Textdaten und das Zusammenfügen von Datensätzen). Lasst Euch davon nicht beirren, wir werden uns diese in den kommenden Wochen noch im Detail anschauen!
# **Und jetzt Ihr!**
Wenn Ihr einen **eigenen Datensatz** habt, den Ihr bereits in R importiert habt, dann könnt Ihr jetzt versuchen, diesen zu bereinigen. Wenn Ihr nicht genug von Datenbereinigung bekommen könnt oder Ihr keinen eigenen Datensatz habt, dann schaut Euch die **R-Datei: 07_datentransformation-uebung.R** (im [Übungsordner](https://download-directory.github.io/?url=https://github.com/CorrelAid/rlernen_umwelt/tree/main/uebungen){target="_blank"} unter 07_datentransformation) an und versucht die Aufgaben darin zu bearbeiten.
# **Zusätzliche Ressourcen**
- [Schummelblatt: dplyr](https://github.com/CorrelAid/rlernen_umwelt/blob/main/cheatsheets/06_cheatsheet-dplyr.pdf){target="_blank"} (engl.)
- [Schummelblatt: stringr](https://github.com/CorrelAid/rlernen_umwelt/blob/main/cheatsheets/06_cheatsheet-stringr.pdf){target="_blank"} (engl.)
- [Schummelblatt: tidyr](https://github.com/CorrelAid/rlernen_umwelt/blob/main/cheatsheets/06_cheatsheet-tidyr.pdf){target="_blank"} (engl.)
- [Data Cleaning in R](https://app.dataquest.io/course/r-data-cleaning){target="_blank"} auf DataQuest (engl.)
- [Advanced Data Cleaning in R](https://app.dataquest.io/course/r-data-cleaning-advanced){target="_blank"} auf DataQuest (engl.)
- Ein noch etwas holpriger Spielplatz, der zeigt, wie Eure Schritte in der Datenbereinigung aussehen: [Tidy Data Tutor](https://tidydatatutor.com){target="_blank"} (engl.)
- [Tidyverse: Tidy data](https://tidyr.tidyverse.org/articles/tidy-data.html){target="_blank"} (engl.)
<a class="btn btn-primary btn-back-to-main" href=`r params$links$end_session`>Session beenden</a>