Qual è la differenza tra lapply e do.call?


143

Sto imparando R di recente e confuso da due funzioni: lapplye do.call. Sembra che siano semplicemente simili alla mapfunzione in Lisp. Ma perché ci sono due funzioni con un nome così diverso? Perché R non usa semplicemente una funzione chiamata map?

Risposte:


126

Esiste una funzione chiamata Mapche può essere simile alla mappa in altre lingue:

  • lapply restituisce un elenco della stessa lunghezza di X, ogni cui elemento è il risultato dell'applicazione di FUN all'elemento corrispondente di X.

  • do.call costruisce ed esegue una chiamata di funzione da un nome o una funzione e un elenco di argomenti da passargli.

  • Mapapplica una funzione agli elementi corrispondenti di determinati vettori ... Mapè un semplice wrapper al mapplyquale non tenta di semplificare il risultato, simile al mapcar del Common Lisp (con argomenti che vengono riciclati, tuttavia). Le versioni future potrebbero consentire un certo controllo del tipo di risultato.


  1. Map è un involucro in giro mapply
  2. lapply è un caso speciale di mapply
  3. Pertanto Mape lapplysarà simile in molti casi.

Ad esempio, ecco lapply:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

E lo stesso 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.callaccetta una funzione come input e schizza i suoi altri argomenti sulla funzione. È ampiamente usato, ad esempio, per assemblare elenchi in strutture più semplici (spesso con rbindo cbind).

Per esempio:

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

4
in realtà ho scoperto che do.callè quasi lo stesso applydi Lisp
Hanfei Sun,

non è l'ultimo esempio che dovrebbe essere do.call(cbind, x)la versione attuale mi dà Error in do.call(c, x) : 'what' must be a function or character string...
sindri_baldur

1
@snoram Quell'esempio funziona ancora. La funzione cbind()è diversa dalla funzione c()e sebbene funzioni anche in questo modo, fornisce risultati diversi.
Andrie,

61

lapplyapplica una funzione su un elenco, do.callchiama una funzione con un elenco di argomenti. Questa sembra una differenza per me ...

Per fare un esempio con un elenco:

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

Con lapply ottieni la media di ogni elemento nell'elenco in questo modo:

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

[[2]]
[1] 5

[[3]]
[1] 8

do.call dà un errore, poiché mean si aspetta che l'argomento "trim" sia 1.

D'altra parte, rbindlega tutti gli argomenti in ordine di riga. Quindi per associare X in ordine di riga, fai:

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

Se lo utilizzassi lapply, R si applicherebbe rbinda tutti gli elementi dell'elenco, dandoti questa assurdità:

> 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

Per avere qualcosa come Map, è necessario ?mapply, che è qualcosa di completamente diverso. Per ottenere ad esempio la media di ogni elemento in X, ma con un taglio diverso, puoi usare:

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

34

lapplyè simile a map, do.callnon lo è. lapplyapplica una funzione a tutti gli elementi di un elenco, do.callchiama una funzione in cui tutti gli argomenti della funzione sono in un elenco. Quindi, per un nelenco di elementi, lapplyha nchiamate di funzione e do.callha solo una chiamata di funzione. Quindi do.callè abbastanza diverso da lapply. Spero che questo chiarisca il tuo problema.

Un esempio di codice:

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

e:

lapply(c(1, 2, 4, 1, 2), function(x) x + 1)

25

In parole semplici:

  1. lapply () applica una determinata funzione per ciascun elemento in un elenco, quindi ci saranno diverse chiamate di funzione.

  2. do.call () applica una determinata funzione all'elenco nel suo insieme, quindi c'è solo una chiamata di funzione.

Il modo migliore per imparare è giocare con gli esempi di funzioni nella documentazione R.


12

lapply()è una funzione simile a una mappa. do.call()è diverso. Viene utilizzato per passare gli argomenti a una funzione in forma di elenco invece di averli elencati. Per esempio,

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

10

Sebbene ci siano state molte risposte, ecco il mio esempio di riferimento. Supponiamo di avere un elenco di dati come:

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

La funzione lapply restituisce un elenco.

lapply(L, sum) 

Quanto sopra significa qualcosa di simile al di sotto.

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

Ora facciamo la stessa cosa per do.call

do.call(sum, L) 

Significa

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

Nel nostro esempio, restituisce 21. In breve, lapply restituisce sempre un elenco mentre il tipo restituito di do.call dipende in realtà dalla funzione eseguita.


5

La differenza tra entrambi sono:

lapply(1:n,function,parameters)

=> Questo invia 1, parametri per la funzione => questo invia 2, parametri per la funzione e così via

do.call 

Invia solo 1 ... n come vettore e parametri per funzionare

Quindi in apply hai n chiamate di funzione, in do.call ne hai solo una

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.