Hej Leute,

heute stelle ich Euch ein super nützliches R-Package namens dplyr vor. Dieses dient der sogenannten Datenmanipulation. Damit ist aber nicht die negative Bedeutung von Manipulation, also Fälschung gemeint, sondern einfach häufige Aufgaben wie neue Spalten zu einer Tabelle hinzufügen, eine Tabelle nach bestimmten Werten zu filtern (wie der Filter in Excel) oder auch nach Klassen zu gruppieren.

Keine Angst, wir gehen Schritt für Schritt vor. Ich erkläre, wie ihr das Package installiert und dann schauen wir uns die wichtigsten R-Befehle von dplyr an, natürlich alle mit Beispielen versehen. Und am Ende kommen wir dann zu JOINs, also dem Verbinden von zwei data.frames. Das ist ein ganz wichtiges Konzept beim Arbeiten mit Datenbanken. Dazu gibt es noch ein praktisches Cheat Sheet, also eine Übersichtsseite zum Nachschlagen. Die könnt ihr kostenlos herunterladen und ausdrucken.

Der Artikel ist doch ziemlich lang geworden, ich will euch ja nichts vorenthalten. Wer es eilig hat und einfach nur einen der dplyr-Funktionen anwenden will, springt einfach zum entsprechenden Abschnitt:

Für die vier join-Varianten von dplyr habe ich für euch eine Übersichtsseite zusammenstellt, die hoffentlich nützlich ist. Der Link ist im letzten Abschnitt Zwei Datensätze miteinander verbinden.

Was ist das R-Package dplyr?

