<- read_csv("../data/gapmindersubset.csv") gapminder
4 Das tidyverse-Paket
Dieses Kapitel orientiert sich zum Teil an dem Kapitel “The tidyverse” des eBuchs Introduction to Data Science von Rafael A. Irizarry. Sehr lesenswert ist außerdem das Buch Data Science for R von Hadley Wickham und Garrett Grolemund. Beide Bücher gehen jedoch über das hinaus, was in diesem Kurs behandelt wird.
4.1 Tidy data
In diesem Kurs gehen wir stets davon aus, dass die Daten als sogenannte tidy data, also als “saubere Daten” vorliegen. Saubere Daten liegen vor, wenn jede Zeile eine Beobachtung beinhaltet und die Spalten die verschiedenen Variablen repräsentieren, die für jede Beobachtung erhoben wurden. In der praktischen empirischen Arbeit hat man natürlich nicht immer saubere Daten und muss häufig viel Mühe aufwenden, um die Daten in ein sauberes Format zu überführen.
Für den Umgang mit sauberen Daten gibt es eine Reihe von R-Paketen, die in dem Paket tidyverse
zusammengefasst sind. Um mit ihnen arbeiten zu können, muss das tidyverse
-Paket einmalig installiert werden. In Kapitel 1.3 wird beschrieben, wie man Pakete installiert. Sollte das tidyverse
-Paket bei Ihnen noch nicht installiert sein, holen Sie das nun bitte nach.
Wenn das Paket installiert ist, kann man es zu Beginn einer R-Sitzung durch den Befehl library(tidyverse)
aktivieren. Diese Aktivierung muss bei jeder neuen Benutzung von R erneut erfolgen.
4.2 Transformationen
Das Paket tidyverse
bietet Funktionen, mit denen Transformationen von Dataframes durchgeführt werden können. Dazu gehört die Auswahl von Variablen oder Beobachtungen, das Errechnen neuer Variablen aus den bisherigen Variablen, Sortieren etc.
Zur Illustration der Befehle laden wir den Datensatz gapmindersubset.csv
, den Sie auch auf der Learnweb-Seite finden. Der Datensatz wird in Kapitel D.3 beschrieben. Gapminder ist eine Stiftung, die u.a. umfangreiche internationale Daten bereitstellt, um (nach eigenen Angaben) gegen falsche Vorstellungen zu kämpfen und eine fakten-basierte Weltsicht zu fördern. Der Datenbestand von Gapminder ist erheblich umfangreicher als der kleine Auszug, den wir hier als Beispiel nutzen.
Zum Einlesen des Dataframes verwenden wir eine der Methoden aus Kapitel 3, z.B. den interaktiven Import (Kapitel 3.3) oder den kommandogesteuerten Import (Kapitel 3.4). Der Dataframe wird unter dem Namen gapminder
abgelegt.
(Wenn Sie den Datensatz auf Ihrem Computer laden wollen, muss der Pfad entsprechend angepasst werden.) Der Anfang des Datensatzes sieht so aus:
head(gapminder)
# A tibble: 6 × 10
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 abw 1986 17467 4449 23256 13396 5989 2.32
2 abw 1987 17097 4103 23441 13838 5971 2.31
3 abw 1988 16779 3786 23499 14274 5996 2.29
4 abw 1989 16798 3653 23290 14786 6070 2.27
5 abw 1990 17453 3876 22691 15477 6218 2.25
6 abw 1991 18796 4531 21748 16321 6468 2.22
# ℹ 2 more variables: co2 <dbl>, gdp_pc <dbl>
Die Daten liegen als tidy data vor. In jeder Zeile werden die Variablenwerte der Einwohnerzahl (pop
), der Fertilität (fert
), des gesamten CO2-Ausstoßes (co2
) und des Pro-Kopf-Bruttoinlandsprodukts (gdp_pc
) im Jahr year
für das Land country
angegeben. Das Land wird durch die übliche ISO-Abkürzung (3-Steller) bezeichnet.
4.2.1 filter
Mit der Funktion filter
kann man bestimmte Beobachtungen aus einem Dataframe auswählen. Angenommen, wir möchten aus dem Dataframe gapminder
nur die Beobachtungen für Deutschland (mit der Abkürzung “deu”) sehen. Die Funktion filter
hat als erstes Argument den Dataframe und als weiteres Argument die Bedingung. Ein Zeilenumbruch zwischen den Argumenten erleichtert die Lesbarkeit, ist aber nicht notwendig.
filter(gapminder,
== "deu") country
Die ersten Zeilen des Outputs sehen so aus:
# A tibble: 6 × 10
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 deu 1970 18249229 5323649 21639297 17591559 15490850 2.04
2 deu 1971 18196497 5376127 21763354 17523583 15651838 1.92
3 deu 1972 18035263 5453507 21939085 17403802 15811901 1.8
4 deu 1973 17751123 5550210 22137964 17259645 15968525 1.7
5 deu 1974 17369889 5672726 22246496 17244537 16086886 1.62
6 deu 1975 16920048 5824422 22223972 17476086 16068982 1.56
# ℹ 2 more variables: co2 <dbl>, gdp_pc <dbl>
Wir sehen beispielsweise, dass in Deutschland im Jahr 1970 rund 78.6 Millionen Einwohner hatte und die Fertilitätsrate ein klein wenig über 2 lag.
Man kann auch komplexere Bedingungen eingeben, z.B. alle Beobachtungen aus Deutschland oder Frankreich zwischen 2015 und 2018:
filter(gapminder,
=="deu" | country=="fra") &
(country>= 2015 &
year <= 2018) year
# A tibble: 8 × 10
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 deu 2015 10837497 4194385 20048624 24622002 22370719 1.45
2 deu 2016 10924700 4182755 20167639 24417910 22638421 1.46
3 deu 2017 11064609 4124606 20291380 24213403 22930375 1.47
4 deu 2018 11208996 4050256 20385848 23997586 23254010 1.48
5 fra 2015 11605039 3796374 15326695 16936946 16144712 1.98
6 fra 2016 11565753 3839238 15278129 16878831 16427369 1.98
7 fra 2017 11517825 3877090 15225642 16819154 16704372 1.98
8 fra 2018 11464213 3901693 15168242 16769987 16973673 1.97
# ℹ 2 more variables: co2 <dbl>, gdp_pc <dbl>
Eine ODER-verknüpfung erfolgt durch den senkrechten Strich (|
), eine UND-Verknüpfung durch das Et-Zeichen (&
). Negationen werden durch das Ausrufezeichen (!
) gekennzeichnet. Die Relationen sind:
- Kleiner als:
<
- Größer als:
>
- Kleiner als oder gleich:
<=
- Größer als oder gleich:
>=
- Gleich:
==
- Ungleich:
!=
Beachten Sie, dass eine Gleichheitsbedingung immer mit einem doppelten Gleichheitszeichen geschrieben werden muss (==
). Das einfache Gleichheitszeichen ist eine andere, synonyme Schreibweise für den Zuweisungsoperator <-
. Es ist ein häufiger Fehler (der einem leider immer wieder passiert), in einer Bedingung das einfache Gleichheitszeichen zu schreiben.
Wenn bei einer Variable Werte fehlen, ist es manchmal sinnvoll, alle Beobachtungen mit fehlenden Werten aus der weiteren Betrachtung auszuschließen. Dabei hilft die Funktion is.na
(für: is there any not available?). Mit ihr kann man feststellen, ob eine Beobachtung fehlt oder nicht. Um zum Beispiel nur Beobachtungen zu behalten, in denen die Variable co2
nicht fehlt, lautet der Befehl
filter(gapminder,
!is.na(co2))
Das Ausrufezeichen steht hierbei für den logischen NICHT-Operator. Den Output der Funktion filter
kann man als neuen Dataframe abspeichern. Um die ausgewählten Beobachtungen als Dataframe mit dem Namen gm_auswahl
zu speichern, gibt man folgendes ein:
<- filter(gapminder,
gm_auswahl BEDINGUNG)
Wenn man sicher ist, dass im weiteren Verlauf der Datenanalyse nur noch die ausgewählten Beobachtungen benötigt werden, dann kann man den Output auch dem alten Dataframe-Namen zuweisen. In diesem Fall wird der alte Dataframe überschrieben.
<- filter(gapminder,
gapminder BEDINGUNG)
4.2.2 select
Wenn man nicht alle Variablen (Spalten) anzeigen lassen will, kann man mit der Funktion select
einzelne Spalten auswählen. Die Syntax ist ähnlich wie bei filter
: Das erste Argument ist der Dataframe, die weiteren Argumente sind die Variablen, die man auswählen will.
Um von dem Beispieldatensatz gapminder
nur die Spalten country
, year
und co2
anzuzeigen, lautet der Befehl
select(gapminder,
country,
year, co2)
Die Zeilenumbrüche erleichtern die Lesbarkeit, sie sind aber nicht unbedingt erforderlich. Als Output erhält man (hier werden nur die ersten paar Zeilen angezeigt):
# A tibble: 6 × 3
country year co2
<chr> <dbl> <dbl>
1 abw 1986 180.
2 abw 1987 447.
3 abw 1988 612.
4 abw 1989 649.
5 abw 1990 488.
6 abw 1991 532.
Es ist auch möglich, Variablen auszuschließen. Dazu setzt man ein Minuszeichen vor den Variablennamen. Mit select(gapminder, -co2)
erhält man einen Dataframe mit allen Variablen bis auf co2
.
Den Output des select
-Befehls kann man als eigenen Dataframe unter einem neuen Namen speichern, z.B.
<- select(gapminder,
gm_auswahl
VARIABLE1, VARIABLE2)
Wenn die nicht ausgewählten Spalten im weiteren Verlauf der Analyse nicht mehr gebraucht werden, kann man den Output unter dem alten Dataframe-Namen speichern.
<- select(gapminder,
gapminder
VARIABLE1, VARIABLE2)
In diesem Fall gehen alle nicht ausgewählten Variablen verloren.
4.2.3 mutate
Wir berechnen nun aus den vorhandenen Variablen eine neue Variable und fügen sie dem Datensatz hinzu. Im Gegensatz zu filter
und select
wird der Dataframe also nicht kleiner, sondern größer. Berechnet werden soll zunächst die Gesamtbevölkerung in jedem Land. Sie ergibt sich als Summe der Bevölkerungszahlen für die fünf Altersklassen,
= pop_0_14 + pop_15_19 + pop_20_39 + pop_40_59 + pop_60plus pop
Die Funktion zum Berechnen neuer Variablen aus schon vorhandenen Variablen lautet mutate
. Der Output von mutate
ist der alte Dataframe ergänzt um eine (oder auch mehrere) Spalten mit der neuen Variablen. Es ist oft sinnvoll, den Output unter dem alten Dataframe-Namen zu speichern. Auf diese Weise wächst der Dataframe um eine Spalte (oder mehrere).
<- mutate(gapminder,
gapminder pop = pop_0_14 + pop_15_19 + pop_20_39 + pop_40_59 + pop_60plus)
Wie bei select
und filter
hat die Funktion mutate
als erstes Argument einen Dataframe, das folgende Argument gibt an, welche neue Variable auf welche Weise aus welchen bisherigen Variablen errechnet werden soll. Die Funktion mutate
gibt den alten Dataframe mit der neuen zusätzlichen Spalte als Output zurück. Wir speichern den neuen, größeren Dataframe wieder unter dem Namen gapminder
. Der Dataframe ist nun um eine Variable breiter geworden.
head(gapminder)
# A tibble: 6 × 11
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 abw 1986 17467 4449 23256 13396 5989 2.32
2 abw 1987 17097 4103 23441 13838 5971 2.31
3 abw 1988 16779 3786 23499 14274 5996 2.29
4 abw 1989 16798 3653 23290 14786 6070 2.27
5 abw 1990 17453 3876 22691 15477 6218 2.25
6 abw 1991 18796 4531 21748 16321 6468 2.22
# ℹ 3 more variables: co2 <dbl>, gdp_pc <dbl>, pop <dbl>
Als nächstes berechnen wir die Höhe der jährlichen CO2-Emissionen (in t) pro Kopf. Da die gesamten CO2-Emissionen in 1000 t gemessen werden, ergibt sich die Pro-Kopf-Emission als \[
\frac{\text{CO}_2\times 1000}{\text{Population}}.
\] Der zugehörige mutate
-Befehl lautet
<- mutate(gapminder,
gapminder co2_pc = co2*1000/pop)
Man kann auch mehrere neue Spalten auf einmal erzeugen. Die Definitionen der neuen Variablen werden dann einfach durch Kommas getrennt. Um nicht nur die CO2-Emissionen pro Kopf, sondern auch das gesamte Bruttoinlandsprodukt auszurechnen, wäre der Befehl (den wir hier jedoch nicht ausführen):
<- mutate(gapminder,
gapminder co2_pc = co2*1000/pop,
gdp_ges = gdp_pc*pop)
Was passiert, wenn man als Variablennamen für die neue Variable den Namen einer schon vorhandenen Variable eingibt? In diesem Fall wird die alte Variable überschrieben. Solche Änderungen sind zwar erlaubt, aber meist nicht empfehlenswert, weil man leicht vergisst, ob schon die neue oder noch die alte Definition gilt.
4.2.4 Pipe %>%
Der sogenannte Pipe-Operator %>%
erlaubt es, eine Reihe von Funktionen in übersichtlicher Form nacheinander so auszuführen, dass der Output einer Funktion als Input für die nächste Funktion dient.
Im Abschnitt zu der Funktion filter
haben wir alle Beobachtungen aus Deutschland ausgewählt. Wenn wir vom Output dieser Funktion nur die Spalten year
, co2
und gdp_pc
ausgegeben haben möchten, können wir das durch select
erreichen. Die Funktionen werden also nacheinander ausgeführt:
dataframe → filter → select
Für solche hintereinander geschalteten Funktionen kann man den Pipe-Operator verwenden. Der Code sieht dann so aus:
%>% filter(country == "deu") %>% select(year, co2, gdp_pc) gapminder
# A tibble: 49 × 3
year co2 gdp_pc
<dbl> <dbl> <dbl>
1 1970 1026862. 17894.
2 1971 1038085. 18421.
3 1972 1042332. 19121.
4 1973 1086625. 19972.
5 1974 1063594. 20142.
6 1975 1003265. 20042.
7 1976 1091730. 21124.
8 1977 1053466. 21881.
9 1978 1080011. 22559.
10 1979 1118797. 23485.
# ℹ 39 more rows
Für eine bessere Lesbarkeit sind Zeilenumbrüche hilfreich. Ein Zeilenumbruch sollte immer nach dem Pipezeichen %>%
erfolgen. Die gleiche Befehlsabfolge sieht dann so aus:
%>%
gapminder filter(country == "deu") %>%
select(year,
co2, gdp_pc)
Was genau macht der Pipe-Operator?
Allgemein gesprochen schickt der Pipe-Operator das Ergebnis (Output) der Funktion auf der linken Seite als erstes Argument in die Funktion auf der rechten Seite. Hier ist ein sehr einfaches Beispiel:
16 %>% sqrt()
[1] 4
Die Reihe lässt sich verlängern:
16 %>% sqrt() %>% log()
[1] 1.386294
Dieser Ausdruck entspricht \(\ln(\sqrt{16})\).
Vergessen Sie beim Pipe-Operator nicht, dass das erste Argument in der Funktion auf der rechten Seite entfällt. In den Funktionen mutate
, filter
und select
wird also der Dataframe (als erstes Argument) nicht mehr angegeben. Betrachten Sie noch einmal die Pipe-Folge:
%>%
gapminder filter(country == "deu") %>%
select(year,
co2, gdp_pc)
Hier dient gapminder
als erstes Argument der Funktion filter
, und der Output der filter
-Funktion dient als erstes Argument der select
-Funktion. Der Pipe-Operator ist immer dann besonders einfach einzusetzen, wenn das erste Argument der Funktionen ein Dataframe ist. Die Funktionen des Pakets tidyverse
(wie mutate
, filter
, select
und einige weitere Funktionen, die wir erst später behandeln werden) haben diese Struktur.
4.3 Sortieren
Beim ersten Arbeiten mit einem Datensatz ist es oft hilfreich und interessant, den Dataframe auf verschiedene Weise zu sortieren. Beispielsweise können wir den Dataframe gapminder
nach der Größe des Pro-Kopf-Bruttoinlandsprodukts (in US-Dollar, inflationsbereinigt) aufsteigend sortieren (und nur die ersten Zeilen ausgeben lassen):
%>%
gapminder arrange(gdp_pc) %>%
head()
# A tibble: 6 × 12
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 mmr 1973 11834262 3038432 7737405 4735224 1820032 5.69
2 mmr 1970 11165354 2786178 7205620 4442925 1684035 5.96
3 mmr 1971 11392339 2875103 7376650 4541110 1729752 5.88
4 mmr 1972 11616284 2960809 7558940 4640752 1775163 5.79
5 mmr 1974 12044882 3107766 7912835 4819916 1866538 5.57
6 mmr 1975 12251389 3174573 8104947 4897276 1916092 5.46
# ℹ 4 more variables: co2 <dbl>, gdp_pc <dbl>, pop <dbl>, co2_pc <dbl>
Offensichtlich war das Pro-Kopf-Inlandsprodukt in den frühen 1970er Jahren in Myanmar besonders niedrig.
Wenn wir absteigend (“descending”) sortieren, ist der Output:
%>%
gapminder arrange(desc(gdp_pc)) %>%
head()
# A tibble: 6 × 12
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 are 1980 277016 59581 532705 124552 20196 5.51
2 are 1977 187350 56105 356541 87941 18925 5.84
3 are 1981 308443 61367 572107 137342 20920 5.42
4 lux 2007 87553 28247 136061 138574 89435 1.62
5 lux 2008 88216 28866 138087 141976 91492 1.61
6 are 1976 164589 46939 304883 78912 18857 5.97
# ℹ 4 more variables: co2 <dbl>, gdp_pc <dbl>, pop <dbl>, co2_pc <dbl>
Das höchste Pro-Kopf-Inlandsprodukt erzielten die Vereinigten Arabischen Emirate (are
) im Jahr 1980. Auch Luxemburg (lux
) gehört zu den besonders reichen Staaten.
Die Funktion top_n
gibt nur die \(n\) Zeilen mit den größten oder kleinsten Werten einer Variable aus. Zum Beispiel sind die fünf Beobachtungen mit den höchsten CO2-Emissionen in dem Dataframe gapminder
:
%>%
gapminder top_n(5, co2)
# A tibble: 5 × 12
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 chn 2013 252201905 87133084 429842988 408952651 197969678 1.6
2 chn 2014 254332681 84582788 424974096 414083119 207216983 1.61
3 chn 2015 255838329 82839200 421407899 416746198 216883821 1.62
4 chn 2017 259556777 80517491 416665926 418256116 235279647 1.63
5 chn 2018 260606877 79819811 414673234 418026446 243943100 1.64
# ℹ 4 more variables: co2 <dbl>, gdp_pc <dbl>, pop <dbl>, co2_pc <dbl>
Von allen Staaten emittiert also China (chn
) in den letzten Jahren die größte Menge an CO2 (absolut, nicht pro Kopf).
Wenn man in der Funktion top_n
einen negativen Wert für \(n\) angibt, werden nicht die \(n\) größten, sondern die \(n\) kleinsten Werte herausgesucht. Die Zeilen mit den neun niedrigsten Emissionen sind:
%>%
gapminder top_n(-9, co2)
# A tibble: 14 × 12
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 btn 1980 174212 38203 118739 65844 18261 6.55
2 bwa 1972 314079 66112 137991 75204 33219 6.58
3 kir 1970 25729 5765 14181 8106 3658 5.46
4 kir 1977 25375 6869 15769 8371 3513 5.03
5 kir 1978 24918 6997 15922 8207 3423 5.06
6 kir 1983 25208 7959 18634 8717 3605 4.99
7 kir 1984 25572 7928 19332 8842 3666 4.95
8 kir 1985 26109 7793 20093 8980 3734 4.91
9 kir 1986 26829 7603 20875 9155 3805 4.87
10 kir 1987 27681 7387 21642 9366 3872 4.83
11 kir 1988 28592 7173 22365 9603 3951 4.78
12 kir 1989 29528 7016 23000 9861 4031 4.74
13 kir 1990 30436 6948 23516 10126 4098 4.69
14 kir 1991 31286 6953 23874 10342 4161 4.64
# ℹ 4 more variables: co2 <dbl>, gdp_pc <dbl>, pop <dbl>, co2_pc <dbl>
Bhutan hatte also in den 1970er Jahren den niedrigsten Ausstoß von CO2 (wiederum werden hier nicht die Pro-Kopf-Größen betrachtet).
Achtung: Fehlende Werte werden bei der Bestimmung der größten bzw. kleinsten Werte ignoriert.
4.4 Kennzahlen
Große Datensätze sind oftmals schwer zugänglich, man spricht manchmal auch von “Datenfriedhöfen”. Um die Daten wirklich zum Sprechen zu bringen, brauchen wir Werkzeuge. Ein sehr wichtiges Werkzeug der Datenanalyse sind Kennzahlen (“summaries”). Die bekannteste Kennzahl ist sicherlich der Durchschnitt, auf den wir später im Kapitel 7.1 noch ausführlicher eingehen werden. Auch die Summe ist in vielen Situationen eine nützliche Kennzahl. In diesem Abschnitt lernen Sie zwei neue Funktionen kennen, mit denen die Datenanalyse vereinfacht wird: summarise
und group_by
. Außerdem wird noch die Funktion pull
vorgestellt, mit der die Resultate für die Weiterverarbeitung in R vorbereitet werden.
4.4.1 summarise
Die summarise
-Funktion erlaubt es, Kennzahlen auf eine intuitive und leicht lesbare Art zu berechnen. Wir starten mit einem einfachen Beispiel. Der Dataframe gapminder
enthält Angaben zu CO2-Emissionen in allen Ländern von 1970 bis 2018 (für viele Länder ist der Datenbestand zu Beginn leider nicht vollständig). Wir beschränken den Datensatz in diesem Beispiel auf alle Beobachtungen des Jahres 2018 und speichern die Auswahl unter dem Namen gm2018
.
<- filter(gapminder, year == 2018) gm2018
Der folgende Code berechnet die Summe der CO2-Emissionen aller Länder (in 1000 t) und die Summe der Bruttoinlandsprodukte aller Länder (in Billionen US-Dollar). Die Schreibweise 1e12
steht für \(1\times 10^{12}\), also eine Billion.
%>%
gm2018 summarise(co2welt = sum(co2),
gdpwelt = sum(gdp_pc*pop)/1e12) -> s
print(s)
# A tibble: 1 × 2
co2welt gdpwelt
<dbl> <dbl>
1 34890019. 81.9
Was passiert hier? Durch den summarise
-Befehl wird ein neuer Dataframe erzeugt und unter dem Namen s
gespeichert. Der neue Dataframe hat zwei Spalten und nur eine Zeile. Die Spaltennamen haben wir in der summarise
-Funktion festgelegt, andere Namen wären natürlich ebenso möglich gewesen. Die Funktion sum
ist eine interne R-Funktion.
Achtung: Am Ende der Pipe wird der endgültige Dataframe mit dem Pfeilsymbol ->
unter einem neuen Dataframe-Namen gespeichert. Hier darf man nicht das Pipe-Zeichen %>%
verwenden. Es ist auch möglich diese Zuweisung anders herum an den Anfang der Pipe zu setzen:
<- gapminder %>%
s filter(year == 2018) %>%
summarise(co2welt = sum(co2),
gdpwelt = sum(gdp_pc*pop)/1e12)
Welche Variante man bevorzugt, ist Geschmackssache.
4.4.2 group_by
Sehr oft berechnet man Kennzahlen nicht nur für die gesamte Population, sondern auch für Teilgruppen. Zum Beispiel können wir die Summe der CO2-Emissionen für jedes Jahr getrennt errechnen. In diesem Fall werden die Beobachtungen nach der Variable year
in Gruppen zusammengefasst. Für jede Gruppe berechnen wir dann die Summe (also die CO2-Weltemissions des jeweiligen Jahres). Um die Gruppen zu definieren, verwenden wir die Funktion group_by
.
<- gapminder %>%
s group_by(year) %>%
summarise(weltco2 = sum(co2))
Die letzten 10 Zeilen des Outputs sehen so aus:
tail(s,10)
# A tibble: 10 × 2
year weltco2
<dbl> <dbl>
1 2009 30039655.
2 2010 31576625.
3 2011 32699321.
4 2012 33217665.
5 2013 33384759.
6 2014 33631760.
7 2015 33633380.
8 2016 33719121.
9 2017 34128587.
10 2018 34890019.
Die Summe der gesamten CO2-Emissionen kann für die Jahre vor 2002 nicht berechnet werden (bzw. sie ist dort NA
), weil in diesen Jahren nicht für alle Länder die CO2-Emissionen gegeben sind. Erst ab 2002 sind die Angaben vollständig.
Der Befehl group_by(year)
verändert den Dataframe kaum sichtbar. Er legt nur fest, dass die Beobachtungen des Dataframes nach Jahren gruppiert werden. Man spricht daher auch von einem “gruppierten Dataframe”. Viele Funktionen des tidyverse
-Pakets reagieren auf die Gruppierung. So berechnet die Funktion summarise
die Kennzahlen jetzt für jede Gruppe einzeln und erstellt einen entsprechenden neuen Dataframe (der hier s
genannt wird). Der neue Dataframe, den der summarise
-Befehl liefert, hat diese Eigenschaften:
- Der neue Dataframe hat so viele Zeilen wie es Gruppen gibt.
- Die erste Spalte des neuen Dataframes zeigt alle Ausprägungen der Gruppierungsvariable.
- Die zweite Spalte enthält die Kennzahlen, die für die Gruppen mit
summarise
berechnet wurden. - Wenn mehrere Kennzahlen berechnet werden, gibt es für jede Kennzahl eine Spalte.
4.4.3 pull
Als Ergebnis der summarise
-Funktion erhalten wir - rein formal gesehen - immer einen Dataframe, selbst wenn es sich nur um eine einzige Zahl handelt. Das kann problematisch werden, wenn wir die Ergebnisse in anderen R-Funktionen weiterverwenden wollen, die numerische Vektoren als Input erwarten. Es gibt jedoch einen einfachen Weg, die Werte einer Spalte als numerischen Vektor aus einem Dataframe heraus zu ziehen. Die Funktion, die das leistet, heißt pull
. Ein Beispiel zur Illustration:
%>%
gapminder filter(year == 2018) %>%
summarise(weltco2 = sum(co2)) %>%
pull(weltco2) -> x
print(x)
[1] 34890019
class(x)
[1] "numeric"
Die Pipe-Kette wählt aus dem Dataframe gapminder
alle Beobachtungen des Jahres 2018 aus. Anschließend wird die Summe aller CO2-Emissionen (in 1000 t) berechnet. An dieser Stelle wird normalerweise ein Dataframe (mit nur einer Zeile und einer Spalte) ausgegeben. Durch die Weiterleitung in die pull
-Funktion wird aber der Inhalt der Spalte weltco2
als numerisches Objekt herausgezogen und letztlich als x
gespeichert. Die class
-Funktion zeigt, dass es sich bei x
nicht mehr um einen Dataframe, sondern um eine Zahl handelt.
4.5 Doppelungen
Ein Fehler, der in Datensätzen gelegentlich auftritt, sind Doppelungen. Eine Beobachtung, die nur als eine Zeile im Datensatz vorkommen sollte, wird versehentlich in einer zweiten, identischen Zeile wiederholt. Das kann natürlich auch mehrere Beobachtungen betreffen. In großen Datensätzen kann man dieses Problem nicht “per Hand” lösen. Die Funktion distinct
aus dem tidyverse
-Paket hilft weiter.
Das erste Argument der Funktion distinct
ist (wie bei quasi allen Funktion aus dem tidyverse
-Paket) der Dataframe. Wenn keine weiteren Argument angegeben sind, werden alle Zeilen aus dem Dataframe entfernt, bei denen alle Variablenwerte identisch sind. Das lässt sich am einfachsten an einem kleinen Beispiel veranschaulichen.
Beispiel:
Der Dataframe D
enthält nur sechs Beobachtungen von vier Variablen.
<- data.frame(Var1=c(3,4,5,4,2,4),
D Var2=c(1999,2000,2004,2000,2003,2000),
Var3=c(834,1221,1204,1221,976,857),
Var4=c(0,1,1,1,0,0))
D
Var1 Var2 Var3 Var4
1 3 1999 834 0
2 4 2000 1221 1
3 5 2004 1204 1
4 4 2000 1221 1
5 2 2003 976 0
6 4 2000 857 0
In diesem Datensatz sind die Zeilen 2 und 4 komplett identisch. Die Doppelung wird durch die Funktion distinct
entfernt:
distinct(D)
Var1 Var2 Var3 Var4
1 3 1999 834 0
2 4 2000 1221 1
3 5 2004 1204 1
4 2 2003 976 0
5 4 2000 857 0
In den meisten Fällen wird man den bereinigten Datensatz unter dem gleichen Namen (hier: D
) oder unter einem neuen Namen abspeichern.
<- distinct(D) D_neu
Mit der Funktion distinct
kann man auch Zeilen entfernen, in denen nur manche Variablen identische Werte annehmen, andere Variablen hingegen nicht. So sind in dem Beispiel von oben die ersten beiden Variablenwerte der sechsten Zeile identisch zu den Werten in den Zeilen 2 und 4 (die Variablen Var3
und Var4
nehmen jedoch andere Werte an). Wenn eine Doppelung nur für bestimmte Variablen relevant ist, kann man diese Variablen als Argumente in der distinct
-Funktion angeben.
distinct(D, Var1, Var2)
Var1 Var2
1 3 1999
2 4 2000
3 5 2004
4 2 2003
In diesem Fall werden die restlichen Variablen standardmäßig entfernt. Um sie im Datensatz zu belassen, dient die Option .keep_all
(mit einem Punkt am Anfang). Das sieht dann so aus:
distinct(D, Var1, Var2, .keep_all=TRUE)
Var1 Var2 Var3 Var4
1 3 1999 834 0
2 4 2000 1221 1
3 5 2004 1204 1
4 2 2003 976 0
Wie alle Funktionen aus dem tidyverse
-Paket, lässt sich auch die Funktion distinct
in eine Pipe integrieren.
4.6 Merging
Wenn Daten, die man gemeinsam analysieren will, in zwei getrennten Dataframes vorliegen, müssen sie zusammengespielt werden (engl. merge). Oftmals möchte man auch zusätzliche Informationen, die aus einem Datensatz errechnet wurden, an einen Dataframe anfügen. Zur Erinnerung: In einem Dataframe in “sauberem Format” ist jede Spalte eine Variable und jede Zeile eine Beobachtung. Wenn wir zwei Dataframes zusammenführen möchten, sind darum zwei grundsätzlich unterschiedliche Situationen zu unterscheiden:
Es kommen weitere Beobachtungen hinzu, d.h. der Dataframe erhält neue Zeilen, er wird länger.
Es kommen weitere Variablen hinzu, d.h. der Dataframe erhält neue Spalten, er wird breiter.
Wir behandeln diese beiden Fälle nacheinander. Beide Fälle können recht komplex werden und es gibt mehrere Möglichkeiten, damit umzugehen. Wir beschränken uns auf zwei einfache und für die praktische Anwendung wichtige Situationen.
4.6.1 bind_rows
Mit dem Befehl bind_rows
werden Beobachtungen (Zeilen) ergänzt. Der Dataframe wird dadurch länger. Das ist beispielsweise relevant, wenn ein Dataframe aktualisiert werden muss, weil neue Beobachtungen erhoben wurden, die unten an den bereits bestehenden Dataframe angehängt werden sollen. Achten Sie darauf, dass die Spaltennamen der beiden Dataframes exakt gleich sein müssen, wenn Sie sie zusammenführen, denn sonst werden die Spalten als unterschiedliche Variablen interpretiert.
Beispiel:
Die letzten sechs Zeilen des Dataframes gapminder
sehen so aus:
tail(gapminder)
# A tibble: 6 × 12
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 zwe 2013 5879046 1456881 4157307 1403405 658781 3.96
2 zwe 2014 5981856 1512159 4227568 1454076 680093 3.9
3 zwe 2015 6068598 1575412 4295900 1514437 700589 3.84
4 zwe 2016 6144984 1637915 4366371 1583583 719853 3.76
5 zwe 2017 6217927 1690993 4444845 1659646 737689 3.68
6 zwe 2018 6291631 1732035 4533425 1741067 754028 3.61
# ℹ 4 more variables: co2 <dbl>, gdp_pc <dbl>, pop <dbl>, co2_pc <dbl>
Wir möchten nun zwei Zeilen ergänzen, und zwar die Daten für Zimbabwe (zwe
) von 2019 und 2020. Diese beiden Beobachtungen liegen in dem Dataframe gm_neu
vor, der wie folgt aussieht:
gm_neu
# A tibble: 2 × 14
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 zwe 2019 6217927 1690993 4444845 1659646 737689 3.68
2 zwe 2020 6291631 1732035 4533425 1741067 754028 3.61
# ℹ 6 more variables: co2 <dbl>, gdp_pc <dbl>, pop <dbl>, co2_pc <dbl>,
# fert <dbl>, co2pc <lgl>
Die neuen Beobachtungen werden nun durch bind_rows
an den Dataframe gapminder
angehängt. Der neue, längere Dataframe kann unter dem alten Namen (gapminder
) oder unter einem neuen Namen abgespeichert werden (hier z.B. unter dem Namen gm_longer
).
<- bind_rows(gapminder, gm_neu)
gm_longer tail(gm_longer,8)
# A tibble: 8 × 14
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 zwe 2013 5879046 1456881 4157307 1403405 658781 3.96
2 zwe 2014 5981856 1512159 4227568 1454076 680093 3.9
3 zwe 2015 6068598 1575412 4295900 1514437 700589 3.84
4 zwe 2016 6144984 1637915 4366371 1583583 719853 3.76
5 zwe 2017 6217927 1690993 4444845 1659646 737689 3.68
6 zwe 2018 6291631 1732035 4533425 1741067 754028 3.61
7 zwe 2019 6217927 1690993 4444845 1659646 737689 3.68
8 zwe 2020 6291631 1732035 4533425 1741067 754028 3.61
# ℹ 6 more variables: co2 <dbl>, gdp_pc <dbl>, pop <dbl>, co2_pc <dbl>,
# fert <dbl>, co2pc <lgl>
4.6.2 left_join
Das Anspielen einer oder mehrerer neuer Variable an einen Dataframe ist fehleranfällig und nicht ganz leicht, weil sichergestellt sein muss, dass jede neue Beobachtung in der richtigen Zeile gespeichert wird. Oft hat der Dataframe mit den neuen Variablen eine andere Länge als der Dataframe, an den die Variablen angehängt werden sollen. Oder die Beobachtungen liegen in einer anderen Reihenfolge vor. Um ganz sicher zu sein, dass jede Beobachtung der richtigen Zeile zugewiesen wird, hilft ein Identifier (ID-Variable). Der Identifier dient dazu, die Beobachtungen in den beiden Dataframes selbst dann eindeutig zu identifizieren, wenn sie nicht in der gleichen Zeile stehen.
Das lässt sich am besten an einem einfachen Beispiel illustrieren.
Beispiel:
Die Daten in einem kleinen Dataframe D
sehen so aus:
<- data.frame(id=1:5,
D x=c(3,4,3,1,1),
y=c(20,20,15,25,22))
print(D)
id x y
1 1 3 20
2 2 4 20
3 3 3 15
4 4 1 25
5 5 1 22
In einem weiteren Datframe D2
gibt Angaben zu den drei Variablen a
, b
und c
, und zwar folgende:
<- data.frame(id=c(2,1,5,4),
D2 a=c(1,4,3,2),
b=c(5,5,4,5),
c=c(9,9,8,8))
print(D2)
id a b c
1 2 1 5 9
2 1 4 5 9
3 5 3 4 8
4 4 2 5 8
Die Variable id
ist der Identifier (jeder beliebige Variablenname ist hier möglich). Er kommt in beiden Datensätzen vor und dient dazu, die Beobachtungen richtig zuzuordnen. Zum Beispiel sagt die erste Zeile von D2
, dass die zugehörigen Werte von a
, b
und c
in die zweite Zeile von D
gehören. Offenbar enthält D2
die Beobachtungen in einer anderen Reihenfolge, und eine Beobachtung mit id=3
fehlt.
Der Dataframe D2
wird nun mit dem Befehl left_join
an D
angespielt. Es ergibt sich:
print(left_join(D, D2, by="id"))
id x y a b c
1 1 3 20 4 5 9
2 2 4 20 1 5 9
3 3 3 15 NA NA NA
4 4 1 25 2 5 8
5 5 1 22 3 4 8
Der neue, breitere Dataframe kann unter dem alten Namen oder unter einem neuen Namen abgespeichert werden (hier im Beispiel wird er gar nicht gespeichert).
Noch ein Beispiel:
Der Identifier muss nicht unbedingt eindeutig sein. Es ist durchaus erlaubt, dass mehrere Beobachtungen den gleichen Wert des Identifiers haben, wie dies Beispiel zeigt. Der (fiktive) Dataframe X
enthält Angaben zum nominalen (d.h. nicht inflationsbereinigten) Einkommen von drei Personen in drei Jahren.
<- data.frame(jahr=rep(2020:2022,3),
X person=rep(1:3,each=3),
nominal=c(1000,1200,1250,800,900,1000,2500,2400,2500))
X
jahr person nominal
1 2020 1 1000
2 2021 1 1200
3 2022 1 1250
4 2020 2 800
5 2021 2 900
6 2022 2 1000
7 2020 3 2500
8 2021 3 2400
9 2022 3 2500
Um die nominalen Größen in reale Größen umzurechnen, verwendet man einen Preisindex (an dieser Stelle fragen wir nicht danach, wie ein solcher Index gebildet wird). Die realen Größen sind der Quotient aus dem nominalen Wert und dem Preisindex, der in dem Jahr galt.
Die (fiktiven) Werte des Preisindex sind im Dataframe preise
enthalten:
<- data.frame(jahr=c(2020,2021,2022),
preise index=c(1.00,1.05,1.11))
preise
jahr index
1 2020 1.00
2 2021 1.05
3 2022 1.11
Mit Hilfe des Befehls left_join
können wir den Index für jedes Jahr als neue Variable an den Dataframe X
anfügen. Zum Verknüpfen dient die Spalte jahr
, die in beiden Dataframes vorkommt und hier als Verknüpfungsvariable dient. Es ist also durchaus möglich, dass ein Wert an mehrere Beobachtungen angespielt wird.
<- left_join(X, preise, by="jahr")
X X
jahr person nominal index
1 2020 1 1000 1.00
2 2021 1 1200 1.05
3 2022 1 1250 1.11
4 2020 2 800 1.00
5 2021 2 900 1.05
6 2022 2 1000 1.11
7 2020 3 2500 1.00
8 2021 3 2400 1.05
9 2022 3 2500 1.11
Wie der Befehlsname left_join
schon nahelegt, gibt es noch andere Möglichkeiten, Dataframes zusammenzuführen, z.B. right_join
oder full_join
. Wir werden sie in diesem Kurs aber nicht brauchen. Wer sich für andere Arten des Anspielens interessiert, kann sich über die Hilfsfunktionen und Cheatsheets informieren.
Drittes Beispiel: Gapminder Gesundheitsdaten
In diesem dritten Beispiel wird gezeigt, wie man weitere Variablen an den Gapminder-Datensatz anspielt. Hier ist die Schwierigkeit, dass es zwei Identifier gibt, nämlich das Land (country
) und das Jahr (year
). Wir nehmen als Ausgangspunkt den Dataframe gapminder
, dessen ersten Zeilen so aussehen:
head(gapminder)
# A tibble: 6 × 12
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 abw 1986 17467 4449 23256 13396 5989 2.32
2 abw 1987 17097 4103 23441 13838 5971 2.31
3 abw 1988 16779 3786 23499 14274 5996 2.29
4 abw 1989 16798 3653 23290 14786 6070 2.27
5 abw 1990 17453 3876 22691 15477 6218 2.25
6 abw 1991 18796 4531 21748 16321 6468 2.22
# ℹ 4 more variables: co2 <dbl>, gdp_pc <dbl>, pop <dbl>, co2_pc <dbl>
An diesen Dataframe soll nun ein zweiter Dataframe mit einigen Gesundheitsvariablen angespielt werden. Wir laden diesen zweiten Datensatz (der auch im Learnweb zu finden ist).
<- read_csv("../data/gapminderhealth.csv") gm_health
Warning: One or more parsing issues, call `problems()` on your data frame for details,
e.g.:
dat <- vroom(...)
problems(dat)
Die ersten Zeilen sehen so aus:
head(gm_health)
# A tibble: 6 × 9
country year lifexpF lifexpM diarrh hiv malaria mening pneumon
<chr> <dbl> <dbl> <dbl> <lgl> <lgl> <lgl> <lgl> <lgl>
1 abw 1970 71.6 63.7 NA NA NA NA NA
2 abw 1971 72.0 64.1 NA NA NA NA NA
3 abw 1972 72.8 64.5 NA NA NA NA NA
4 abw 1973 73.5 64.9 NA NA NA NA NA
5 abw 1974 73.9 65.3 NA NA NA NA NA
6 abw 1975 74.3 65.4 NA NA NA NA NA
Der Datensatz enthält die Variablen lifexpF
und lifexpM
(Lebenserwartung der Frauen und Männer) sowie die Zahl von Todesfällen von Kindern bis zum Alter von 5 Jahren an Durchfall (diarrh
), HIV (hiv
), Malaria (malaria
), Hirnhautentzündung (mining
) und Lungenentzündung (pneumon
). Die Zahl der verstorbenen Kinder wird auf 1000 Geburten bezogen, sie gibt also an, wie viele von 1000 geborenen Kindern in den ersten Lebensjahren an diesen Krankheiten gestorben sind.
Der Dataframe gm_health
wird nun an den Dataframe gapminder
angefügt. Es gibt zwei Identifier-Variablen, nämlich country
und year
. Sie werden durch die Funktion c
zusammengefasst und als Argument by
übergeben. Der neue, breitere Dataframe wird unter dem Namen gm_wider
gespeichert.
<- left_join(gapminder, gm_health,
gm_wider by=c("country","year"))
Dieser neue Dataframe hat die Variablen (Spalten)
names(gm_wider)
[1] "country" "year" "pop_0_14" "pop_15_19" "pop_20_39"
[6] "pop_40_59" "pop_60plus" "fertility" "co2" "gdp_pc"
[11] "pop" "co2_pc" "lifexpF" "lifexpM" "diarrh"
[16] "hiv" "malaria" "mening" "pneumon"
Die ersten Zeilen des verbreiterten Dataframes lauten (der Dataframe ist zu breit, um hier in kompletter Zeilenlänge angezeigt werden zu können):
head(gm_wider)
# A tibble: 6 × 19
country year pop_0_14 pop_15_19 pop_20_39 pop_40_59 pop_60plus fertility
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 abw 1986 17467 4449 23256 13396 5989 2.32
2 abw 1987 17097 4103 23441 13838 5971 2.31
3 abw 1988 16779 3786 23499 14274 5996 2.29
4 abw 1989 16798 3653 23290 14786 6070 2.27
5 abw 1990 17453 3876 22691 15477 6218 2.25
6 abw 1991 18796 4531 21748 16321 6468 2.22
# ℹ 11 more variables: co2 <dbl>, gdp_pc <dbl>, pop <dbl>, co2_pc <dbl>,
# lifexpF <dbl>, lifexpM <dbl>, diarrh <lgl>, hiv <lgl>, malaria <lgl>,
# mening <lgl>, pneumon <lgl>