Die grundlegenden Funktionen für das Benutzen von R kennen Sie nun. Im Laufe des Seminars werden wir viele dieser Funktionen wiederholt benutzen, und damit üben. Diese Fuktionen sind implementiert im sog. baseR Paket des Programs. Wenn Sie jedoch in Zukunft einmal größere und komplexere Operationen vornehmen, dann gibt es deutlich effizientere und mächtigere Pakete. Eines davon ist das Paket tidyverse. Dieses hat während der vergangenen Jahre enorm an Popularität gewonnen und wird mehr und mehr genutzt. Wir wollen daher dieses Seminar auch dazu nutzen, Sie mit dem Paket tidyverse frühzeitig in Kontakt zu bringen. Natürlich können wir in dem begrenzten Rahmen lediglich einzelne grundlegende Funktionen beibringen - wir ermutigen Sie jedoch, selbstständig weiter nach Funktionen zu suchen und recherchieren. Nach jedem Kapitel werden wir daher weitere Quellen zur Verfügung stellen.
So ist es auch im Fall von tidyverse. Dieses Skript hier hat nicht den Anspruch auf Vollständigkeit, sondern gibt eine kurze Einführung in Befehle und Funktionen, welche wir in der jeweiligen Woche brauchen. Viele Erläuterungen und Hintergründe basieren auf diesem Online Skript.
Tibble
Das tibble ist im Prinzip eine Weiterentwickung des Data Frames in baseR - es handelt sich also um eine Tabelle. Allerdings gibt es Regeln, die dazu führen, dass die Daten in einem tibble sauberer und konsistenter abgespeichert werden. Insbesondere sind Spaltenname in einem tibble syntaktisch korrekt und folgen den Regeln für Variablennamen in R. Dies bedeutet, dass sie keine Leerzeichen enthalten und andere spezielle Zeichen vermieden werden. tibbles versuchen zudem, die Datenklasse (z. B. numerisch, character, etc.) jeder Spalte so gut wie möglich beizubehalten. Dies unterscheidet sich von herkömmlichen Datenrahmen, die manchmal automatisch Datentypen konvertieren. Daraus ergibt sich, dass tibbles ein einfacheres und konsistenteres subsetting (d.h., ausschneiden von Teilen) erlauben.
Zur besseren Orientierung laden wir einmal einen Datensatz ein. Mit der Funktion slice_head() können wir uns die oberen Zeilen ausgeben lassen.
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 4.0.1 ✔ tibble 3.2.1
✔ lubridate 1.9.4 ✔ tidyr 1.3.1
✔ purrr 1.0.4
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Wie Sie sehen, gibt es für unseren Anwendungen erst einmal keine großen Unterschiede - und während der ersten Wochen brauchen Sie sich keine großen Gedanken zu machen. Wenn Sie jedoch jetzt shcon tiefer eintauchen wollen, dann empfehle ich Ihnen dieses Online-Skript.
Der %>% Operator (pipe-Operator)
Was Sie jedoch häufiger sehen werden, ist der sog. Pipe-Operator %>%. Dieser erlaubt es Ihnen, mehrere (im Prinzip unbegrenzt viele) Operationen durchzuführen, ohne jedes Zwischenergebnis auf einer neuen variablen abspeichern zu müssen. Dies klingt erstmal nicht sehr spektakulär, aber es vereinfacht Ihren Code ganz erheblich. Wir werden immer mal wieder diesen Operator benutzen, in Woche I z.B. im Kontext von Selektionen.
Im Grundsatz ist die Funktionsweise des %>% Operators wie folgt: auf das Objekt links des Operators wird die Operation rechts des Operators angewandt. Dieses Prozedur kann beliebig oft wiederholt werden, sodass am Ende z.B. eine Operation lauten kann: ergebnis <- data %>% Operation01 %>% Operation02 %>% Operation03 Dabei wird Operation01 auf Data Frame (zw. den tibble) angewandt. Auf das Ergebnis der Operation wird dann Operation02 angewandt, usw. weiter unten werden wir uns ein paar Beispiele anschauen, wodurch dies dann klarer wird.
Als shortcut zu Schreiben des %>%-Operators in R können Sie die Tastenkombination Strg+Umschalt+M verwenden.
Gängige Funktionen im tidyverse
Die Anzahl der möglichen Operationen im Paket tidyverse sind sehr umfangreich, und im Rahmen dieses Kurses (und möglicherweise weiteren Kursen während Ihres Studiums) werden wir nicht alle benötigen. Es gibt jedoch eine Auswahl von ca. 10-15 Funktionen, die man immer wieder benutzen wird. Keine Angst: Sie müssen diese nicht alle auswendig können oder gar aus dem *ff** beherrschen. Jedes Mal, wenn wir eine Funktion anwenden, werden wir sie detailliert erläutern.
Die am häufigsten Funktionen sind:
filter() - Auswahl von Zeilen, basierend auf einem Kriterium (oder mehreren Kriterien) der Spalten \(\rightarrow\) siehe Beispiel weiter unten.
select() - Auswählen von Spalten
rename() - Umbennen von Spaltenname
arrange() - Umsortieren von Spalten
mutate() - Erstellen von neuen Variablen
group_by() - Gruppieren von Variablen
summarize() - Zusammenfassen von Variablen (d.h., Spalten) innerhalb eines Datensatzes
left_join() - spaltenweises Zusammenfügen von mehreren Datensätzen
tally() - liefert die Gesamtsumme der Werte der angegebenen Spalte(n) oder die Anzahl der Zeilen im Tibble
count() - liefert die Anzahl der eindeutigen Werte der angegebenen Spalten
add_count() - count()-Werte als neue Spalte hinzufügen
glimpse() - einen Überblick über die im Datensatz enthaltenen Daten zu erhalten
pull() - das Ergebnis einer vorangegangenen Operation als Einzelwert oder Vektor erhalten
pivot_longer() - Umwandlung vom wide ins long Format
pivot_wider() - Umwandlung vom long ins wide Format
na.rm = TRUE - Argument in vielen Funktionen zum Umgang mit fehlenden Werten
drop = TRUE - Argument beim Extrahieren einzelner Werte aus tibbles
Das klingt erstmal ziemlich komplex und überwältigend? Das stimmt - und ich kann mich nur wiederholen, dass wir nicht von Ihnen erwarten, dass Sie die Funktionen können am Ende des Kurses. Dennoch hilft es m.E. wenn man frühzeitig von solchen Funktionen gehört hat.
Am einfachsten ist es, wenn Sie die Fnktionen “einfach mal anwenden” - so gehe ich zumindest immer an neue Sachen, und bisher hat es geholfen. Sie können z.B. die Daten aus der Übungsaufgabe nehmen und dann Stück für Stück die ein oder andere Funktion ausprobieren. Wir haben gelernt, die Daten wie folgt einzuladen:
in einem ersten Schritt wandeln fassen wir die beiden Vektoren zu einem Data Frame zusammen und konvertieren die Daten von °F in °C. Zusätzlich berechnen wir eine Spalte datum, welche die Tage von 1.10.2023 bis zum 31.10.2023 als Datum formatiert enthält.
Die erste Funktion des Pakets tidyverse, die wir nutzen ist die Funktion filter. Diese Funktion wird verwendet, wenn man einen Data Frame (d.h., eine Tabelle) verkleinern will basierend auf einem Kriterium in einer Spalte. Zum Beispiel könnten wir sagen, dass wir aus der obigen Tabelle alle Zeilen rauswerfen wollen, bei denen die Temperatur an der Dachstation kleiner als 15°C ist. Wir kontrollieren unsere Abfrage, indem wir vor und nach der Operation die Anzahl der Zeilen ermitteln:
# Anzahl der Zeilen VOR der filter()-Operationnrow(df)
[1] 31
df_sub <- df %>%filter(dach >15)nrow(df_sub)
[1] 7
Was haben wir gemacht? Wir haben unseren Data Frame df genommen, und die Funktion filter() darauf angewandt. Als “Bezug” zwischen Data Frame und filter() haben wir den %>%-Operator genommen. Das ergebnis haben wir auf eine neue Variable df_sub geschrieben. Experimentieren Sie ein wenig herum, und verändern Sie den filter().
Sie können auch komplexere Filter anwenden. Zum Beispiel könnten wir fragen: An welchem Tag im Oktober ist die Tempratur im Garten am höchsten?. Übersetzt heißt dass, dass wir (a) die Maximaltemperatur der Gartenstation ermitteln müssen, und dann (b) einen Filter anwenden, welcher diesen Maximalwert abfragt. Punkt (a) haben wir schon im vorherigen Kapitel kennengelernt.
# Ermitteln des MaximalwertsmaxGarten <-max(df$garten)# Anwendung des Filtersdf %>%filter(garten == maxGarten)
garten dach datum
1 17.35 17.65 2023-10-17
Und schon haben wir die entsprechende Information. Probieren Sie es aus: wie sähe das Ergebnis aus für die Minimumtemperatur der Dachstation? Die Abfrage ist sehr ähnlich.
Zusätzliche wichtige Funktionen
Die Funktion rbind()
Mit rbind() können mehrere Datensätze zeilenweise zusammengefügt werden. Dies ist nützlich, wenn Sie Daten aus verschiedenen Quellen kombinieren möchten:
# Beispiel: Zwei separate Datensätzedf_teil1 <- df[1:10, ]df_teil2 <- df[11:20, ]# Zusammenfügendf_kombiniert <-rbind(df_teil1, df_teil2)nrow(df_kombiniert)
[1] 20
Die Funktion pull()
pull() extrahiert eine einzelne Spalte als Vektor, was für weitere Berechnungen hilfreich ist:
# Extrahieren der Garten-Temperaturen als Vektorgarten_werte <- df %>%pull(garten)class(garten_werte)
[1] "numeric"
length(garten_werte)
[1] 31
Das Argument drop = TRUE
Das Argument drop = TRUE wird beim Extrahieren einzelner Werte aus tibbles verwendet. Es bestimmt, ob die Struktur des tibbles beibehalten wird oder ob ein einfacherer Datentyp (wie ein Vektor) zurückgegeben wird:
# Erstellen eines tibbles zur Demonstrationtib <-as_tibble(df)# Mit drop = FALSE (Standard bei tibbles) - behält tibble-Strukturergebnis_tibble <- tib[1:3, "garten", drop =FALSE]class(ergebnis_tibble)
In den meisten statistischen Funktionen müssen Sie explizit angeben, wie mit fehlenden Werten (NA) umgegangen werden soll:
# Beispiel mit NA-Wertenbeispiel_daten <-c(10, 15, NA, 20, 25, NA, 30)# Ohne na.rm=TRUE gibt mean() NA zurückmean(beispiel_daten)
[1] NA
# Mit na.rm=TRUE werden NA-Werte ignoriertmean(beispiel_daten, na.rm =TRUE)
[1] 20
Wechseln zwischen long und wide Format
Bisher haben wir die Tabellen ein für uns intuitives Format gehabt: die Werte einzelner Variablen (in unserem Fall dach und garten) sind in individuellen Spalten untergebracht. Obwohl das für die Übersicht der Daten gut ist, ist es bei Datenzusammenfassungen oder beim Erstellen von Gruppengrafiken (siehe nächstes Kapitel zum Erstellen von Grafiken) die Tabelle ein wenig anders anzuordnen. Man spricht hierbei auch vom sogenannten long-Format. Im “long”-Format ist jede Beobachtung in einer eigenen Zeile, und es gibt Spalten, welche die Werte der Beobachtungen und Metadaten beschreiben. Typischerweise gibt es eine Spalte, die die Art der Messung oder Variable angibt, eine Spalte, die die Werte dieser Variable enthält, und gegebenenfalls andere Spalten, die zusätzliche Informationen enthalten. Das Paket tidverse gibt uns Werkzeuge an die Hand, mit denen dies einfach möglich ist. Wir wenden die Funktion pivot_longer() einmal an, um den Unterschied festzustellen:
Schauen Sie sich die Tabelle genau an: nun sind die Spalten für dach und garten untereinander angeordnet, sortiert nach der Variable datum. Definiert haben wir dies durch das Funktionsargument cols=c(), in welchem wir die Variablen angegeben haben, die wir untereinander angeben wollen; mit dem Argument names_to= haben wir der neuen Spalte einen einprägsamen Namen gegeben.
Die Tabelle wird dadurch länger und möglicherweise weniger intuitiv zum lesen; aber die Funktionalität erhöht sich massiv. Wir lernen in ein paar Wochen, wie wir einfache Berechnungen nun durchführen können - zudem können wir auomatisiert mehrere Grafiken mit wenigen Code-Zeilen erstellen (mehr dazu im nächsten Kapitel).
Natürlich können wir die Tabelle auch wieder in das *wide+-Format zurückwandeln: