/ / Яка різниця між lapply та do.call? - r, функціонально-програмування

Яка різниця між lapply і do.call? - r, функціональне програмування

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

Відповіді:

100 для відповіді № 1

Існує функція, яка називається 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"

51 за відповідь № 2

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

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

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

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

> 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

28 для відповіді № 3

lapply схоже на map, do.call не. lapply застосовує функцію до всіх елементів списку, do.call викликає функцію, де всі аргументи функції знаходяться у списку. Отже для a 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)

20 за відповідь № 4

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

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

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

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


12 за відповіддю № 5

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

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

8 для відповіді № 6

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

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 за відповідь № 7

Різниця між ними:

lapply(1:n,function,parameters)

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

do.call

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

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