Quelle est la différence entre lapply et do.call?

143

J'apprends R récemment et je suis confus par deux fonctions: lapplyet do.call. Il semble qu'ils soient simplement similaires à la mapfonction en Lisp. Mais pourquoi y a-t-il deux fonctions avec un nom si différent? Pourquoi R n'utilise-t-il pas simplement une fonction appelée map?

Soleil de Hanfei
la source

Réponses:

126

Il existe une fonction appelée Mapqui peut être similaire à la carte dans d'autres langues:

  • lapply renvoie une liste de même longueur que X, dont chaque élément est le résultat de l'application de FUN à l'élément correspondant de X.

  • do.call construit et exécute un appel de fonction à partir d'un nom ou d'une fonction et une liste d'arguments à lui passer.

  • Mapapplique une fonction aux éléments correspondants de vecteurs donnés ... Mapest un simple wrapper mapplyauquel ne tente pas de simplifier le résultat, similaire au mapcar de Common Lisp (avec des arguments recyclés cependant). Les versions futures peuvent permettre un certain contrôle du type de résultat.


  1. Map est une enveloppe autour mapply
  2. lapply est un cas particulier de mapply
  3. Par conséquent, Mapet lapplysera similaire dans de nombreux cas.

Par exemple, voici lapply:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

Et la même chose en utilisant Map:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

do.callprend une fonction comme entrée et éclabousse ses autres arguments sur la fonction. Il est largement utilisé, par exemple, pour assembler des listes en structures plus simples (souvent avec rbindoucbind ).

Par exemple:

x <- lapply(iris, class)
do.call(c, x)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
   "numeric"    "numeric"    "numeric"    "numeric"     "factor" 
Andrie
la source
4
en fait, j'ai trouvé do.callpresque le même que applydans Lisp
Hanfei Sun
ce dernier exemple n'est-il pas censé être do.call(cbind, x)la version actuelle me donne Error in do.call(c, x) : 'what' must be a function or character string...
sindri_baldur
1
@snoram Cet exemple fonctionne toujours. La fonction cbind()est différente de la fonction c(), et bien que cela fonctionne également, cela donne des résultats différents.
Andrie
61

lapplyapplique une fonction sur une liste, do.callappelle une fonction avec une liste d'arguments. Cela me semble une grande différence ...

Pour donner un exemple avec une liste:

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

Avec lapply, vous obtenez la moyenne de chaque élément de la liste comme ceci:

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

[[2]]
[1] 5

[[3]]
[1] 8

do.call donne une erreur, car la moyenne s'attend à ce que l'argument "trim" soit 1.

D'autre part, rbindlie tous les arguments par ligne. Donc, pour lier X rowwise, vous faites:

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

Si vous utilisiez lapply, R s'appliquerait rbindà chaque élément de la liste, vous donnant ce non-sens:

> 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

Pour avoir quelque chose comme Map, vous avez besoin de ?mapplyquelque chose de différent. Pour obtenir par exemple la moyenne de chaque élément de X, mais avec un ajustement différent, vous pouvez utiliser:

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

lapplyest similaire à map, do.calln'est pas. lapplyapplique une fonction à tous les éléments d'une liste, do.callappelle une fonction où tous les arguments de la fonction sont dans une liste. Donc, pour une nliste d'éléments, lapplya ndes appels de fonction et do.calln'a qu'un seul appel de fonction. C'est donc do.callassez différent de lapply. J'espère que cela clarifie votre problème.

Un exemple de code:

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

et:

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

En termes simples:

  1. lapply () applique une fonction donnée pour chaque élément d'une liste, il y aura donc plusieurs appels de fonction.

  2. do.call () applique une fonction donnée à la liste dans son ensemble, il n'y a donc qu'un seul appel de fonction.

La meilleure façon d'apprendre est de jouer avec les exemples de fonctions de la documentation R.

LoveMeow
la source
12

lapply()est une fonction de type carte. do.call()est différent. Il est utilisé pour passer les arguments à une fonction sous forme de liste au lieu de les énumérer. Par exemple,

> do.call("+",list(4,5))
[1] 9
Frankc
la source
10

Bien qu'il y ait eu de nombreuses réponses, voici mon exemple pour référence. Supposons que nous ayons une liste de données comme:

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

La fonction lapply renvoie une liste.

lapply(L, sum) 

Ce qui précède signifie quelque chose comme ci-dessous.

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

Maintenant, faisons la même chose pour do.call

do.call(sum, L) 

Ça veut dire

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

Dans notre exemple, il renvoie 21. En bref, lapply retourne toujours une liste alors que le type de retour de do.call dépend vraiment de la fonction exécutée.

Kimman
la source
5

La différence entre les deux sont:

lapply(1:n,function,parameters)

=> Cet envoi 1, paramètres à fonction => cela envoie 2, paramètres à fonction et ainsi de suite

do.call 

Envoie juste 1… n comme vecteur et paramètres pour fonctionner

Donc dans apply vous avez n appels de fonction, dans do.call vous n'en avez qu'un

nitin lal
la source