Dplyr wurde 2014 von Hadley Wickham entwickelt (https://blog.rstudio.com/2014/01/17/introducing-dplyr/) und hat sich seitdem rasant verbreitet. Wie oben schon geschrieben erleichtert das Package die Aufbereitung von Datensätzen, indem es einfach zu nutzende Funktionen für die üblichen Aufgaben bereitstellt wie z.B. für die Auswahl von Spalten (select), nach gewissen Kriterien die Zeilen filtern (filter) oder Werte zu aggregieren (summarise). Der zu bearbeitende Datensatz muss als data.frame oder tibble (die data.frame-Variante im tidyverse) vorliegen, also einer Tabelle mit mehreren Spalten und vielen Zeilen.

Im Prinzip sind viele diese Aufgaben vergleichbar mit dem SQL-Befehl select. Ist ja auch logisch, in SQL geht es schließlich auch um die Verarbeitung von Tabellen. Man könnte also für viele Befehle auch das Package sqldf nehmen, welches es erlaubt, SQL-Befehle auf data.frames loszulassen. Macht natürlich nur Sinn, wenn man sich ein wenig mit SQL auskennt. Ein ausführlicher Artikel ist in Planung, aktuell müsst ihr euch noch mit einem R-Bite, also nur einem Mini-Happen, zu SQL-Befehlen in R mit sqldf begnügen.

Die Stärke von dplyr liegt im klar strukturierten Aufbau: Die Befehle sind als Verb benannt. Das erste Argument ist immer die Datentabelle (data.frame), die weiteren Argumente beschreiben, was genau zu tun ist und als Rückgabe gibt es wieder einen data.frame.

dplyr vs. data.table

Als Alternative möchte ich noch das Package data.table nennen. Mittlerweile ist ein regelrechter Kampf entstanden, welches Package denn besser geeignet sei. Die Syntax ist jedenfalls grundlegend verschieden. Tendenziell wird dplyr als etwas einfacher in der Anwendung beschrieben (was Anwender von data.table verneinen), dafür ist data.table insbesondere bei großen Datensätzen schneller. Es muss aber jeder selber entscheiden, welches Package er bevorzugt. Ich nutze einfach beide abhängig von der Anwendung.

Installation von dplyr

dplyr ist ein ganz normales Package in R, d.h. ihr müsst es einmalig mit install.packages(„dplyr“)  herunterladen und installieren. Im Anschluss genügt es dann, das Package mittels library(dplyr) einzubinden.

Da dplyr ein Teil des tidyverse ist, funktioniert alternativ die Installation auch mit install.packages(„tidyverse“), womit ihr alle Packages, die im tidyverse enthalten sind, installiert.

Wenn dplyr einmal heruntergeladen und installiert ist, wird es einfach mit library(dplyr) oder require(dplyr) eingebunden. Dabei spuckt R folgende Warnung heraus:

dplyr-warnungen-laden

Was bedeuten diese dplyr-Warnungen? R macht nur darauf aufmerksam, dass einige Funktionen aus dem Package dplyr genauso heißen wie welche aus den Package stats und base, welche standardmäßig in R geladen werden. D.h. wenn wir nun filter, lag, intersect, setdiff, setequal oder union verwenden, wird die Funktion dieses Namens von dplyr aufgerufen und nicht mehr die „Standard“-Funktion. Wenn man den Package-Namen gefolgt von zwei Doppelpunkten voranstellt, kann man aber dennoch darauf zugreifen. Also stats::filter, stats::lag, base::intersect, base::setdiff, base::setequal und base::union, falls man das möchte.

 

Was bedeutet der R-Code „%>%“? Die Pipe aus magrittr

Dieses komische Zeichen „Prozent – größer – Prozent“ nennt sich Forward-Pipe und ist ein Konzept, welches die Lesbarkeit von R-Code erhöhen soll. Prinzipiell braucht man sie nicht, die Pipe hat sich aber als so praktisch erwiesen, dass sie heute vielfach verwendet wird. Insbesondere im tidyverse, also dplyr, ggplot2 etc., ist sie nicht mehr wegzudenken.

Aber was macht sie denn nun. Ganz einfach eigentlich: Statt f(x, …) schreibt man nun x %>% f(…). Warum ist das so nützlich? Weil damit der verschachtelte Aufruf von Funktionen viel lesbarer wird. Stellt euch vor, wir wollen auf einen Datensatz df zuerst die Funktion f anwenden und auf das Ergebnis die Funktion g. Dann wäre der normale Code g(f(df)). Mit der magrittr-Pipe wäre dass df  %>% f %>% g und entspricht der Leserichtung von links nach rechts. Kommen nun noch Parameter in Spiel, z.B. p1 und p2 für f sowie p3 für g, dann wäre der konventionelle R-Code g(f(df,p1,p2),p3). Mit der Pipe df %>% f(p1,p2) %>% g(p3).

Diese Pipe wurde 2014 von Stefan Milton Bache mit dem Package magrittr in R (benannt nach dem Bild einer Pfeife von René Magritte) umgesetzt und von Hadley Wickham in das tidyverse integriert. Wenn ihr also ein Paket aus dem tidyverse ladet, bekommt ihr automatisch die Pipe-Funktionalität dazu. Wer sich für die Entstehung interessiert: Ursprünglich kommt die Pipe Forward wohl aus der Programmiersprache F#, dort allerdings mit dem Syntax „|>“. Diese Funktionalität fand Bache so praktisch, dass er sie in R umsetze. Schaut mal auf diesen Blogeintrag von R-Statistics.com.

Übrigens, der Shortcut in R-Studio für die Pipe ist Strg + Shift + M. In meinem Blogartikel über die nützlichsten RStudio Shortcuts findet ihr noch 14 weitere.

 

Die wichtigsten Funktionen von dplyr – R

Die Funktionen dplyr::mutate und transmute

Der R-Befehl mutate ergänzt einen Datensatz um eine oder mehrere Spalten. Der häufigste Fall ist die Berechnung aus anderen Spalten. Aber auch Ergänzung von Konstanten oder das Löschen einer Spalte kann man mit mutate erreichen. Als Rückgabewert wird der „mutierte“ Datensatz zurückgegeben.

Eine Variante ist die dplyr-Funktion transmute. Das funktioniert ganz genauso, nur der Rückgabewert ist nicht der komplette Datensatz, sondern nur die „mutierten“ Spalten.

Die Funktion dplyr::select und rename

Der R-Befehl select wählt eine oder mehrere Spalten aus. Nicht mehr und nicht weniger. Klingt eigentlich überflüssig, denn dafür gibt es schon mehrere Varianten im Standard-R (Base-R). Macht aber doch Sinn, denn select hat mehrere entscheidende Vorteile:

  • es erzeugt sehr gut lesbaren Code
  • man kann auf die Anführungszeichen verzichten
  • es funktioniert mit der Pipe, also dem Hintereinander Ausführen mehrerer Schritte
  • die Auswahl bzw. Abwahl von Spalten ist flexibel und hat einige nützliche Kniffe (siehe Code-Beispiel)

Während select nur einen data.frame mit den ausgewählten Spalten zurückgibt, gibt die dplyr-Funktion rename den ganzen data.frame zurück. Diese Funktion ist, wie der Name schon sagt, zum Umbenennen von Spalten da.

Wenn Du statt Spalten auszuwählen Zeilen auswählen willst, dann ist der Befehl filter der richtige.

Die Sache mit den Anführungszeichen – Variablen mit Spaltennamen

Das ist tatsächlich – man glaubt es nicht – ein kompliziertes Thema. Was ist, wenn man einem dplyr-Befehl statt direkt die Spaltennamen (ohne Anführungszeichen) eine Variable mit dem Spaltennamen oder einen Vektor mit Spaltennamen (mit Anführungszeichen) übergeben will?

Im Gegensatz zu den meisten anderen Funktionen verstehen select direkt Vektoren mit den Spaltennamen. Stellt euch vor, ihr wollt am Anfang vom Skript die zu untersuchenden Variablen definieren (übrigens sehr zu empfehlen, sauberer Programmierstil). Oder das Programm entscheidet dynamisch, welche Spalten ausgewählt werden sollen. Dann stehen die Spaltennamen in String-Variablen oder –Vektoren. Die meisten Funktionen aus dplyr können damit nicht ohne weiteres umgehen (das hat durchaus Sinn, denn dadurch werden Doppeldeutigkeiten verhindert), bei select funktioniert es aber problemlos.

Bei rename benötigen wir den !!-Operator (siehe Code-Beispiel)

Wer mehr über non-standard-evaluation und quote/unquote erfahren will, findet in diesem Artikel auf der tidyverse-Seite eine gute Erklärung.

Nützliche Funktionen für select, aber auch andere dplyr-Befehle

dplyr liefert einige hilfreiche Funktionen mit, die die Auswahl mehrerer Spalten mit rename oder select erleichtern. Diese Funktionen können aber auch in den anderen Befehlen wie filter angewendet werden. Wer es genau nimmt: Die Befehle sind im Package tidyselect, welches aber von dplyr geladen wird.

  • starts_with – Wie der Name schon sagt, liefert starts_with die Spalten zurück, die mit der im Parameter angegebenen Zeichenkette anfangen
  • ends_with – Wie starts_with, nur eben für die Endung
  • contains – auch diese Funktion analog zu starts_with und ends_with. Hier muss einfach nur der String im Spaltennamen enthalten sein
  • matches – Auswahl der Spalten über einen regulären Ausdruck. Mehr über reguläre Ausdrücke und die Base-R-Befehle grepl, gsub, … erfahrt ihr übrigens in diesem R-HowTo zu RegEx
  • num_range – Auswahl von Spaltennamen, welche durchnummeriert sind. Also zum Beispiel V01, V02, V03, …
  • one_of – Auswahl der Spalten, deren Namen per String-Vektor angegeben werden. Bei select funktioniert das impliziert (siehe Abschnitt über Anführungszeichen)
  • everything – eben alle Spalten
  • last_col – eben die letzte Spalte

Die Funktion dplyr:: filter

Mit dem dplyr-Befehl filter lassen sich Zeilen aus einem data.frame filtern. D.h. der Datensatz wird nach bestimmten Bedingungen reduziert, z.B. Alter > 50. Also ganz simpel, aber mit eine der häufigsten Anwendungen, denn meist wollen wir nur gewisse Daten analysieren oder zum Beispiel zwei Gruppen miteinander vergleichen.

Die Funktion dplyr:: summarise/summarize und dplyr::group_by

Das Package dplyr beinhaltet auch die R-Funktion summarize oder summarise (je nachdem ob man britisches oder amerikanisches Englisch lieber mag). Mit dieser lassen sich Daten aggregieren, also z.B. eine Summe oder ein Mittelwert bilden.

Insbesondere in Kombination mit der dplyr-Funktion group_by entfaltet summarize seine Wirkung. group_by funktioniert wie der SQL-Zusatz group by zum select-Befehl. Man unterteilt damit den Datensatz in verschiedene Gruppen. Kombiniert man nun summarize und group_by, lassen sich bequem Aggregate in diesen Gruppen berechnen. Im Endeffekt ähnlich zur aggregate-Funktion von Base-R, nur komfortabler.

Die Funktion dplyr:: arrange

Der R-Befehl arrange ordnet einen Datensatz entsprechend der Variablen, die als Parameter übergeben werden. Viel mehr gibt es darüber gar nicht zu sagen, schaut euch das Code-Beispiel an. Um eine umgekehrte Reihenfolge zu erhalten, gibt es die Funktion desc. Bei numerischen Spalten geht natürlich auch einfach das Minus-Zeichen, aber für Strings und Faktoren braucht man desc.

Zwei data.frames miteinander verbinden – joins

Kommen wir nun zu einem zentralen Bestandteil vom Datenmanagement, dem Verbinden von zwei Tabellen mittels merge oder join. Der R-Befehl merge wird in Base-R bzw. data.table verwendet, join kommt aus SQL und es gibt genau vier Varianten davon.

Wie funktioniert das grundsätzlich? Zum einen können Tabellen ganz einfach aneinander gehangen werden (untereinander oder nebeneinander), zum anderen können Tabellen anhand eines eindeutigen Identifikators (z.B. Kundennummer, Seriennummer, Name) verbunden werden. D.h. die Zeile aus Tabelle 2 wird neben die Zeile aus Tabelle 1, die den gleichen Identifikator hat, gepackt.

Wie oben erwähnt, gibt es vier Varianten mit den Identifikator-Werten umzugehen, welche nicht übereinstimmen

  • inner join: Es bleiben nur die Zeilen übrig, deren Identifikator in beiden Tabellen vorkommen.
  • left join: Die zuerst genannte Tabelle (also die linke) bleibt vollständig erhalten. Gibt es kein Pendant in der zweiten Tabelle, wird mit NAs aufgefüllt.
  • right join: Genau umgekehr zu left join. Die zweite Tabelle bleibt komplett erhalten. Werte, die keine Entsprechung in der ersten Tabelle haben, werden mit NAs aufgefüllt.
  • full (outer) join: Sowohl die erste als auch die zweite Tabelle bleiben vollständig erhalten.

dplyr join cheatsheet - inner_join,full_join,left_join,right_join

Das dplyr join-Cheatsheet als pdf zum Nachschlagen könnt ihr gerne kostenlos herunterladen.

Gibt man nichts explizit an, werden alle gleichnamigen Spalten als Identifikatoren verwendet. Man kann aber auch über den Parameter by die Identifikator-Spalten definieren.

Fazit

Habt ihr euch wirklich alles bis zum Ende durchgelesen? Dann seid ihr nun bestens gerüstet, dplyr einzusetzen. Daneben habt ihr das Konzept der Pipe kennengelernt, welches viele Anwendungen hat, z.B. auch für das Grafik-Package ggplot2. Und ihr versteht nun die verschiedenen join-Arten.

Fun Fact: Pliers heißt Zange auf englisch. Daher kommt die Zange im Logo von dplyr.

Hinterlasst einen Kommentar und schreibt mir, wie ihr dplyr einsetzt.

Happy coding,

Euer Holger