Недавно я изучаю 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