代码之家  ›  专栏  ›  技术社区  ›  ngm

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

  •  4
  • ngm  · 技术社区  · 8 年前

    此数据框包含我称之为“数据”的内容:

    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))
    

    这是一个数据帧,我打算用作函数查找表之类的东西。 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 行获取 功能和任何 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
    

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

    2 回复  |  直到 8 年前
        1
  •  3
  •   Axeman    8 年前

    “如果将f2中的函数重新定义为两个变量的显式函数会使事情变得更容易,那也没关系。”

    是的,我认为这是一种更自然的情况。否则,数据将按行存储,可能需要重新格式化。

    重新定义功能:

    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()
    

    这给出了相同的结果。

        2
  •  2
  •   akrun    8 年前

    我们可以使用 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的帖子中的内容相同。