Vektorisierter Mittelwert in R

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 7

Wie 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] 13

Klappt auch nicht:

sum(c(x,y))
## [1] 13

Beispiel für vektorisierte Funktionen

Inflix-Funktionen scheinen alle vektorisiert zu sein:

x - y
## [1]  0  0 -1
x == y
## [1]  TRUE  TRUE FALSE
x * y
## [1]  1  4 12
x %% y  # Rest (Modulo)
## [1] 0 0 3

Beispiel 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 7
rowMeans(d)
## [1] 1.0 2.0 3.5

Vektorisieren 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.5

map 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 FALSE

map 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.5

mutate 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.5

Oder 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.5

Das 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.5

Weiterführende Infos

Hier findet sich eine gute Einführung in zeilenweise Operationen im Tidyverse.