Was ist der Unterschied zwischen lapply und do.call?

143

Ich lerne R kürzlich und bin durch zwei Funktionen verwirrt: lapplyund do.call. Es scheint, dass sie der mapFunktion in Lisp nur ähnlich sind . Aber warum gibt es zwei Funktionen mit so unterschiedlichen Namen? Warum verwendet R nicht einfach eine aufgerufene Funktion map?

Hanfei Sun.
quelle

Antworten:

125

Es gibt eine Funktion namens Map, die der Karte in anderen Sprachen ähnlich sein kann:

  • lapply Gibt eine Liste mit der gleichen Länge wie X zurück, deren jedes Element das Ergebnis der Anwendung von FUN auf das entsprechende Element von X ist.

  • do.call erstellt und führt einen Funktionsaufruf aus einem Namen oder einer Funktion und einer Liste von Argumenten aus, die an ihn übergeben werden sollen.

  • Mapwendet eine Funktion auf die entsprechenden Elemente gegebener Vektoren an ... Mapist ein einfacher Wrapper, mapplyder nicht versucht, das Ergebnis zu vereinfachen, ähnlich wie das Mapcar von Common Lisp (wobei jedoch Argumente recycelt werden). Zukünftige Versionen ermöglichen möglicherweise eine gewisse Kontrolle des Ergebnistyps.


  1. Map ist ein Wrapper herum mapply
  2. lapply ist ein Sonderfall von mapply
  3. Daher Mapund lapplywird in vielen Fällen ähnlich sein.

Zum Beispiel ist hier lapply:

lapply(iris, class)
$Sepal.Length
[1] "numeric"

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

Und das gleiche mit Map:

Map(class, iris)
$Sepal.Length
[1] "numeric"

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

do.callNimmt eine Funktion als Eingabe und verteilt ihre anderen Argumente auf die Funktion. Es wird beispielsweise häufig verwendet, um Listen zu einfacheren Strukturen zusammenzustellen (häufig mit rbindodercbind ).

Beispielsweise:

x <- lapply(iris, class)
do.call(c, x)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
   "numeric"    "numeric"    "numeric"    "numeric"     "factor" 
Andrie
quelle
4
Eigentlich fand ich do.callfast das gleiche wie applyin Lisp
Hanfei So
soll nicht das letzte Beispiel ist do.call(cbind, x)die aktuelle Version gibt mir Error in do.call(c, x) : 'what' must be a function or character string...
sindri_baldur
1
@snoram Das Beispiel funktioniert immer noch. Die Funktion cbind()unterscheidet sich von der Funktion c(), und obwohl dies auch funktioniert, liefert sie unterschiedliche Ergebnisse.
Andrie
61

lapplyWendet eine Funktion auf eine Liste an und do.callruft eine Funktion mit einer Liste von Argumenten auf. Das sieht für mich nach einem ziemlichen Unterschied aus ...

Um ein Beispiel mit einer Liste zu geben:

X <- list(1:3,4:6,7:9)

Mit lapply erhalten Sie den Mittelwert jedes Elements in der Liste wie folgt:

> lapply(X,mean)
[[1]]
[1] 2

[[2]]
[1] 5

[[3]]
[1] 8

do.call gibt einen Fehler aus, da der Mittelwert erwartet, dass das Argument "trim" 1 ist.

rbindBindet andererseits alle Argumente zeilenweise. Um X zeilenweise zu binden, gehen Sie wie folgt vor:

> do.call(rbind,X)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8    9

Wenn Sie verwenden würden lapply, würde R für rbindjedes Element der Liste gelten, was Ihnen diesen Unsinn gibt:

> lapply(X,rbind)
[[1]]
     [,1] [,2] [,3]
[1,]    1    2    3

[[2]]
     [,1] [,2] [,3]
[1,]    4    5    6

[[3]]
     [,1] [,2] [,3]
[1,]    7    8    9

Um so etwas wie Map zu haben, braucht ?mapplyman etwas ganz anderes. Um zB den Mittelwert jedes Elements in X zu erhalten, aber mit einem anderen Zuschnitt, könnten Sie Folgendes verwenden:

> mapply(mean,X,trim=c(0,0.5,0.1))
[1] 2 5 8
Joris Meys
quelle
34

lapplyist ähnlich map, do.callist nicht. lapplyWendet eine Funktion auf alle Elemente einer Liste an und do.callruft eine Funktion auf, bei der sich alle Funktionsargumente in einer Liste befinden. Also für eine nElementliste, lapplyhat nFunktionsaufrufe und do.callhat nur einen Funktionsaufruf. Ist do.callalso ganz anders alslapply . Hoffe, dies klärt Ihr Problem.

Ein Codebeispiel:

do.call(sum, list(c(1, 2, 4, 1, 2), na.rm = TRUE))

und:

lapply(c(1, 2, 4, 1, 2), function(x) x + 1)
Paul Hiemstra
quelle
25

In einfachsten Worten:

  1. lapply () wendet für jedes Element in einer Liste eine bestimmte Funktion an, sodass mehrere Funktionsaufrufe erfolgen.

  2. do.call () wendet eine bestimmte Funktion auf die gesamte Liste an, sodass nur ein Funktionsaufruf vorhanden ist.

Der beste Weg zu lernen ist, mit den Funktionsbeispielen in der R-Dokumentation herumzuspielen.

LoveMeow
quelle
12

lapply()ist eine kartenähnliche Funktion. do.call()ist anders. Es wird verwendet, um die Argumente in Listenform an eine Funktion zu übergeben, anstatt sie aufzählen zu lassen. Zum Beispiel,

> do.call("+",list(4,5))
[1] 9
frankc
quelle
10

Obwohl es viele Antworten gab, ist hier mein Beispiel als Referenz. Angenommen, wir haben eine Liste von Daten als:

L=list(c(1,2,3), c(4,5,6))

Die Funktion lapply gibt eine Liste zurück.

lapply(L, sum) 

Das Obige bedeutet so etwas wie unten.

list( sum( L[[1]]) , sum( L[[2]]))

Lassen Sie uns jetzt dasselbe für do.call tun

do.call(sum, L) 

Es bedeutet

sum( L[[1]], L[[2]])

In unserem Beispiel wird 21 zurückgegeben. Kurz gesagt, lapply gibt immer eine Liste zurück, während der Rückgabetyp von do.call wirklich von der ausgeführten Funktion abhängt.

kimman
quelle
5

Der Unterschied zwischen beiden ist:

lapply(1:n,function,parameters)

=> Dies sendet 1, Parameter an Funktion => Dies sendet 2, Parameter an Funktion und so weiter

do.call 

Sendet einfach 1… n als Vektor und Parameter zur Funktion

In apply haben Sie also n Funktionsaufrufe, in do.call haben Sie nur einen

nitin lal
quelle