¿Cuál es la diferencia entre lapply y do.call?

143

Estoy aprendiendo R recientemente y confundido por dos funciones: lapplyy do.call. Parece que son similares a mapfuncionar en Lisp. Pero, ¿por qué hay dos funciones con un nombre tan diferente? ¿Por qué R no usa una función llamada map?

Hanfei Sun
fuente

Respuestas:

126

Hay una función llamada Mapque puede ser similar a map en otros idiomas:

  • lapply devuelve una lista de la misma longitud que X, cada elemento del cual es el resultado de aplicar FUN al elemento correspondiente de X.

  • do.call construye y ejecuta una llamada de función a partir de un nombre o una función y una lista de argumentos que se le pasarán.

  • Mapaplica una función a los elementos correspondientes de vectores dados ... Mapes un contenedor simple al mapplyque no intenta simplificar el resultado, similar al mapcar de Common Lisp (sin embargo, con los argumentos que se reciclan). Las versiones futuras pueden permitir cierto control del tipo de resultado.


  1. Map es un envoltorio alrededor mapply
  2. lapply es un caso especial de mapply
  3. Por lo tanto Mapy lapplyserá similar en muchos casos.

Por ejemplo, aquí está lapply:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

Y lo mismo usando Map:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

do.calltoma una función como entrada y salpica sus otros argumentos a la función. Es ampliamente utilizado, por ejemplo, para ensamblar listas en estructuras más simples (a menudo conrbind o cbind).

Por ejemplo:

x <- lapply(iris, class)
do.call(c, x)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
   "numeric"    "numeric"    "numeric"    "numeric"     "factor" 
Andrie
fuente
44
En realidad, encontré que do.calles casi lo mismo que applyen Lisp
Hanfei Sun
No es que el último ejemplo supone que es do.call(cbind, x)la versión actual me da Error in do.call(c, x) : 'what' must be a function or character string...
sindri_baldur
1
@snoram Ese ejemplo aún funciona. La función cbind()es diferente de la función c(), y aunque esto también funciona, da resultados diferentes.
Andrie
61

lapplyaplica una función sobre una lista, do.callllama a una función con una lista de argumentos. Eso me parece una gran diferencia ...

Para dar un ejemplo con una lista:

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

Con lapply obtienes la media de cada elemento de la lista de esta manera:

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

[[2]]
[1] 5

[[3]]
[1] 8

do.call da un error, ya que la media espera que el argumento "recortar" sea 1.

Por otro lado, rbindune todos los argumentos rowwise. Entonces, para unir X rowwise, haces:

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

Si lo usara lapply, R se aplicaría rbinda cada elemento de la lista, dándole estas tonterías:

> 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

Para tener algo como Mapa, necesitas ?mapply, que es algo completamente diferente. Para obtener, por ejemplo, la media de cada elemento en X, pero con un recorte diferente, puede usar:

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

lapplyes similar a map, do.callno lo es. lapplyaplica una función a todos los elementos de una lista, do.callllama a una función donde todos los argumentos de la función están en una lista. Entonces, para una nlista de elementos, lapplytiene nllamadas a funciones y do.callsolo tiene una llamada a funciones. Entonces do.calles bastante diferente de lapply. Espero que esto aclare tu problema.

Un ejemplo de código:

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

y:

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

En palabras más simples:

  1. lapply () aplica una función dada para cada elemento en una lista, por lo que habrá varias llamadas a funciones.

  2. do.call () aplica una función dada a la lista como un todo, por lo que solo hay una llamada a la función.

La mejor manera de aprender es jugar con los ejemplos de funciones en la documentación de R.

LoveMeow
fuente
12

lapply()Es una función de mapa. do.call()es diferente. Se utiliza para pasar los argumentos a una función en forma de lista en lugar de enumerarlos. Por ejemplo,

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

Aunque ha habido muchas respuestas, aquí está mi ejemplo de referencia. Supongamos que tenemos una lista de datos como:

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

La función lapply devuelve una lista.

lapply(L, sum) 

Lo anterior significa algo como abajo.

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

Ahora hagamos lo mismo para do.call

do.call(sum, L) 

Significa

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

En nuestro ejemplo, devuelve 21. En resumen, lapply siempre devuelve una lista, mientras que el tipo de retorno de do.call realmente depende de la función ejecutada.

Kimman
fuente
5

La diferencia entre ambos es:

lapply(1:n,function,parameters)

=> Este envío 1, parámetros para funcionar => esto envía 2, parámetros para funcionar, etc.

do.call 

Solo envía 1 ... n como vector y parámetros para funcionar

Entonces, en apply, tienes n llamadas a funciones, en do.call solo tienes una

nitin lal
fuente