tidyverse
und tibbles
Pakete benutzen
das CRAN und Paketinstallation
Wie in der ersten Sitzung schon angedeutet, ist eine der größten wenn nicht die größte Stärke von R das Comprehensive R Archive Network.
Zum einen werden dort die Installationsdateien für die neuesten R-Versionen gehostet, für uns viel praktischer ist aber, dass dort auch fast unzählige Pakete zugänglich gemacht werden. Mit diesen Paketen oder auch packages
lässt sich der Funktionsumfang von R beliebig erweitern.
Diese Pakete lassen sich mit der naheliegend benannten Funktion install.packages
installieren. Ein für uns wichtiges Paket, das eine ganze Sammlung von nützlichen Paketen beinhaltet, die wir ab jetzt regelmäßig benutzen werden, ist das tidyverse
.
Bitte installieren Sie diese Sammlung mit dem folgenden Code:
install.packages('tidyverse')
Pakete laden
Wenn das Paket installiert ist, lässt es sich ganz einfach mit library
in den genutzten Namensraum laden.
Pakete, die nicht vor der Benutzung geladen wurden, können nicht benutzt werden!
Da wir es gleich benutzen werden, laden wir schon einmal das tidyverse
library(tidyverse)
Datensätze erstellen und ergänzen
Datensätze
Bisher haben wir nur einfache Vektoren benutzt um Daten auszudrücken. Das geht zwar, solange man nur Daten eines Formats und in überschaubarer Anzahl betrachtet, sobald wir aber an richtige experimentelle Kontexte denken, reicht das nicht mehr.
Deswegen gibt es in R so genannte ‘rechteckige Datensätze’, die Vektoren als Spalten zu einer Tabelle kombinieren. Die Spalten können dabei unterschiedliche Datenformate haben.
Datensätze erstellen
Datensätze werden in R data.frames
genannt und können mit data.frame()
erstellt werden.
Hier werden wir aber direkt auf die Basis-R Funktion verzichten und die etwas hübschere Funktion tibble()
aus dem tidyverse
nutzen.
Ein tibble
ist prinzipiell ein data.frame
, hat aber ein paar zusätzliche quality-of-life-features, die den Umgang mit ihnen vereinfachen.
Beispiel-Datensatz
Wir erstellen jetzt erstmal unseren ersten Datensatz:
<- tibble(
my_1st_tibble index = 1:10,
name = c('Agnes Nitt',
'Samuel Vimes',
'Esme Weatherwax',
'Gytha Ogg',
'Horace Worblehat',
'Mustrum Ridcully',
'Fred Colon',
'Leonard of Quirm',
'Havelock Vetinari',
'Reg Shoe'
),group = c(1,2,1,1,3,3,2,2,2,2)
)
tibble
Der Datensatz sieht dann so aus:
my_1st_tibble
## # A tibble: 10 × 3
## index name group
## <int> <chr> <dbl>
## 1 1 Agnes Nitt 1
## 2 2 Samuel Vimes 2
## 3 3 Esme Weatherwax 1
## 4 4 Gytha Ogg 1
## 5 5 Horace Worblehat 3
## 6 6 Mustrum Ridcully 3
## 7 7 Fred Colon 2
## 8 8 Leonard of Quirm 2
## 9 9 Havelock Vetinari 2
## 10 10 Reg Shoe 2
Also: Jedes Argument von eben ist jetzt eine Spalte, jeder Wert in allen Vektoren jetzt ein Zeile.
Überblick über den Datensatz verschaffen
Zwar ist in unserem Fall das tibble
ziemlich überschaubar, sollten wir uns aber trotzdem einen Überblick verschaffen wollen, können wir die glimpse
-Funktion benutzen:
glimpse(my_1st_tibble)
## Rows: 10
## Columns: 3
## $ index <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
## $ name <chr> "Agnes Nitt", "Samuel Vimes", "Esme We…
## $ group <dbl> 1, 2, 1, 1, 3, 3, 2, 2, 2, 2
Spalten hinzufügen
Wir stellen uns jetzt vor, dass unser Datensatz die Anmeldeliste für ein Experiment darstellt.
Nach der Anmeldung haben die Probanden das Experiment durchgeführt und an zwei Testzeitpunkten in einem von uns designeten Aufmerksamkeitsparadigma die folgenden Punkte erhalten:
name | points_t1 | points_t2 |
---|---|---|
Agnes Nitt | 4.8 | 2.8 |
Samuel Vimes | 3.2 | 5.8 |
Esme Weatherwax | 3.5 | 4.8 |
Gytha Ogg | 3.1 | 5.3 |
Horace Worblehat | 4.2 | 5.8 |
Mustrum Ridcully | 4.7 | 5.0 |
Fred Colon | 3.4 | 4.7 |
Leonard of Quirm | 2.8 | 6.2 |
Havelock Vetinari | 4.2 | 4.0 |
Reg Shoe | 4.0 | 5.2 |
Diese Daten wollen wir jetzt unserem Datensatz hinzufügen, um sie für unsere Auswertungen verwenden zu können (das Beispiel ist ein bisschen künstlich, später werden wir einfach Datensätze aus externen Dateien einlesen. Um das Prinzip zu demonstrieren, ergibt es hier aber Sinn).
Um dies zu tun, benutzen wir die mutate
-Funktion (auf deutsch ‘ändern’ oder ‘mutieren’).
mutate(my_1st_tibble,
points_t1 = c(4.8, 3.2, 3.5, 3.1, 4.2, 4.7, 3.4, 2.8, 4.2, 4),
points_t2 = c(2.8, 5.8, 4.8, 5.3, 5.8, 5, 4.7, 6.2, 4, 5.2))
## # A tibble: 10 × 5
## index name group points_t1 points_t2
## <int> <chr> <dbl> <dbl> <dbl>
## 1 1 Agnes Nitt 1 4.8 2.8
## 2 2 Samuel Vimes 2 3.2 5.8
## 3 3 Esme Weatherwax 1 3.5 4.8
## 4 4 Gytha Ogg 1 3.1 5.3
## 5 5 Horace Worblehat 3 4.2 5.8
## 6 6 Mustrum Ridcully 3 4.7 5
## 7 7 Fred Colon 2 3.4 4.7
## 8 8 Leonard of Quirm 2 2.8 6.2
## 9 9 Havelock Vetinari 2 4.2 4
## 10 10 Reg Shoe 2 4 5.2
mutate
funktioniert wieder wie alle bisher gesehenen Funktionen, wenn wir das Objekt nicht überschreiben, wird der Output nicht gespeichert.
glimpse(my_1st_tibble)
## Rows: 10
## Columns: 3
## $ index <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
## $ name <chr> "Agnes Nitt", "Samuel Vimes", "Esme We…
## $ group <dbl> 1, 2, 1, 1, 3, 3, 2, 2, 2, 2
Wir könnten jetzt einfach den Datensatz wie gewohnt überschreiben, nutzen aber die Gelegenheit um ein weiteres wichtiges feature des tidyverse
einzuführen.
%>%
ist die ‘pipe’, ein Operator, der den Output des links genannten Ausdrucks als erstes Argument an den rechts genannten Ausdruck weitergibt.
Mit diesem Operator können wir das Beispiel von eben wie folgt umformulieren:
<- my_1st_tibble %>%
my_1st_tibble mutate(points_t1 = c(4.8, 3.2, 3.5, 3.1, 4.2, 4.7, 3.4, 2.8, 4.2, 4),
points_t2 = c(2.8, 5.8, 4.8, 5.3, 5.8, 5, 4.7, 6.2, 4, 5.2))
Nur noch schnell gucken ob das geklappt hat:
my_1st_tibble
## # A tibble: 10 × 5
## index name group points_t1 points_t2
## <int> <chr> <dbl> <dbl> <dbl>
## 1 1 Agnes Nitt 1 4.8 2.8
## 2 2 Samuel Vimes 2 3.2 5.8
## 3 3 Esme Weatherwax 1 3.5 4.8
## 4 4 Gytha Ogg 1 3.1 5.3
## 5 5 Horace Worblehat 3 4.2 5.8
## 6 6 Mustrum Ridcully 3 4.7 5
## 7 7 Fred Colon 2 3.4 4.7
## 8 8 Leonard of Quirm 2 2.8 6.2
## 9 9 Havelock Vetinari 2 4.2 4
## 10 10 Reg Shoe 2 4 5.2
Die mutate
-Funktion wird richtig nützlich, wenn wir dem Datensatz Spalten hinzufügen wollen, die aus den anderen Spalten zusammengesetzt sind.
So könnten wir in unserem Beispiel überlegen, die Veränderung zum zweiten Messzeitpunkt als Spalte hinzufügen zu wollen. Dafür können wir die nötige arithmetische Operation einfach in der mutate-Funktion ausführen:
<- my_1st_tibble %>%
my_1st_tibble mutate(change = points_t2 - points_t1)
my_1st_tibble
## # A tibble: 10 × 6
## index name group points_t1 points_t2 change
## <int> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 1 Agnes Nitt 1 4.8 2.8 -2
## 2 2 Samuel Vimes 2 3.2 5.8 2.6
## 3 3 Esme Weathe… 1 3.5 4.8 1.3
## 4 4 Gytha Ogg 1 3.1 5.3 2.2
## 5 5 Horace Worb… 3 4.2 5.8 1.6
## 6 6 Mustrum Rid… 3 4.7 5 0.300
## 7 7 Fred Colon 2 3.4 4.7 1.3
## 8 8 Leonard of … 2 2.8 6.2 3.4
## 9 9 Havelock Ve… 2 4.2 4 -0.200
## 10 10 Reg Shoe 2 4 5.2 1.2
Spalten verändern
Es funktionieren natürlich nicht nur arithmetische Operatoren, wir können auch alle anderen vektorisierten Funktionen benutzen. Vektorisiert heißt ganz einfach gesagt, dass ein Vektor eingegeben wird und ein genauso langer Vektor ausgegeben wird1.
In unserem Beispiel könnten wir überlegen, dass wir statt der Differenz die Wurzel aus der quadrierten Differenz als Änderung haben wollen. Da wir die Differenz schon zum Datensatz hinzugefügt haben, können wir sie einfach überschreiben.
<- my_1st_tibble %>%
my_1st_tibble mutate(change = sqrt(change^2))
my_1st_tibble
## # A tibble: 10 × 6
## index name group points_t1 points_t2 change
## <int> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 1 Agnes Nitt 1 4.8 2.8 2
## 2 2 Samuel Vimes 2 3.2 5.8 2.6
## 3 3 Esme Weathe… 1 3.5 4.8 1.3
## 4 4 Gytha Ogg 1 3.1 5.3 2.2
## 5 5 Horace Worb… 3 4.2 5.8 1.6
## 6 6 Mustrum Rid… 3 4.7 5 0.300
## 7 7 Fred Colon 2 3.4 4.7 1.3
## 8 8 Leonard of … 2 2.8 6.2 3.4
## 9 9 Havelock Ve… 2 4.2 4 0.200
## 10 10 Reg Shoe 2 4 5.2 1.2
Datensätze sortieren und indizieren
Datensätze sortieren
Der erste Schritt bei vielen Auswertungen ist es, sich die größten und kleinsten Werte einer Gruppe oder Variable anzugucken. Das kann schnell erreicht werden, indem man den gegebenen Datensatz anhand einer Varaible sortiert.
Wir benutzen weiter unseren Datensatz von eben und wollen zuerst absteigend nach den Änderungen sortieren.
Dafür können wir die arrange
-Funktion und unseren pipe-Operator benutzen:
%>%
my_1st_tibble arrange(change)
## # A tibble: 10 × 6
## index name group points_t1 points_t2 change
## <int> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 9 Havelock Ve… 2 4.2 4 0.200
## 2 6 Mustrum Rid… 3 4.7 5 0.300
## 3 10 Reg Shoe 2 4 5.2 1.2
## 4 3 Esme Weathe… 1 3.5 4.8 1.3
## 5 7 Fred Colon 2 3.4 4.7 1.3
## 6 5 Horace Worb… 3 4.2 5.8 1.6
## 7 1 Agnes Nitt 1 4.8 2.8 2
## 8 4 Gytha Ogg 1 3.1 5.3 2.2
## 9 2 Samuel Vimes 2 3.2 5.8 2.6
## 10 8 Leonard of … 2 2.8 6.2 3.4
Wie man unschwer erkennen kann, ist hier der Standard, den Datensatz in aufsteigender Reihenfolge der Variable zu sortieren. Um das umzukehren, können wir die desc
-Funktion nutzen, deren Name für ‘descending’, also absteigend steht:
%>%
my_1st_tibble arrange(desc(change))
## # A tibble: 10 × 6
## index name group points_t1 points_t2 change
## <int> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 8 Leonard of … 2 2.8 6.2 3.4
## 2 2 Samuel Vimes 2 3.2 5.8 2.6
## 3 4 Gytha Ogg 1 3.1 5.3 2.2
## 4 1 Agnes Nitt 1 4.8 2.8 2
## 5 5 Horace Worb… 3 4.2 5.8 1.6
## 6 7 Fred Colon 2 3.4 4.7 1.3
## 7 3 Esme Weathe… 1 3.5 4.8 1.3
## 8 10 Reg Shoe 2 4 5.2 1.2
## 9 6 Mustrum Rid… 3 4.7 5 0.300
## 10 9 Havelock Ve… 2 4.2 4 0.200
mehrere Sortierschlüssel
Wenn wir der arrange
-Funktion mehr als eine Variable übergeben, werden die zusätzlichen Variablen als zusätzliche Sortierschlüssel interpretiert.
Wir könnten zum Beispiel aufsteigend nach der Gruppe und dann pro Gruppe absteigend nach der Veränderung sortieren wollen. Das könnte dann so aussehen:
%>%
my_1st_tibble arrange(group, desc(change))
## # A tibble: 10 × 6
## index name group points_t1 points_t2 change
## <int> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 4 Gytha Ogg 1 3.1 5.3 2.2
## 2 1 Agnes Nitt 1 4.8 2.8 2
## 3 3 Esme Weathe… 1 3.5 4.8 1.3
## 4 8 Leonard of … 2 2.8 6.2 3.4
## 5 2 Samuel Vimes 2 3.2 5.8 2.6
## 6 7 Fred Colon 2 3.4 4.7 1.3
## 7 10 Reg Shoe 2 4 5.2 1.2
## 8 9 Havelock Ve… 2 4.2 4 0.200
## 9 5 Horace Worb… 3 4.2 5.8 1.6
## 10 6 Mustrum Rid… 3 4.7 5 0.300
Auswahl von Spalten
Es passiert öfter, dass wir eine oder mehrere Variablen nicht mehr benötigen und der Übersichtlichkeit halber aus dem Datensatz entfernen wollen.
Das tidyverse
bietet dafür mit der select
-Funktion eine sehr intuitiv zugängliche Syntax an, die wir zur Auswahl und zum Ausschluss von Spalten nutzen können. Dazu pipen wir einfach wieder den Datensatz in die Funktion und listen diejenigen Variablen auf, die wir behalten können.
In unserem Beispiel könnten wir uns überlegen, den Index und die beiden Punkt-Spalten nicht mehr zu benötigen. Wir geben also einfach den Dantensatz in die select
-Funktion und listen die restlichen Variablen auf:
%>%
my_1st_tibble select(name, group, change)
## # A tibble: 10 × 3
## name group change
## <chr> <dbl> <dbl>
## 1 Agnes Nitt 1 2
## 2 Samuel Vimes 2 2.6
## 3 Esme Weatherwax 1 1.3
## 4 Gytha Ogg 1 2.2
## 5 Horace Worblehat 3 1.6
## 6 Mustrum Ridcully 3 0.300
## 7 Fred Colon 2 1.3
## 8 Leonard of Quirm 2 3.4
## 9 Havelock Vetinari 2 0.200
## 10 Reg Shoe 2 1.2
Hier funktioniert auch die schon bei der numerischen Vektor-Indizierung vorgestellte Methode zum Ausschluss von Werten. Durch -
-eingeleitete Variablennamen lassen sich einfach ausschließen:
%>%
my_1st_tibble select(-index, -points_t1, -points_t2)
## # A tibble: 10 × 3
## name group change
## <chr> <dbl> <dbl>
## 1 Agnes Nitt 1 2
## 2 Samuel Vimes 2 2.6
## 3 Esme Weatherwax 1 1.3
## 4 Gytha Ogg 1 2.2
## 5 Horace Worblehat 3 1.6
## 6 Mustrum Ridcully 3 0.300
## 7 Fred Colon 2 1.3
## 8 Leonard of Quirm 2 3.4
## 9 Havelock Vetinari 2 0.200
## 10 Reg Shoe 2 1.2
Wir können die Spalten-Auswahl auch benutzen, um den Datensatz für folgende Funktionen vorzubereiten. Ein Beispiel ist die schon aus der letzen Sitzung bekannte Funktion cor
, die neben Vektoren auch einen Datensatz mit numerischen Spalten als Input versteht.
Wir könnten uns zum Beispiel die Frage stellen, ob die Aufmerksamkeitswerte vor und nach dem Training miteinander korreliert sind.
%>%
my_1st_tibble select(points_t1, points_t2) %>%
cor()
## points_t1 points_t2
## points_t1 1.0000000 -0.6449612
## points_t2 -0.6449612 1.0000000
Das tidyverse
bietet wie gesagt viele features, die unser Leben als empirische Forscher leichter machen, darunter eine Reihe von selection helpers
.
Der erste, den wir hier verwenden wollen ist die contains
-Funktion. Eine Funktion in der wir Teile von Spaltennamen suchen können, bei uns zum Beispiel 'points'
, um den Aufruf von eben ein bisschen zu vereinfachen:
%>%
my_1st_tibble select(contains('points')) %>%
cor()
## points_t1 points_t2
## points_t1 1.0000000 -0.6449612
## points_t2 -0.6449612 1.0000000
Der zweite helper, den wir ausprobieren ist where
, ein helper, der uns erlaubt, mit Hilfe einer Funktion Spalten auszuwählen, auf die eine Bedingung zutrifft.
In unserem Beispiel wollen wir alle numerischen Variablen miteinander korrelieren, indem wir where
mit is.numeric
kombinieren:
%>%
my_1st_tibble select(where(is.numeric)) %>%
cor()
## index group points_t1
## index 1.00000000 0.4227600 -0.06127845
## group 0.42276002 1.0000000 0.28205162
## points_t1 -0.06127845 0.2820516 1.00000000
## points_t2 0.24860383 0.4354397 -0.64496117
## change -0.32568808 -0.3039316 -0.65762107
## points_t2 change
## index 0.2486038 -0.3256881
## group 0.4354397 -0.3039316
## points_t1 -0.6449612 -0.6576211
## points_t2 1.0000000 0.4254564
## change 0.4254564 1.0000000
logische Auswahl von Zeilen
Um Zeilen aus einem Datensatz auszuwählen gibt es sowohl die Möglichkeit über filter
mit logischen Angaben Zielen auszuwählen, als auch mit slice
eine numerische Auswahl zu treffen.
Logische Indizierung kann praktisch sein, wenn man die Einträge sehen möchte, die zum Beispiel unterdurchschnittlich viel Veränderung gezeigt haben. Das könnte so aussehen:
%>%
my_1st_tibble filter(change < mean(change))
## # A tibble: 6 × 6
## index name group points_t1 points_t2 change
## <int> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 3 Esme Weather… 1 3.5 4.8 1.3
## 2 5 Horace Worbl… 3 4.2 5.8 1.6
## 3 6 Mustrum Ridc… 3 4.7 5 0.300
## 4 7 Fred Colon 2 3.4 4.7 1.3
## 5 9 Havelock Vet… 2 4.2 4 0.200
## 6 10 Reg Shoe 2 4 5.2 1.2
numerische Auswahl von Zeilen
Zusätzlich zur logischen Indizierung bietet das tidyverse
mit der slice
-Funktion auch die Möglichkeit numerisch zu indizieren.
Das könnte in unserem Beispiel exemplarisch hilfreich sein, um die drei Versuchspersonen ausgeben zu lassen, die die größte Veränderung gezeigt haben.
%>%
my_1st_tibble arrange(desc(change)) %>%
slice(1:3)
## # A tibble: 3 × 6
## index name group points_t1 points_t2 change
## <int> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 8 Leonard of Q… 2 2.8 6.2 3.4
## 2 2 Samuel Vimes 2 3.2 5.8 2.6
## 3 4 Gytha Ogg 1 3.1 5.3 2.2
Das ist nicht ganz richtig, aber für hier ausreichend nah genug an der richtigen Aussage.↩︎