Какая разница между lapply и do.call?

Недавно я изучаю R и смущен двумя функциями: lapply и do.call. Похоже, что они похожи на функцию map в Lisp. Но почему существуют две функции с таким именем? Почему R не использует только функцию map?

Ответ 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