web-dev-qa-db-fra.com

Quelle est la difference entre lapply et do.call?

J'apprends R récemment et confondu par deux fonctions: lapplyet do.call. Il semble qu’elles soient similaires à la fonction map dans 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?

126
Hanfei Sun

Il existe une fonction appelée Map qui peut être similaire à mapper dans d'autres langues:

  • lapply renvoie une liste de la même longueur que X, chaque élément résultant 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 d'une liste d'arguments à lui transmettre.

  • Map applique une fonction aux éléments correspondants de vecteurs donnés ... Map est un simple wrapper pour mapply qui ne tente pas de simplifier le résultat, semblable au mapcar de Common LISP (avec les arguments en cours de recyclage, cependant). Les versions futures peuvent permettre un certain contrôle du type de résultat.


  1. Map est un wrapper autour de mapply
  2. lapply est un cas particulier de mapply
  3. Par conséquent, Map et lapply seront similaires 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 avec Map:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

do.call prend une fonction en entrée et éclabousse ses autres arguments à la fonction. Il est largement utilisé, par exemple, pour assembler des listes en structures plus simples (souvent avec rbind ou cbind).

Par exemple:

x <- lapply(iris, class)
do.call(c, x)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
   "numeric"    "numeric"    "numeric"    "numeric"     "factor" 
112
Andrie

lapply applique une fonction sur une liste, do.call appelle une fonction avec une liste d'arguments. Cela ressemble à une différence pour moi ...

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, comme mean s'attend à ce que l'argument "trim" soit égal à 1.

D'autre part, rbind lie tous les arguments ligne par ligne. Donc, pour lier X par rangée, 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 appliquerait rbind à chaque élément de la liste, ce qui vous donnerait 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 ?mapply, ce qui est tout à fait différent. Pour obtenir par exemple la moyenne de chaque élément dans X, mais avec un ajustement différent, vous pouvez utiliser:

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

lapply est similaire à map, do.call n'est pas. lapply applique une fonction à tous les éléments d'une liste, do.call appelle une fonction où tous les arguments de la fonction sont dans une liste. Ainsi, pour une liste d'éléments n, lapply a n appels de fonction et do.call n'a qu'un seul appel de fonction. Alors do.call est assez 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)
30
Paul Hiemstra

En termes simples:

  1. lapply () applique une fonction donnée pour chaque élément de la liste. Il y aura donc plusieurs appels de fonction.

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

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

24
LoveMeow

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

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

Bien qu'il y ait eu beaucoup de réponses, voici mon exemple à titre de 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]]))

Faisons maintenant la même chose pour do.call

do.call(sum, L) 

Ça veut dire

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

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

10
kimman

La différence entre les deux sont:

lapply(1:n,function,parameters)

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

do.call 

Envoie simplement 1… n en tant que vecteur et paramètres pour fonctionner

Donc, en appliquant vous avez n appels de fonction, en do.call vous n’avez qu’un seul

5
nitin lal