在 data.frame 上使用 invoke_map() 或 exec()

问题描述 投票:0回答:2

我有一个数据框,其中不同的行需要不同的评估来计算结果。这些评估中的每一个都在函数中实现,并且要使用的相应函数在数据帧的列中指定。这是一个最小的例子:

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()
的内容,但我将两者结合起来的尝试似乎都不起作用,因为
exec()
似乎只是使用列表:

df$result = purrr::pmap(df,df$f)
df$result = purrr::pmap(df$f,exec,df)
...

有没有比过滤每个函数的数据帧、在每个过滤的数据帧上使用 pmap 然后将所有内容绑定在一起更优雅的方法?

提前谢谢您!

编辑:我应该提到我的数据框有很多列,并且函数不需要相同的参数(例如,有些可能会跳过 ´´´a´´´,但需要 ´´´b´´´)。因此,我需要一种不需要显式传递参数的方法。

r purrr
2个回答
4
投票

您可以使用 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 包于 2022 年 5 月 27 日创建(v2.0.1)


PS。您可能会收到错误,因为您将命名参数传递给

exec()
。当您
pmap(list(f = "f1", a = 1, b = 1), exec)
时,所有命名参数都会传递给
...
中的
exec(.fn, ...)
,因为没有任何列表元素被命名为
.fn

在上面的示例中,列表元素在没有名称的情况下传递,因此第一个参数(通过

exec()
)被假定为
.fn

所以你可以结合使用你建议的方法

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

1
投票

在行上使用

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
© www.soinside.com 2019 - 2024. All rights reserved.