Недавно я изучаю R и смущен двумя функциями: lapply
и do.call
. Похоже, что они похожи на функцию map
в Lisp. Но почему существуют две функции с таким именем? Почему R не использует только функцию map
?
Какая разница между lapply и do.call?
Ответ 1
Существует функция с именем Map
, которая может быть похожа на карту на других языках:
-
lapply
возвращает список той же длины, что и X, каждый элемент которого является результатом применения FUN к соответствующему элементу X. -
do.call
строит и выполняет вызов функции от имени или функции и список аргументов, которые должны быть переданы ему. -
Map
применяет функцию к соответствующим элементам заданных векторов...Map
представляет собой простую оболочку дляmapply
, которая не пытается упростить результат, аналогичный Common Lisp mapcar ( с аргументами, которые перерабатываются, однако). Будущие версии могут позволить некоторый контроль над типом результата.
-
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"
Ответ 2
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
дает ошибку, так как среднее ожидает, что аргумент "trim" будет равен 1.
С другой стороны, rbind
связывает все аргументы rowwise. Чтобы связать X-роллинг, выполните следующие действия:
> 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
Чтобы иметь что-то вроде Карты, вам нужно ?mapply
, что-то другое. Чтобы получить, например, среднее значение для каждого элемента в X, но с другой обрезкой, вы можете использовать:
> mapply(mean,X,trim=c(0,0.5,0.1))
[1] 2 5 8
Ответ 3
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)
Ответ 4
В самых простых словах:
-
lapply() применяет заданную функцию для каждого элемента в списке, поэтому будет несколько вызовов функций.
-
do.call() применяет данную функцию к списку в целом, поэтому есть только один вызов функции.
Лучший способ учиться - играть с примерами функций в документации R.
Ответ 5
lapply()
- это карта-подобная функция. do.call()
отличается. Он используется для передачи аргументов функции в виде списка вместо их перечисления. Например,
> do.call("+",list(4,5))
[1] 9
Ответ 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 действительно зависит от выполняемой функции.
Ответ 7
Различие между ними:
lapply(1:n,function,parameters)
= > Это отправить 1, параметры для функции = > это отправляет 2, параметры для функции и т.д.
do.call
Просто отправляет 1... n в качестве вектора и параметры для функции
Итак, у вас есть n вызовов функций, в do.call у вас есть только один
Ответ 8
Я чувствовал, что один важный аспект do.call
здесь не был продемонстрирован (или не был явным для меня); то есть вы можете передать именованные параметры в list
функции с помощью do.call
.
Например, runif
принимает параметры n
, min
и max
. Их можно передать с помощью do.call
, как показано ниже.
para <- list(n = 10, min = -1, max = 1)
do.call(runif, para)
#[1] -0.4689827 -0.2557522 0.1457067 0.8164156 -0.5966361 0.7967794
#[7] 0.8893505 0.3215956 0.2582281 -0.8764275