使用不同的参数在数据框中每行应用/映射不同的功能

时间:2018-07-13 17:01:37

标签: r dplyr purrr

对于您来说,我有一个简单的问题,purrr专家在那里躲避了我一段时间以来的最佳搜索努力。首先,让我们看一下我要使用的嵌套列表数据结构。

加载程序包

#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]>

预先感谢您提供的解决我的问题的帮助!

P.S。我查看了以下资源,但尚未找到答案:

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

2 个答案:

答案 0 :(得分:5)

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-07-13创建。

答案 1 :(得分:1)

我们可以使用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]>