Jakob Richter

Statistik, R, Fotografie und Sonstiges

lapply() und sapply() – Der Einstieg in die apply-Funktionen.

Warum gerade lapply() und keine der gebräuchlicheren Funktionen apply Funktionen aus R? Ganz einfach: lapply() ist die Grundfunktion und die anderen Funktionen bauen auf dieser Funktionsweise auf. Da man lapply() nicht nur auf Vektoren, sondern auch auf Listen anwenden kann bietet es ungeahnte (vllt. auch unausdenkbare) Möglichkeiten der Verwendung. Aus diesem Grund ist das Beispiel auch äußerst praxisunrelevant.

Funktionsweise lapply()

Versuch eines Schemas: So ungefähr arbeitet lapply().



Beschäftigen wir uns zunächst mit Listen. Listen sind das vermutlich flexibelste Werkzeug um Daten zu “speichern”, denn als einzelnes Listenelement lässt sich wohl alles in R definieren. u.a. sinnvoll können sein:

  • Vektoren aller Art
  • Funktionen
  • data.frames
  • lineare Modelle
  • Listen
  • usw.

Ebenso kann die Ausgabe der Funktion die in lapply() arbeitet jeglichen Datentyp annehmen.
Um dies zu demonstrieren definieren wir für unser Beispiel diese krude Liste:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
a <- list()
a[[1]] <- 8
a[[2]] <- 5:10
a[[3]] <- c(Frucht="Banane")
a[[4]] <- function(x) x+1
a[["Banane"]] <- "test"
a[[5]] <- list(a=1:10,b=10:1)
a[["Ende"]] <- "fin"
 
#Wie sieht das fertig aus?
a
# [[1]]
# [1] 8
# 
# [[2]]
# [1]  5  6  7  8  9 10
# 
# [[3]]
# Frucht 
# "Banane" 
# 
# [[4]]
# function (x) 
#   x + 1
# 
# $Banane
# $Banane$a
# [1]  1  2  3  4  5  6  7  8  9 10
# 
# $Banane$b
# [1] 10  9  8  7  6  5  4  3  2  1
# 
# 
# $Ende
# [1] "fin"

Wie man schön sehen kann, können tatsächlich in jedes einzelne Listenelement unterschiedliche Datentypen gespeichert werden. Auch wird deutlich, dass wir nicht unbedingt Zahlen zur Indizierung benötigen, sondern den einzelnen Listenelementen auch Namen geben können.
Doch Vorsicht! Auch ein benanntes Listenelement hat intern eine Nummer. So z.B. wird a[["banane"]] das 5te Listenelement und mit a[[5]] kann ebenfalls darauf zugegriffen werden.
Auch wichtig: Wenn ein Listenelement zu einer Liste hinzugefügt werden soll, so kann dies nur am direkten Ende der Liste geschehen. Unsere Liste hat die Länge 6. Ein Element mit der Nummer 8 (a[[8]]) ließe sich nicht erstellen.
Schauen wir uns nun eine ebenfalls untypische lapply()-Funktion an:

37
38
39
40
41
42
43
44
45
46
47
48
ergebnis <- lapply(a,function(x){
  if(is.numeric(x)){
    res <- sum(x)^2
  }else if(is.character(x)){
    res <- paste(names(x),x) #Fügt zwei character zu einem zusammen.
  }else if(is.function(x)){
    res <- x(9)
  }else{ #Wenn kein Datentyp bisher passt.
    res <- "irgendwas komisches"
  }
  return(res)
})

Da verschiedenste Datentypen behandelt werden sollen wurden die Fallunterscheidungen eingebaut. Was hier geschieht sollte klar werden, wenn wir uns das Ergebnis ansehen:

49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
ergebnis
[[1]]
[1] 64
 
[[2]]
[1]  25  36  49  64  81 100
 
[[3]]
[1] "Frucht Banane"
 
[[4]]
[1] 10
 
$Banane
[1] "irgendwas komisches"
 
$Ende
[1] " fin"

Und was ist mit sapply()?

Das ist sehr einfach zu erklären. Und im prinzip steht auch alles in der R-Hilfe: ?sapply liefert:

sapply is a user-friendly version and wrapper of lapply by default returning a vector, matrix or, if simplify=”array”, an array if appropriate, by applying simplify2array(). sapply(x, f, simplify=FALSE, USE.NAMES=FALSE) is the same as lapply(x,f).

sapply() arbeitet also genau so wie lapply(). Es wird nur versucht das Ergebnis nicht als Liste sondern als Vektor oder Matrix auszugeben. Das funktioniert jedoch nur, wenn das Ergebnis der Funktion immer die gleiche Länge hat. Also:

  • Funktionsergebnis ist eine Zahl oder ein Character
  • Funktionsergebnis ist ein numerischer Vektor immer gleicher Länge

Im ersten Fall ist das Gesamtergebnis ein Vektor, im zweiten Fall eine Matrix in der die Funktionsergebnisse spaltenweise stehen. Dafür noch zwei kurze Beispiele:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
### Beispiel 1
 
b <- c(2,4,1)
e2 <- sapply(b,function(x){
  res <- numeric(max(b))
  res[x] <- 1
  return(res)
})
e2
#      [,1] [,2] [,3]
# [1,]    0    0    1
# [2,]    1    0    0
# [3,]    0    0    0
# [4,]    0    1    0
 
### Beispiel 2
 
c <- list(a=1:3,b=4:6,c=c(1,3,5))
sapply(c,function(x){
  res <- numeric(6)
  res[x] <- 1
  return(res)
})
#      a b c
# [1,] 1 0 1
# [2,] 1 0 0
# [3,] 1 0 1
# [4,] 0 1 0
# [5,] 0 1 1
# [6,] 0 1 0

Viel Spaß beim selber programmieren!

Leave a Reply