Яка різниця між 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.