波浪号运算符具有何种普遍性可用于构建匿名函数?
With which generality can tilde operator be used to build anonymous functions?
在某些函数中,如 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
?对于某些特殊情况,base R
是否可以理解?
谢谢!
公式对象不是函数,只有将公式传递给的被调用函数编写为将公式参数解释为函数时,公式才会被视为函数。许多 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
,类似于 base R 中的 match.fun
,除了它还将公式解释为函数。这让人们可以编写自己的函数,这些函数接受将它们解释为函数的公式参数。
就问题中的例子而言:
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]])
正如 caldwellst 上面所说,tilda ~
用于创建公式对象,这是一些未计算的代码,可以稍后使用。公式与函数不同,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
在某些函数中,如 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
?对于某些特殊情况,base R
是否可以理解?
谢谢!
公式对象不是函数,只有将公式传递给的被调用函数编写为将公式参数解释为函数时,公式才会被视为函数。许多 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
,类似于 base R 中的 match.fun
,除了它还将公式解释为函数。这让人们可以编写自己的函数,这些函数接受将它们解释为函数的公式参数。
就问题中的例子而言:
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]])
正如 caldwellst 上面所说,tilda ~
用于创建公式对象,这是一些未计算的代码,可以稍后使用。公式与函数不同,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