【问题标题】:apply/map a different function per row in a data frame with varying parameters在具有不同参数的数据框中每行应用/映射不同的函数
【发布时间】:2018-12-22 02:40:54
【问题描述】:

我有一个简单的问题要请教各位专家,一段时间以来我一直无法尽最大努力进行谷歌搜索。首先,让我们看一下我正在尝试使用的嵌套列表数据结构。

加载包

#R version 3.4.1    
library(purrr) # version 0.2.4
library(dplyr) # version 0.7.4

定义函数

f1 <- function(a, b, c) {a + b^c}
f2 <- function(x) {x * 2}
f3 <- function(y, z) {y * z}

定义参数集

这些将传递给f1f2f3 中的每一个:

p1 <- data_frame(a = c(2, 4, 5, 7, 8),
                 b = c(1, 1, 2, 2, 2),
                 c = c(.5, 5, 1, 2, 3))
p2 <- data_frame(x = c(1, 4))
p3 <- data_frame(y = c(2, 2, 2, 3),
                 z = c(5, 4, 3, 2))

将它们组合成一个嵌套的数据框

我正在努力将我的数据保持在一个漂亮、整洁的矩形中。 “id”变量是函数名本身(在我的真实数据中,有数百个):

df <- data_frame(fun_id = c('f1', 'f2', 'f3'), 
                 params = list(p1, p2, p3), 
                 funs = list(f1, f2, f3))

检查结构会显示paramsfuns 的列表列:

print(df)

# A tibble: 3 x 3
  fun_id           params   funs
   <chr>           <list> <list>
1     f1 <tibble [5 x 3]>  <fun>
2     f2 <tibble [2 x 1]>  <fun>
3     f3 <tibble [4 x 2]>  <fun>

我的问题

使用purrr 函数和dplyr::mutate,我如何在df 中获得一个名为results 的新列表列,其中每个元素都是一个列表,其中包含执行funs 中的函数的输出以行方式从params 获取参数?

我可以让pmap 为一个简单的案例做我想做的事:

> pmap(.l = p1, .f = f1)

[[1]]
[1] 3

[[2]]
[1] 5

[[3]]
[1] 7

[[4]]
[1] 11

[[5]]
[1] 16

但我真的很想在数据框中执行此操作以保持一切正常。以下内容让我找到了正确的结构(一个带有结果列表列的数据框),但仅适用于一行并且没有概括:

> df %>% 
  slice(1) %>% 
  mutate(results = list(pmap(.l = params[[1]], .f = funs[[1]])))

# A tibble: 1 x 4
  fun_id           params   funs    results
   <chr>           <list> <list>     <list>
1     f1 <tibble [5 x 3]>  <fun> <list [5]>

提前感谢您帮助解决我的问题!

附:我查看了以下资源,但尚未找到答案:

purrr::pmap with dplyr::mutate

Using purrr::pmap within mutate to create list-column

http://statwonk.com/purrr.html

https://github.com/rstudio/cheatsheets/raw/master/purrr.pdf

https://jennybc.github.io/purrr-tutorial/index.html

【问题讨论】:

    标签: r dplyr purrr


    【解决方案1】:

    purrr 中有一个方便的函数来解决这种情况;将函数列表应用于相应的参数列表!它被称为invoke_map,可以与mutate 一起使用,如下所示。我认为与map2(~pmap()) 相比的主要优势在于,如果有其他参数要提供给params 中未包含的任何函数,您可以将它们作为命名参数添加到... 中,而无需修改params

    library(tidyverse)
    f1 <- function(a, b, c) {a + b^c}
    f2 <- function(x) {x * 2}
    f3 <- function(y, z) {y * z}
    p1 <- data_frame(
      a = c(2, 4, 5, 7, 8),
      b = c(1, 1, 2, 2, 2),
      c = c(.5, 5, 1, 2, 3)
    )
    p2 <- data_frame(x = c(1, 4))
    p3 <- data_frame(
      y = c(2, 2, 2, 3),
      z = c(5, 4, 3, 2)
    )
    df <- data_frame(
      fun_id = c("f1", "f2", "f3"),
      params = list(p1, p2, p3),
      funs = list(f1, f2, f3)
    )
    
    df2 <- df %>%
      mutate(results = invoke_map(.f = funs, .x = params))
    df2
    #> # A tibble: 3 x 4
    #>   fun_id params           funs   results  
    #>   <chr>  <list>           <list> <list>   
    #> 1 f1     <tibble [5 x 3]> <fn>   <dbl [5]>
    #> 2 f2     <tibble [2 x 1]> <fn>   <dbl [2]>
    #> 3 f3     <tibble [4 x 2]> <fn>   <dbl [4]>
    df2$results
    #> [[1]]
    #> [1]  3  5  7 11 16
    #> 
    #> [[2]]
    #> [1] 2 8
    #> 
    #> [[3]]
    #> [1] 10  8  6  6
    

    reprex package (v0.2.0) 于 2018 年 7 月 13 日创建。

    【讨论】:

    • 下次我需要用 purrr“调用”一个函数时,我会记住 invoke_map 方法。谢谢! :)
    【解决方案2】:

    我们可以使用map2 并为每一行应用pmap 函数。

    df2 <- df %>%
      mutate(result = map2(params, funs, ~pmap(.l = .x, .f = .y)))
    df2
    # # A tibble: 3 x 4
    #   fun_id params           funs   result    
    #   <chr>  <list>           <list> <list>    
    # 1 f1     <tibble [5 x 3]> <fn>   <list [5]>
    # 2 f2     <tibble [2 x 1]> <fn>   <list [2]>
    # 3 f3     <tibble [4 x 2]> <fn>   <list [4]>
    

    【讨论】:

    • 感谢您的解决方案!它确实解决了问题(并且是第一个),但我喜欢 Calum 提供的 invoke_map 解决方案的简单性和专用性。
    • @vergilcw 我同意 Calum 的回答对此更好。
    猜你喜欢
    • 2020-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-14
    • 2017-01-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多