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)中使用函数,但我 运行 遇到了一些困难。以下是我的问题的一个最小(简单)示例。
假设我有一个接受三个参数的函数:x
和 y
是数字,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
应用到这三列。它应该像以前一样是 27
和 227
。但是当我尝试这个时,我得到一个错误:
> 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
应该是一个列表,而不是函数。 mutate
和 rowwise
在这里做了一些险恶的事情,比如自动将列表转换为向量。
编辑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))
我正在尝试在 R 中的数据帧(tidyverse tibbles)中使用函数,但我 运行 遇到了一些困难。以下是我的问题的一个最小(简单)示例。
假设我有一个接受三个参数的函数:x
和 y
是数字,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
应用到这三列。它应该像以前一样是 27
和 227
。但是当我尝试这个时,我得到一个错误:
> 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
应该是一个列表,而不是函数。 mutate
和 rowwise
在这里做了一些险恶的事情,比如自动将列表转换为向量。
编辑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))