在 data.frame 上使用 invoke_map() 或 exec()
Using invoke_map() or exec() on a data.frame
我有一个数据框,其中不同的行需要不同的评估来计算结果。这些评估中的每一个都在一个函数中实现,并且要使用的相应函数在数据框中的一列中指定。这是一个最小的例子:
f1 = function(a,...){return(2*a)}
f2 = function(a,b,...){return(a+b)}
df = data.frame(a=1:4,b=5:8,f=c('f1','f2','f2','f1'))
#Expected result:
a b f result
1 1 5 f1 2
2 2 6 f2 8
3 3 7 f2 10
4 4 8 f1 8
使用 pmap
,我可以将一个函数应用于数据帧的每一行,我还阅读了有关 exec()
替换 invoke_map()
的内容,但是 none我尝试将两者结合起来似乎有效,因为 exec()
似乎只适用于列表:
df$result = purrr::pmap(df,df$f)
df$result = purrr::pmap(df$f,exec,df)
...
有没有比过滤每个函数的数据帧更优雅的方法,在每个过滤的数据帧上使用 pmap,然后将所有内容重新绑定在一起?
提前致谢!
编辑:我应该提到我的数据框有很多列,并且函数不需要相同的参数(例如,有些可能会跳过 ´´´a´´´,但需要 ´´´b´ ´´).因此我需要一种不需要显式传递参数的方法。
在行上使用 lapply()
,使用 do.call()
df$result = lapply(1:nrow(df), \(i) {
do.call(df[i,"f"],as.list(subset(df[i,],select=-f)))
})
输出:
a b f result
<int> <int> <chr> <dbl>
1 1 5 f1 2
2 2 6 f2 8
3 3 7 f2 10
4 4 8 f1 8
您可以使用 exec() 和 pmap() 执行此操作
f1 = function(a,...){return(2*a)}
f2 = function(a,b,...){return(a+b)}
df = data.frame(a= 1:4, b = 5:8, f = c('f1',' f2', 'f2', 'f1'))
require(purrr)
require(dplyr)
df |> mutate(result = pmap(list(f, a, b), exec))
#> a b f result
#> 1 1 5 f1 2
#> 2 2 6 f2 8
#> 3 3 7 f2 10
#> 4 4 8 f1 8
由 reprex package (v2.0.1)
创建于 2022-05-27
PS。您可能会遇到错误,因为您将命名参数传递给 exec()
。当你 pmap(list(f = "f1", a = 1, b = 1), exec)
时,所有命名参数都传递给 exec(.fn, ...)
中的 ...
,因为列表元素的 none 被命名为 .fun
.
在上面的例子中,传递的列表元素没有它们的名字,因此第一个参数被假定(exec()
)为.fun
。
所以你可以使用你建议的方法结合base::unname()
:
df |> relocate(f) |> unname() |> pmap(exec)
# [[1]]
# [1] 2
#
# [[2]]
# [1] 8
#
# [[3]]
# [1] 10
#
# [[4]]
# [1] 8
而没有 unname()
你会得到错误:
df |> relocate(f) |> pmap(exec)
# Error in .f(f = .l[[1L]][[i]], a = .l[[2L]][[i]], b = .l[[3L]][[i]], ...):
# argument ".fn" is missing, with no default
或者,您可以将 df$f
重命名为 df$.fn
并传递整个 data.frame:
df |> rename(.fn = "f") |> pmap(exec)
# [[1]]
# [1] 2
#
# [[2]]
# [1] 8
#
# [[3]]
# [1] 10
#
# [[4]]
# [1] 8
我有一个数据框,其中不同的行需要不同的评估来计算结果。这些评估中的每一个都在一个函数中实现,并且要使用的相应函数在数据框中的一列中指定。这是一个最小的例子:
f1 = function(a,...){return(2*a)}
f2 = function(a,b,...){return(a+b)}
df = data.frame(a=1:4,b=5:8,f=c('f1','f2','f2','f1'))
#Expected result:
a b f result
1 1 5 f1 2
2 2 6 f2 8
3 3 7 f2 10
4 4 8 f1 8
使用 pmap
,我可以将一个函数应用于数据帧的每一行,我还阅读了有关 exec()
替换 invoke_map()
的内容,但是 none我尝试将两者结合起来似乎有效,因为 exec()
似乎只适用于列表:
df$result = purrr::pmap(df,df$f)
df$result = purrr::pmap(df$f,exec,df)
...
有没有比过滤每个函数的数据帧更优雅的方法,在每个过滤的数据帧上使用 pmap,然后将所有内容重新绑定在一起?
提前致谢!
编辑:我应该提到我的数据框有很多列,并且函数不需要相同的参数(例如,有些可能会跳过 ´´´a´´´,但需要 ´´´b´ ´´).因此我需要一种不需要显式传递参数的方法。
在行上使用 lapply()
,使用 do.call()
df$result = lapply(1:nrow(df), \(i) {
do.call(df[i,"f"],as.list(subset(df[i,],select=-f)))
})
输出:
a b f result
<int> <int> <chr> <dbl>
1 1 5 f1 2
2 2 6 f2 8
3 3 7 f2 10
4 4 8 f1 8
您可以使用 exec() 和 pmap() 执行此操作
f1 = function(a,...){return(2*a)}
f2 = function(a,b,...){return(a+b)}
df = data.frame(a= 1:4, b = 5:8, f = c('f1',' f2', 'f2', 'f1'))
require(purrr)
require(dplyr)
df |> mutate(result = pmap(list(f, a, b), exec))
#> a b f result
#> 1 1 5 f1 2
#> 2 2 6 f2 8
#> 3 3 7 f2 10
#> 4 4 8 f1 8
由 reprex package (v2.0.1)
创建于 2022-05-27PS。您可能会遇到错误,因为您将命名参数传递给 exec()
。当你 pmap(list(f = "f1", a = 1, b = 1), exec)
时,所有命名参数都传递给 exec(.fn, ...)
中的 ...
,因为列表元素的 none 被命名为 .fun
.
在上面的例子中,传递的列表元素没有它们的名字,因此第一个参数被假定(exec()
)为.fun
。
所以你可以使用你建议的方法结合base::unname()
:
df |> relocate(f) |> unname() |> pmap(exec)
# [[1]]
# [1] 2
#
# [[2]]
# [1] 8
#
# [[3]]
# [1] 10
#
# [[4]]
# [1] 8
而没有 unname()
你会得到错误:
df |> relocate(f) |> pmap(exec)
# Error in .f(f = .l[[1L]][[i]], a = .l[[2L]][[i]], b = .l[[3L]][[i]], ...):
# argument ".fn" is missing, with no default
或者,您可以将 df$f
重命名为 df$.fn
并传递整个 data.frame:
df |> rename(.fn = "f") |> pmap(exec)
# [[1]]
# [1] 2
#
# [[2]]
# [1] 8
#
# [[3]]
# [1] 10
#
# [[4]]
# [1] 8