Sự khác biệt giữa lapply và do.call là gì?


143

Tôi đang học R gần đây và bối rối bởi hai chức năng: lapplydo.call. Có vẻ như chúng chỉ tương tự như mapchức năng trong Lisp. Nhưng tại sao có hai chức năng với một tên khác nhau như vậy? Tại sao R không sử dụng hàm gọi là map?

Câu trả lời:


125

Có một chức năng được gọi là Mapcó thể tương tự như bản đồ trong các ngôn ngữ khác:

  • lapply trả về một danh sách có cùng độ dài với X, mỗi phần tử là kết quả của việc áp dụng FUN cho phần tử tương ứng của X.

  • do.call xây dựng và thực hiện một cuộc gọi hàm từ một tên hoặc một hàm và một danh sách các đối số được truyền cho nó.

  • Mapáp dụng một hàm cho các phần tử tương ứng của các vectơ đã cho ... Maplà một trình bao bọc đơn giản mapplymà không cố gắng đơn giản hóa kết quả, tương tự như bản đồ của Common Lisp (tuy nhiên với các đối số được tái chế). Các phiên bản trong tương lai có thể cho phép một số kiểm soát của loại kết quả.


  1. Map là một bao bọc xung quanh mapply
  2. lapply là một trường hợp đặc biệt của mapply
  3. Do đó Maplapplysẽ tương tự trong nhiều trường hợp.

Ví dụ, đây là lapply:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

Và sử dụng tương tự Map:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

do.callnhận một hàm làm đầu vào và phân tách các đối số khác của nó cho hàm. Nó được sử dụng rộng rãi, ví dụ, để tập hợp các danh sách thành các cấu trúc đơn giản hơn (thường có rbindhoặc cbind).

Ví dụ:

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

4
thực ra tôi thấy do.callgần giống như applyở Lisp
Hanfei Sun

không phải là ví dụ cuối cùng được cho là do.call(cbind, x)phiên bản hiện tại mang lại cho tôi Error in do.call(c, x) : 'what' must be a function or character string...
sindri_baldur

1
@snoram Ví dụ đó vẫn hoạt động. Hàm cbind()này khác với hàm c()và mặc dù điều này cũng hoạt động, nhưng nó cho kết quả khác nhau.
Andrie

61

lapplyáp dụng một hàm trên một danh sách, do.callgọi một hàm với một danh sách các đối số. Điều đó có vẻ khá khác biệt với tôi ...

Để đưa ra một ví dụ với một danh sách:

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

Với lapply bạn có được ý nghĩa của mọi yếu tố trong danh sách như thế này:

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

[[2]]
[1] 5

[[3]]
[1] 8

do.call đưa ra một lỗi, như có nghĩa là mong đợi đối số "trim" là 1.

Mặt khác, rbindliên kết tất cả các đối số theo hàng. Vì vậy, để liên kết X theo hàng, bạn làm:

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

Nếu bạn sẽ sử dụng lapply, R sẽ áp dụng rbindcho mọi thành phần của danh sách, cung cấp cho bạn điều vô nghĩa này:

> 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

Để có một cái gì đó giống như Bản đồ, bạn cần ?mapply, đó là một cái gì đó khác nhau hoàn toàn. Để lấy ví dụ: giá trị trung bình của mọi phần tử trong X, nhưng với cách cắt khác nhau, bạn có thể sử dụng:

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

34

lapplylà tương tự map, do.calllà không. lapplyáp dụng một hàm cho tất cả các thành phần của danh sách, do.callgọi một hàm trong đó tất cả các đối số hàm nằm trong danh sách. Vì vậy, đối với một ndanh sách thành phần, lapplyncác lệnh gọi hàm và do.callchỉ có một lệnh gọi hàm. Vì vậy, do.calllà khá khác nhau từ lapply. Hy vọng điều này làm rõ vấn đề của bạn.

Một ví dụ mã:

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

và:

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

25

Nói một cách đơn giản nhất:

  1. lapply () áp dụng một hàm nhất định cho từng thành phần trong danh sách, do đó sẽ có một số lệnh gọi hàm.

  2. do.call () áp dụng một hàm nhất định cho toàn bộ danh sách, do đó chỉ có một lệnh gọi hàm.

Cách tốt nhất để học là chơi xung quanh với các ví dụ chức năng trong tài liệu R.


12

lapply()là một chức năng giống như bản đồ. do.call()khác. Nó được sử dụng để truyền các đối số cho một hàm ở dạng danh sách thay vì liệt kê chúng. Ví dụ,

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

10

Mặc dù đã có nhiều câu trả lời, đây là ví dụ của tôi để tham khảo. Giả sử chúng ta có một danh sách dữ liệu như:

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

Hàm lapply trả về một danh sách.

lapply(L, sum) 

Ở trên có nghĩa là một cái gì đó như dưới đây.

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

Bây giờ hãy để chúng tôi làm điều tương tự cho do.call

do.call(sum, L) 

Nó có nghĩa là

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

Trong ví dụ của chúng tôi, nó trả về 21. Tóm lại, lapply luôn trả về một danh sách trong khi kiểu trả về của do.call thực sự phụ thuộc vào hàm được thực thi.


5

Sự khác biệt giữa cả hai là:

lapply(1:n,function,parameters)

=> Điều này gửi 1, tham số cho hàm => điều này sẽ gửi 2, tham số cho chức năng, v.v.

do.call 

Chỉ cần gửi 1 Nv như một vectơ và tham số cho hàm

Vì vậy, trong ứng dụng bạn có n cuộc gọi chức năng, trong do.call bạn chỉ có một cuộc gọi

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.