Setup
library(tidyverse)## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──## ✓ ggplot2 3.3.3 ✓ purrr 0.3.4
## ✓ tibble 3.1.2 ✓ dplyr 1.0.6
## ✓ tidyr 1.1.3 ✓ stringr 1.4.0
## ✓ readr 1.4.0 ✓ forcats 0.5.1## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()Einige Funktionen in R sind vektorisiert, andere nicht
Einige Funktionen in R sind vektorisiert: sie führen ihren Dienst für jedes Element eines Vektors aus. Erzeugen wir dazu ein paar Daten:
x = c(1,2,3)
y = c(1,2,4)x + y## [1] 2 4 7Wie man sieht, wird die Funktion “Summe” elementweise ausgeführt: Für jedes Paar von (x,y) wird die Summe berechnet.
Leide sind nicht alle Funktionen vektorisiert:
sum(x,y)## [1] 13Klappt auch nicht:
sum(c(x,y))## [1] 13Beispiel für vektorisierte Funktionen
Inflix-Funktionen scheinen alle vektorisiert zu sein:
x - y## [1] 0 0 -1x == y## [1] TRUE TRUE FALSEx * y## [1] 1 4 12x %% y # Rest (Modulo)## [1] 0 0 3Beispiel für nicht-vektorisierte Funktionen
Die Liste ist lang, wichtige Beispiele sind:
- mean
- sum
- identical
- …
Typischer Anwendungsfall
Ein typischer Anwendungsfall sind zeilenweise Berechnungen, etwa der Mittelwert pro Zeile einer Tabelle.
Vektorisieren für Mittelwerte und Summen
Möchte man sum und mean vektorisiert über Zeilen einer Tabelle anwenden, so gibt es Helferfuntionen, nämlich rowSums und rowMeans.
Dazu brauchen wir zuerst eine Tabelle:
d <- tibble(
x = c(1,2,3),
y = c(1,2,4)
)knitr::kable(d)| x | y |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | 4 |
rowSums(d)## [1] 2 4 7rowMeans(d)## [1] 1.0 2.0 3.5Vektorisieren mit dem Tidyverse
Mittels Tidyverse-Methoden gibt es eine Reihe von Ansätzen.
map
d %>%
map2_dbl(.x = x,
.y = y,
.f = ~ mean(c(.x,.y)))## [1] 1.0 2.0 3.5map wendet eine Funktion auf jedes Element eines Vektors oder einer Liste an. Im Standard wird eine Liste zurückgegeben.
map_dbl gibt einen Wert vom Typ dbl (Gleitkommazahl) zurück. map2 übergibt jeweils ein Element von zwei Vektoren x und y an eine Funktionen f: f(x, y) für jedes Elementenpaar von x und y, d.h. (\(x_1\), \(y_1\)), )\(x_2,y_2\)), ….
rowwise
rowwise teilt die Tabelle in zeilenweise Gruppen ein: jede Zeile wird eine eigene Gruppe, also Teil-Tabelle. Dann wird mean etc. wieder funktionieren.
d %>%
rowwise() %>%
mutate(row_mean = mean(c(x,y)),
row_identical = identical(x,y))## # A tibble: 3 x 4
## # Rowwise:
## x y row_mean row_identical
## <dbl> <dbl> <dbl> <lgl>
## 1 1 1 1 TRUE
## 2 2 2 2 TRUE
## 3 3 4 3.5 FALSEmap mit mutate
Möchte man das Ergebnis von map in eine Tabelle einbinden, so macht man das wie gewohnt mit mutate:
d %>%
mutate(row_mean = map2_dbl(.x = x,
.y = y,
.f = ~ mean(c(.x,.y))) )## # A tibble: 3 x 3
## x y row_mean
## <dbl> <dbl> <dbl>
## 1 1 1 1
## 2 2 2 2
## 3 3 4 3.5mutate und rowMeans
Auch das geht, wenn auch etwas umständlich, da rowMeans eine Tabelle als Input erwartet:
d %>%
mutate(row_mean = rowMeans(select(., x,y)))## # A tibble: 3 x 3
## x y row_mean
## <dbl> <dbl> <dbl>
## 1 1 1 1
## 2 2 2 2
## 3 3 4 3.5Oder so:
d %>%
mutate(row_mean = rowMeans(across(.cols = c(x, y))))## # A tibble: 3 x 3
## x y row_mean
## <dbl> <dbl> <dbl>
## 1 1 1 1
## 2 2 2 2
## 3 3 4 3.5Das funktioniert, da across einen Tibble (d.h. eine Tabelle) zurückliefert.
Mit Infix-Funktionen
d %>%
mutate(row_mean = (x + y)/2)## # A tibble: 3 x 3
## x y row_mean
## <dbl> <dbl> <dbl>
## 1 1 1 1
## 2 2 2 2
## 3 3 4 3.5Weiterführende Infos
Hier findet sich eine gute Einführung in zeilenweise Operationen im Tidyverse.