С какой общностью можно использовать оператор тильды для создания анонимных функций? - PullRequest
0 голосов
/ 14 октября 2019

Внутри некоторых функций, таких как dplyr::mutate_at или purrr::map, кажется , что можно использовать оператор тильды ~ для создания анонимных функций .

ДляНапример, можно сделать как в связанном вопросе: map(iris, ~length(unique(.)))

Или также: mtcars %>% mutate_all(~.*2)

Я пытался подражать этому внутри sapply, чтобы избежать sapply(list, function(item) {something_with_item}). Я писал sapply(list, ~ something_with_.), но я получаю ошибку

Error in match.fun(FUN) : 
  '~ something_with_.' is not a function, character or symbol

Воспроизводимый пример:

> sapply(names(mtcars),function(item) mean(mtcars[[item]]))
       mpg        cyl       disp         hp       drat         wt       qsec 
 20.090625   6.187500 230.721875 146.687500   3.596563   3.217250  17.848750 
        vs         am       gear       carb 
  0.437500   0.406250   3.687500   2.812500 
> sapply(names(mtcars),~mean(mtcars[[.]]))
Error in match.fun(FUN) : 
  '~mean(mtcars[[.]])' is not a function, character or symbol

Почему? Понимание этого синтаксиса как функции - это просто поведение некоторых пакетов как dplyr и purrr? Это понимается базой R для некоторых особых случаев?

Спасибо!

Ответы [ 2 ]

1 голос
/ 14 октября 2019

Как сказал выше caldwellst, тильда ~ используется для создания объекта формулы, представляющего собой немного неоцененный код, который можно использовать позже. Формулы не совпадают с функциями, и функции purrr работают с формулами, потому что они вызывают rlang::as_function (через purrr::as_mapper) в фоновом режиме. Функции *apply, очевидно, этого не делают, хотя вы можете имитировать это поведение, вызывая одну из вышеперечисленных функций в своей собственной измененной функции *apply (лучше просто использовать функции map, следующее просто дляпроиллюстрировать смысл):

# Write function with `as_mapper()`.
fapply <- function(x, func) {
    sapply(x, purrr::as_mapper(func))
}

# Now we can use formulae.
fapply(names(mtcars), ~ mean(mtcars[[.]]))

#### OUTPUT ####

       mpg        cyl       disp         hp       drat         wt       qsec         vs         am       gear       carb 
 20.090625   6.187500 230.721875 146.687500   3.596563   3.217250  17.848750   0.437500   0.406250   3.687500   2.812500 
1 голос
/ 14 октября 2019

Объект формулы не является функцией, и формула будет рассматриваться как функция, только если вызванная функция, которой передается формула, была написана для интерпретации аргументов формулы как функции. Многие из функций tidyverse написаны таким образом, но в общем случае формула по умолчанию не является функцией.

fn $

В пакете gusbfn есть fn$, что позволит использовать практически любую функциюкоторый принимает аргумент функции для принятия формул. Предисловие вызова функции с fn$, а затем аргументы формулы интерпретируются как функции (при условии соблюдения определенных правил).

В примере, приведенном в вопросе, мы можем сделать это, не требуя написания специальной версии sapply для интерпретации формул как функций:

library(gsubfn)

fn$sapply(names(mtcars), item ~ mean(mtcars[[item]]))

, что дает:

       mpg        cyl       disp         hp       drat         wt       qsec 
 20.090625   6.187500 230.721875 146.687500   3.596563   3.217250  17.848750 
        vs         am       gear       carb 
  0.437500   0.406250   3.687500   2.812500 

См. ?fn для получения дополнительной информации и примеров.

match.funfn

В пакете gsubfn также есть match.funfn, что похоже на match.fun в базе R, кроме неготакже будет интерпретировать формулы как функции. Это позволяет писать свои собственные функции, которые принимают аргументы формулы, интерпретируя их как функции.

В соответствии с примером в вопросе:

library(gsubfn)

sapplyfn <- function(X, FUN, ...) {
  FUN <- match.funfn(FUN)
  sapply(X, FUN, ...)
}

sapplyfn(names(mtcars), item ~ mean(mtcars[[item]]))

, дающим:

       mpg        cyl       disp         hp       drat         wt       qsec 
 20.090625   6.187500 230.721875 146.687500   3.596563   3.217250  17.848750 
        vs         am       gear       carb 
  0.437500   0.406250   3.687500   2.812500 

as.function.formula

Пакет gsubfn такжеимеет as.function.formula, который преобразует формулу в функцию. Используется fn$ и match.funfn. Например,

library(gsubfn)
as.function(item ~ mean(mtcars[[item]]))

, дающий:

function (item) 
mean(mtcars[[item]])
...