Apa perbedaan antara lapply dan do.call?

143

Saya belajar R baru-baru ini dan bingung oleh dua fungsi: lapplydan do.call. Tampaknya mereka hanya mirip dengan mapfungsi di Lisp. Tetapi mengapa ada dua fungsi dengan nama yang berbeda? Mengapa R tidak hanya menggunakan fungsi yang disebut map?

Hanfei Sun
sumber

Jawaban:

125

Ada fungsi yang disebut Mapyang mungkin mirip dengan peta dalam bahasa lain:

  • lapply mengembalikan daftar dengan panjang yang sama dengan X, yang setiap elemennya merupakan hasil dari penerapan FUN ke elemen X yang sesuai.

  • do.call membangun dan mengeksekusi panggilan fungsi dari nama atau fungsi dan daftar argumen untuk diteruskan ke sana.

  • Mapmenerapkan fungsi ke elemen terkait dari vektor yang diberikan ... Mapadalah pembungkus sederhana mapplyyang tidak berusaha menyederhanakan hasilnya, mirip dengan mapcar Common Lisp (dengan argumen yang didaur ulang, namun). Versi mendatang dapat memungkinkan beberapa kontrol dari tipe hasil.


  1. Map adalah pembungkus di sekitar mapply
  2. lapply adalah kasus khusus mapply
  3. Karena itu Mapdan lapplyakan serupa dalam banyak kasus.

Sebagai contoh, ini adalah lapply:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

Dan hal yang sama menggunakan Map:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

do.callmengambil fungsi sebagai input dan memecah argumen lainnya ke fungsi. Ini banyak digunakan, misalnya, untuk merakit daftar menjadi struktur yang lebih sederhana (seringkali dengan rbindatau cbind).

Sebagai contoh:

x <- lapply(iris, class)
do.call(c, x)
Sepal.Length  Sepal.Width Petal.Length  Petal.Width      Species 
   "numeric"    "numeric"    "numeric"    "numeric"     "factor" 
Andrie
sumber
4
sebenarnya saya temukan do.callhampir sama dengan applydi Lisp
Hanfei Sun
bukankah itu contoh terakhir yang seharusnya menjadi do.call(cbind, x)versi saat ini memberi saya Error in do.call(c, x) : 'what' must be a function or character string...
sindri_baldur
1
@ snoram Contoh itu masih berfungsi. Fungsi cbind()berbeda dari fungsi c(), dan meskipun ini juga berfungsi, ia memberikan hasil yang berbeda.
Andrie
61

lapplymenerapkan fungsi di atas daftar, do.callmemanggil fungsi dengan daftar argumen. Itu tampak sangat berbeda bagi saya ...

Untuk memberi contoh dengan daftar:

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

Dengan lapply Anda mendapatkan rata-rata dari setiap elemen dalam daftar seperti ini:

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

[[2]]
[1] 5

[[3]]
[1] 8

do.call memberikan kesalahan, karena rata-rata mengharapkan argumen "trim" menjadi 1.

Di sisi lain, rbindikat semua argumen secara searah. Jadi untuk mengikat X berturut-turut, Anda lakukan:

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

Jika Anda akan menggunakan lapply, R akan berlaku rbinduntuk setiap elemen daftar, memberi Anda omong kosong ini:

> 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

Untuk memiliki sesuatu seperti Peta, Anda perlu ?mapply, yang merupakan sesuatu yang sama sekali berbeda. Untuk mendapatkan misalnya rata-rata setiap elemen dalam X, tetapi dengan pemangkasan yang berbeda, Anda bisa menggunakan:

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

lapplymirip dengan map, do.callbukan. lapplymenerapkan fungsi ke semua elemen daftar, do.callmemanggil fungsi di mana semua argumen fungsi ada dalam daftar. Jadi untuk ndaftar elemen, lapplymemiliki npanggilan fungsi, dan do.callhanya memiliki satu panggilan fungsi. Jadi do.callsangat berbeda dari lapply. Semoga ini menjelaskan masalah Anda.

Contoh kode:

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

dan:

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

Dengan kata paling sederhana:

  1. lapply () menerapkan fungsi yang diberikan untuk setiap elemen dalam daftar, sehingga akan ada beberapa panggilan fungsi.

  2. do.call () menerapkan fungsi yang diberikan ke daftar secara keseluruhan, jadi hanya ada satu panggilan fungsi.

Cara terbaik untuk belajar adalah bermain-main dengan contoh-contoh fungsi dalam dokumentasi R.

LoveMeow
sumber
12

lapply()adalah fungsi seperti peta. do.call()berbeda. Ini digunakan untuk meneruskan argumen ke fungsi dalam bentuk daftar daripada meminta mereka disebutkan. Misalnya,

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

Meskipun sudah ada banyak jawaban, ini adalah contoh saya untuk referensi. Misalkan kita memiliki daftar data sebagai:

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

Fungsi ini mengembalikan daftar.

lapply(L, sum) 

Di atas berarti sesuatu seperti di bawah ini.

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

Sekarang mari kita lakukan hal yang sama untuk do.call

do.call(sum, L) 

Itu berarti

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

Dalam contoh kita, ia mengembalikan 21. Singkatnya, lapply selalu mengembalikan daftar sementara jenis kembalinya dari do.call benar-benar tergantung pada fungsi yang dijalankan.

Kimman
sumber
5

Perbedaan keduanya adalah:

lapply(1:n,function,parameters)

=> Ini mengirim 1, parameter berfungsi => ini mengirim 2, parameter berfungsi dan seterusnya

do.call 

Hanya mengirim 1 ... n sebagai vektor dan parameter berfungsi

Jadi dalam berlaku Anda memiliki panggilan fungsi n, di do.call Anda hanya memiliki satu

nitin lal
sumber