从函数返回形状不同的数据帧/小滴并使用pmap收集它们

时间:2019-07-16 15:38:00

标签: r purrr

我有一个复杂的函数,由于一些参数化的计算结果,该函数返回多个小标题(或数据帧)。这些小节的形状不同,所以我不能只返回一个小节。

我希望能够为每个参数组合访问不同的结果类型,因此我创建了参数组合并使用pmap_dfr映射它们以获取结果。这在某种程度上可行,但是通过这种方式,在我的结果中,无法确定我正在查看哪种结果:

library(tidyverse)

foo <- function(.param1, .param2) {
  return(tibble(
    .param1 = .param1,
    .param2 = .param2,
    data = list(
      ret1 = tibble(ret1_col1 = c(1, 2, 3), ret1_col2 = c(1, 2, 3)),
      ret2 = tibble(ret2_col1 = c(1, 2, 3, 4, 5)),
      ret3 = tibble(ret3_col1 = c(1, 2), ret3_col2 = c(1, 2), ret3_col3 = c(1, 2))
    )
  ))
}

tibble::tribble(
  ~.param1, ~.param2,
  1, 2,
  3, 4
) %>% 
  pmap_dfr(foo)

#> # A tibble: 6 x 3
#>   .param1 .param2 data            
#>     <dbl>   <dbl> <list>          
#> 1       1       2 <tibble [3 × 2]>
#> 2       1       2 <tibble [5 × 1]>
#> 3       1       2 <tibble [2 × 3]>
#> 4       3       4 <tibble [3 × 2]>
#> 5       3       4 <tibble [5 × 1]>
#> 6       3       4 <tibble [2 × 3]>

reprex package(v0.3.0)于2019-07-16创建

例如,对于第一行,这指的是<tibble>

理想情况下,我会得到以下结果:

  .param1 .param2             ret1             ret2             ret3
    <dbl>   <dbl>           <list>           <list>           <list>
1       1       2 <tibble [3 × 2]> <tibble [5 × 1]> <tibble [2 × 3]>
2       3       4 <tibble [3 × 2]> <tibble [5 × 1]> <tibble [2 × 3]>

我该如何实现?

2 个答案:

答案 0 :(得分:1)

如果我的理解正确,则可以对函数做一些小的修改,以标记出要创建的数据框。一种方法是仅创建一个其值具有与数据帧匹配的名称的列,即ret1ret2

library(tidyverse)

foo <- function(.param1, .param2) {
  dfs <- c("ret1", "ret2", "ret3") # added here
  return(tibble(
    .param1 = .param1,
    .param2 = .param2,
    col = dfs,                     # added here
    data = list(
      tibble(ret1_col1 = c(1, 2, 3), ret1_col2 = c(1, 2, 3)),
      tibble(ret2_col1 = c(1, 2, 3, 4, 5)),
      tibble(ret3_col1 = c(1, 2), ret3_col2 = c(1, 2), ret3_col3 = c(1, 2))
    ) %>%
      setNames(dfs)
  ))
}

然后,您可以像在其他任何列上一样在该列表列上使用spread

tibble::tribble(
  ~.param1, ~.param2,
  1, 2,
  3, 4
) %>% 
  pmap_dfr(foo) %>%
  spread(key = col, value = data)
#> # A tibble: 2 x 5
#>   .param1 .param2 ret1             ret2             ret3            
#>     <dbl>   <dbl> <list>           <list>           <list>          
#> 1       1       2 <tibble [3 × 2]> <tibble [5 × 1]> <tibble [2 × 3]>
#> 2       3       4 <tibble [3 × 2]> <tibble [5 × 1]> <tibble [2 × 3]>

答案 1 :(得分:0)

一种解决方案是不返回小标题列表,而是返回列表中的每个小标题:

return(tibble(
    .param1 = .param1,
    .param2 = .param2,
    ret1 = list(tibble(ret1_col1 = c(1, 2, 3), ret1_col2 = c(1, 2, 3))),
    ret2 = list(tibble(ret2_col1 = c(1, 2, 3, 4, 5))),
    ret3 = list(tibble(ret3_col1 = c(1, 2), ret3_col2 = c(1, 2), ret3_col3 = c(1, 2)))
))

这样,pmap_dfr可以正确收集结果。

完整示例:

library(tidyverse)

foo <- function(.param1, .param2) {
  return(tibble(
    .param1 = .param1,
    .param2 = .param2,
    ret1 = list(tibble(ret1_col1 = c(1, 2, 3), ret1_col2 = c(1, 2, 3))),
    ret2 = list(tibble(ret2_col1 = c(1, 2, 3, 4, 5))),
    ret3 = list(tibble(ret3_col1 = c(1, 2), ret3_col2 = c(1, 2), ret3_col3 = c(1, 2)))
  ))
}

tibble::tribble(
  ~.param1, ~.param2,
  1, 2,
  3, 4
) %>% 
  pmap_dfr(foo) %>% unnest(ret1)
#> # A tibble: 6 x 4
#>   .param1 .param2 ret1_col1 ret1_col2
#>     <dbl>   <dbl>     <dbl>     <dbl>
#> 1       1       2         1         1
#> 2       1       2         2         2
#> 3       1       2         3         3
#> 4       3       4         1         1
#> 5       3       4         2         2
#> 6       3       4         3         3

reprex package(v0.3.0)于2019-07-16创建