将具有多变量函数列表变量的数据框应用于具有函数参数的数据框

Apply data frame with list-variable of multivariable functions to a data frame with function arguments

这个数据框包含我称之为 "data":

library(tidyverse)
df_d <- data_frame(key = c("cat", "cat", "dog", "dog"), 
               value_1 = c(1,2,3,4), 
               value_2 = c(2,4,6,8))

这是一个数据框,我打算将其用作函数查找之类的东西 table。 f是单变量函数,f2是多变量函数:

df_f <- data_frame(key = c("cat", "dog"),
               f = c(function(x) x^2, function(x) sqrt(x)),
               f2 = c(function(x) (x[1]+x[2])^2, function(x) sqrt(x[1]+x[2])))

我可以轻松制作数据框,以便任何 cat 行获得 cat 函数,任何 dog 行获得 dog 函数:

df_both <- left_join(df_d, df_f)

我能够弄清楚如何将每个 f 函数应用到 value_1 列以获得:

df_both %>% mutate(result = invoke_map_dbl(f, value_1))        
#> # A tibble: 4 x 6
#>   key   value_1 value_2 f      f2     result
#>   <chr>   <dbl>   <dbl> <list> <list>  <dbl>
#> 1 cat      1.00    2.00 <fn>   <fn>     1.00
#> 2 cat      2.00    4.00 <fn>   <fn>     4.00
#> 3 dog      3.00    6.00 <fn>   <fn>     1.73
#> 4 dog      4.00    8.00 <fn>   <fn>     2.00

我的问题是:如何创建一个列 result2,它接受 f2 中的每个函数并将其用作其输入 c(value_1, value_2)。如果将 f2 中的函数重新定义为两个变量的显式函数使事情变得容易得多,那也很好。

期望的输出:

#> # A tibble: 4 x 7
#>   key   value_1 value_2 f      f2     result result2
#>   <chr>   <dbl>   <dbl> <list> <list>  <dbl>   <dbl>
#> 1 cat      1.00    2.00 <fn>   <fn>     1.00    9.00
#> 2 cat      2.00    4.00 <fn>   <fn>     4.00   36.0 
#> 3 dog      3.00    6.00 <fn>   <fn>     1.73    3.00
#> 4 dog      4.00    8.00 <fn>   <fn>     2.00    3.46

(问题由今天早些时候的一个不幸的自我删除问题引起。)

我们可以使用 pmap

df_both %>% 
   mutate(result = invoke_map_dbl(f, value_1), 
          result2 = pmap_dbl(.[c('value_1', 'value_2', 'f2')],  ~(..3)(c(..1, ..2))))
# A tibble: 4 x 7
#   key   value_1 value_2 f      f2     result result2
#   <chr>   <dbl>   <dbl> <list> <list>  <dbl>   <dbl>
#1 cat      1.00    2.00 <fun>  <fun>    1.00    9.00
#2 cat      2.00    4.00 <fun>  <fun>    4.00   36.0 
#3 dog      3.00    6.00 <fun>  <fun>    1.73    3.00
#4 dog      4.00    8.00 <fun>  <fun>    2.00    3.46

在这里,我们不更改 OP 的功能。它与 OP 中的 post.

相同

"If re-defining the functions in f2 to be explicitly functions of two variables makes things much easier, that's fine too."

是的,我认为这是更自然的情况。否则数据按行存储,并且可能会被重塑。

重新定义函数:

df_f <- data_frame(key = c("cat", "dog"),
                   f = c(function(x) x^2, function(x) sqrt(x)),
                   f2 = c(function(x, y) (x + y)^2, function(x, y) sqrt(x + y)))
df_both <- left_join(df_d, df_f)

现在您再次使用 map_invoke,将 .x 作为列表传递,尽管您需要使用 transpose:

将列表翻转过来
mutate(
  df_both,
  result  = invoke_map_dbl(f, value_1),
  result2 = invoke_map_dbl(f2, transpose(list(value_1, value_2)))
)
# A tibble: 4 x 7
  key   value_1 value_2 f      f2     result result2
  <chr>   <dbl>   <dbl> <list> <list>  <dbl>   <dbl>
1 cat        1.      2. <fn>   <fn>     1.00    9.00
2 cat        2.      4. <fn>   <fn>     4.00   36.0 
3 dog        3.      6. <fn>   <fn>     1.73    3.00
4 dog        4.      8. <fn>   <fn>     2.00    3.46

一组三参数函数将简单地扩展为 invoke_map_dbl(f3, transpose(list(value_1, value_2, value_3))

请注意,这种方法在大型数据集上效果不佳,因为您没有使用矢量化。

一个更具可扩展性的替代方案可能涉及嵌套,您至少在每个组中应用一次每个函数:

df_both %>% 
  group_by(key) %>% 
  nest() %>% 
  mutate(data = map(
    data, 
    ~mutate(., result = first(f)(value_1), result2 = first(f2)(value_1, value_2))
    )) %>% 
  unnest()

结果相同。