Яка різниця між lapply і do.call?


143

Я нещодавно вивчаю R і переплутана двома функціями: lapplyі do.call. Здається, вони просто схожі на mapфункцію в Lisp. Але чому існують дві функції з такою різною назвою? Чому R просто не використовує функцію, яку називають map?

Відповіді:


126

Існує названа функція, Mapяка може бути схожа на карту іншими мовами:

  • lapply повертає список тієї ж довжини, що і X, кожен елемент якого є результатом застосування FUN до відповідного елемента X.

  • do.call будує та виконує виклик функції з імені або функції та списку аргументів, що передаються їй.

  • MapЗастосовує функцію до відповідних елементів заданих векторів ... Map- це проста обгортка, до mapplyякої не намагаються спростити результат, подібно до картографа Common Lisp (однак аргументи рециркулюються). Майбутні версії можуть дозволити деякий контроль над типом результату.


  1. Map - це обгортка навколо mapply
  2. lapply є особливим випадком mapply
  3. Тому Mapі lapplyбуде подібним у багатьох випадках.

Наприклад, ось lapply:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

І те саме, використовуючи Map:

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

$Sepal.Width
[1] "numeric"

$Petal.Length
[1] "numeric"

$Petal.Width
[1] "numeric"

$Species
[1] "factor"

do.callприймає функцію в якості вхідного даних і бризки інших аргументів функції. Він широко використовується, наприклад, для збирання списків у більш прості структури (часто з rbindабо cbind).

Наприклад:

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

4
насправді я знайшов do.callмайже те саме, що і applyв Ліспі
— Ханфей, Сонце,

чи не останній приклад, який має бути do.call(cbind, x)поточною версією, дає мені Error in do.call(c, x) : 'what' must be a function or character string...
— sindri_baldur

1
@snoram Цей приклад все ще працює. Функція cbind()відрізняється від функції c(), і хоча ця функція також працює, вона дає різні результати.
— Андрі

61

lapplyзастосовує функцію над списком, do.callвикликає функцію зі списком аргументів. Це виглядає як для мене зовсім різниця ...

Щоб навести приклад зі списком:

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

За допомогою лампа ви отримуєте середнє значення кожного елемента у списку, як це:

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

[[2]]
[1] 5

[[3]]
[1] 8

do.call дає помилку, оскільки середнє очікує, що аргумент "обрізка" дорівнює 1.

З іншого боку, rbindпов'язує всі аргументи rowwise. Отже, щоб зв’язати X rowwise, ви зробите:

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

Якщо ви використовуєте lapply, R застосовуватиметься rbindдо кожного елемента списку, даючи вам цю нісенітницю:

> 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

Щоб мати щось на кшталт Map, вам потрібно ?mapply, що взагалі щось різне. Щоб отримати, наприклад, середнє значення кожного елемента в X, але з різною обробкою, ви можете використовувати:

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

34

lapplyсхожий на map, do.callні. lapplyзастосовує функцію до всіх елементів списку, do.callвикликає функцію, де всі аргументи функції знаходяться у списку. Таким чином , для nсписку елементів, lapplyмають nвиклики функцій, і do.callмає тільки один виклик функції. Так що do.callзовсім відрізняється від lapply. Сподіваємось, це пояснить вашу проблему.

Приклад коду:

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

і:

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

25

Найбільш простими словами:

  1. lapply () застосовує задану функцію для кожного елемента в списку, тому буде кілька викликів функцій.

  2. do.call () застосовує задану функцію до списку в цілому, тому існує лише один виклик функції.

Найкращий спосіб навчитися - це грати з прикладами функцій у документації R.


12

lapply()- карта-функція. do.call()інакший. Він використовується для передачі аргументів функції у формі списку, а не для їх перерахування. Наприклад,

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

10

Хоча відповідей було багато, ось мій приклад для довідки. Припустимо, у нас є список даних як:

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

Функція lapply повертає список.

lapply(L, sum) 

Сказане означає щось подібне нижче.

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

Тепер давайте зробимо те ж саме для do.call

do.call(sum, L) 

Це означає

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

У нашому прикладі він повертає 21. Коротше кажучи, lapply завжди повертає список, тоді як тип повернення do.call дійсно залежить від виконуваної функції.


5

Різниця між обома:

lapply(1:n,function,parameters)

=> Це відправлення 1, параметри до функції => це посилає 2, параметри для функціонування тощо

do.call 

Просто надсилає 1 ... n як вектор і параметри для функціонування

Отже, у застосуванні у вас є n функціональних викликів, у do.call у вас є лише один

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.