Я нещодавно вивчаю R і переплутана двома функціями: lapply
і do.call
. Здається, вони просто схожі на map
функцію в Lisp. Але чому існують дві функції з такою різною назвою? Чому R просто не використовує функцію, яку називають map
?
Я нещодавно вивчаю R і переплутана двома функціями: lapply
і do.call
. Здається, вони просто схожі на map
функцію в Lisp. Але чому існують дві функції з такою різною назвою? Чому R просто не використовує функцію, яку називають map
?
Відповіді:
Існує названа функція, Map
яка може бути схожа на карту іншими мовами:
lapply
повертає список тієї ж довжини, що і X, кожен елемент якого є результатом застосування FUN до відповідного елемента X.
do.call
будує та виконує виклик функції з імені або функції та списку аргументів, що передаються їй.
Map
Застосовує функцію до відповідних елементів заданих векторів ... Map
- це проста обгортка, до mapply
якої не намагаються спростити результат, подібно до картографа Common Lisp (однак аргументи рециркулюються). Майбутні версії можуть дозволити деякий контроль над типом результату.
Map
- це обгортка навколо mapply
lapply
є особливим випадком mapply
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"
do.call(cbind, x)
поточною версією, дає мені Error in do.call(c, x) : 'what' must be a function or character string
...
cbind()
відрізняється від функції c()
, і хоча ця функція також працює, вона дає різні результати.
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
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)
Найбільш простими словами:
lapply () застосовує задану функцію для кожного елемента в списку, тому буде кілька викликів функцій.
do.call () застосовує задану функцію до списку в цілому, тому існує лише один виклик функції.
Найкращий спосіб навчитися - це грати з прикладами функцій у документації R.
Хоча відповідей було багато, ось мій приклад для довідки. Припустимо, у нас є список даних як:
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 дійсно залежить від виконуваної функції.
Різниця між обома:
lapply(1:n,function,parameters)
=> Це відправлення 1, параметри до функції => це посилає 2, параметри для функціонування тощо
do.call
Просто надсилає 1 ... n як вектор і параметри для функціонування
Отже, у застосуванні у вас є n функціональних викликів, у do.call у вас є лише один
do.call
майже те саме, що іapply
в Ліспі