Jaka jest różnica między lapply i do.call?

143

Niedawno uczę się języka R i jestem zdezorientowany przez dwie funkcje: lapplyi do.call. Wygląda na to, że są po prostu podobne do mapfunkcji w Lispie. Ale dlaczego istnieją dwie funkcje o tak różnych nazwach? Dlaczego R nie używa po prostu funkcji o nazwie map?

Hanfei Sun
źródło

Odpowiedzi:

125

Istnieje funkcja o nazwie, Mapktóra może być podobna do mapy w innych językach:

  • lapply zwraca listę o tej samej długości co X, której każdy element jest wynikiem zastosowania FUN do odpowiedniego elementu X.

  • do.call konstruuje i wykonuje wywołanie funkcji z nazwy lub funkcji oraz listy argumentów, które mają być do niej przekazane.

  • Mapstosuje funkcję do odpowiednich elementów danych wektorów ... Mapjest prostym opakowaniem, mapplyktóre nie próbuje uprościć wyniku, podobnie jak mapcar Common Lispa (jednak z odzyskiwaniem argumentów). Przyszłe wersje mogą pozwolić na pewną kontrolę nad typem wyniku.


  1. Map jest opakowaniem wokół mapply
  2. lapply jest szczególnym przypadkiem mapply
  3. Dlatego Mapiw lapplywielu przypadkach będzie podobnie.

Na przykład tutaj jest lapply:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

I to samo używając Map:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

do.callprzyjmuje funkcję jako dane wejściowe i rozdziela jej inne argumenty na funkcję. Jest szeroko stosowany na przykład do tworzenia list w prostsze struktury (często z rozszerzeniemrbind lub cbind).

Na przykład:

x <- lapply(iris, class)
do.call(c, x)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
   "numeric"    "numeric"    "numeric"    "numeric"     "factor" 
Andrie
źródło
4
właściwie znalazłem do.callto prawie to samo co applyw Lisp
Hanfei Sun
czy to nie ostatni przykład ma być do.call(cbind, x)obecną wersją, która daje mi Error in do.call(c, x) : 'what' must be a function or character string...
sindri_baldur
1
@snoram Ten przykład nadal działa. Funkcja cbind()różni się od funkcji c()i chociaż to również działa, daje inne wyniki.
Andrie,
61

lapply stosuje funkcję na liście, do.call wywołuje funkcję z listą argumentów. Dla mnie wygląda to na dużą różnicę ...

Aby podać przykład z listą:

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

Z lapply otrzymujesz średnią każdego elementu na liście w ten sposób:

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

[[2]]
[1] 5

[[3]]
[1] 8

do.call daje błąd, ponieważ średnia oczekuje, że argument „trim” będzie równy 1.

Z drugiej strony rbindwiąże wszystkie argumenty wierszowo. Aby połączyć X wierszami, wykonaj:

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

Gdybyś użył lapply, R miałoby zastosowanie rbinddo każdego elementu listy, co daje taki nonsens:

> 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

Aby mieć coś takiego jak Mapa, potrzebujesz ?mapply, co jest czymś zupełnie innym. Aby uzyskać np. Średnią każdego elementu w X, ale z innym przycięciem, możesz użyć:

> mapply(mean,X,trim=c(0,0.5,0.1))
[1] 2 5 8
Joris Meys
źródło
34

lapplyjest podobny do map, do.callnie jest. lapplystosuje funkcję do wszystkich elementów listy, do.callwywołuje funkcję, w której wszystkie argumenty funkcji znajdują się na liście. Więc dla nlisty elementów lapplyma nwywołania funkcji i do.callma tylko jedno wywołanie funkcji. Więc do.callróżni się od lapply. Mam nadzieję, że to wyjaśnia twój problem.

Przykład kodu:

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

i:

lapply(c(1, 2, 4, 1, 2), function(x) x + 1)
Paul Hiemstra
źródło
25

Najprościej mówiąc:

  1. lapply () stosuje daną funkcję dla każdego elementu na liście, więc będzie kilka wywołań funkcji.

  2. do.call () stosuje daną funkcję do listy jako całości, więc jest tylko jedno wywołanie funkcji.

Najlepszym sposobem nauki jest zabawienie się z przykładami funkcji w dokumentacji języka R.

LoveMeow
źródło
12

lapply()jest funkcją podobną do mapy. do.call()jest inny. Służy do przekazywania argumentów do funkcji w formie listy zamiast ich wyliczania. Na przykład,

> do.call("+",list(4,5))
[1] 9
frankc
źródło
10

Chociaż odpowiedzi było wiele, oto mój przykład w celach informacyjnych. Załóżmy, że mamy listę danych jako:

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

Funkcja lapply zwraca listę.

lapply(L, sum) 

Powyższe oznacza coś takiego jak poniżej.

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

Zróbmy teraz to samo dla do.call

do.call(sum, L) 

To znaczy

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

W naszym przykładzie zwraca 21. Krótko mówiąc, lapply zawsze zwraca listę, podczas gdy typ zwracania funkcji do.call naprawdę zależy od wykonywanej funkcji.

kimman
źródło
5

Różnica między nimi to:

lapply(1:n,function,parameters)

=> Wysyła 1, parametry do funkcji => wysyła 2, parametry do funkcji i tak dalej

do.call 

Po prostu wysyła 1… n jako wektor i parametry do działania

Więc w stosowaniu masz n wywołań funkcji, w do.call masz tylko jedno

nitin lal
źródło