R:“f(x) 中的错误:在尝试将函数列用作 tibble 中的参数时找不到函数 "f"”

R: `Error in f(x): could not find function "f"` when trying to use column of functions as argument in a tibble

我正在尝试在 R 中的数据帧(tidyverse tibbles)中使用函数,但我 运行 遇到了一些困难。以下是我的问题的一个最小(简单)示例。

假设我有一个接受三个参数的函数:xy 是数字,f 是一个函数。它执行 f(x) + y 和 returns 输出:

func_then_add = function(x, y, f) {
  result = f(x) + y
  return(result)
}

我有一些简单的函数可以用作 f:

squarer = function(x) {
  result = x^2
  return(result)
}

cuber = function(x) {
  result = x^3
  return(result)
}

自行完成,func_then_add 与宣传的一样:

> func_then_add(5, 2, squarer)
[1] 27
> func_then_add(6, 11, cuber)
[1] 227

但是假设我有一个数据框(tidyverse tibble),其中两列用于数字参数,一列用于我想要的函数:

library(tidyverse)
library(magrittr)

test_frame = tribble(
  ~arg_1, ~arg_2, ~func,
  5, 2, squarer,
  6, 11, cuber
)

> test_frame
# A tibble: 2 x 3
  arg_1 arg_2 func  
  <dbl> <dbl> <list>
1     5     2 <fn>  
2     6    11 <fn>  

然后我想将等于 func_then_add 的另一列 result 应用到这三列。它应该像以前一样是 27227。但是当我尝试这个时,我得到一个错误:

> test_frame %>% mutate(result=func_then_add(.$arg_1, .$arg_2, .$func))
Error in f(x) : could not find function "f"

为什么会发生这种情况,我该如何正确获得我想要的东西?我承认我是 "functional programming" 的新手,所以也许我只是犯了一个明显的语法错误...

不是最优雅的,但我们可以做到:

test_frame %>% 
  mutate(Res= map(seq_along(.$func), function(x)
        func_then_add(.$arg_1, .$arg_2, .$func[[x]]))) 

EDIT:上面的 map 都覆盖了整个数据,这并不是 OP 真正想要的。正如@January 所建议的,这可以更好地应用为:

Result <- test_frame %>% 
  mutate(Res= map(seq_along(.$func), function(x)
       func_then_add(.$arg_1[x], .$arg_2[x], .$func[[x]])))

Result$Res 

上面的代码又不是很有效,因为它 returns 是一个列表。一个更好的选择(再次由@January 建议是使用 map_dbl 其中 returns 与其对象相同的数据类型:

test_frame %>% 
   mutate(Res= map_dbl(seq_along(.$func), function(x)
       func_then_add(.$arg_1[x], .$arg_2[x], .$func[[x]])))
# A tibble: 2 x 4
  arg_1 arg_2 func     Res
  <dbl> <dbl> <list> <dbl>
1     5     2 <fn>      27
2     6    11 <fn>     227

这是因为你应该映射而​​不是变异。 Mutate 调用该函数一次,并将整个列作为参数提供。

第二个问题是test_frame$func[1]不是一个函数,而是一个只有一个元素的列表。您不能有 "function" 列,只能列出列。

试试这个:

test_frame$result <- with(test_frame, 
          map_dbl(1:2, ~ func_then_add(arg_1[.], arg_2[.], func[[.]])))

结果:

# A tibble: 2 x 4
  arg_1 arg_2 func   result
  <dbl> <dbl> <list>  <dbl>
1     5     2 <fn>       27
2     6    11 <fn>      227

编辑:使用 dplyr、mutate 和 rowwise 的更简单的解决方案:

test_frame %>% rowwise %>% mutate(res=func_then_add(arg_1, arg_2, func))

坦率地说,我对最后一个有点困惑。为什么是 func 而不是 func[[1]]func 应该是一个列表,而不是函数。 mutaterowwise 在这里做了一些险恶的事情,比如自动将列表转换为向量。

编辑2:实际上,rowwise手册中明确写了:

Its main impact is to allow you to work with list-variables in ‘summarise()’ and ‘mutate()’ without having to use ‘[[1]]’.

最终编辑: 我最近对 ​​tidyverse 如此着迷,以至于我没有想到最简单的选择——使用 base R:

apply(test_frame, 1, function(x) func_then_add(x$arg_1, x$arg_2, x$func))