在mutate中使用purrr :: pmap创建list-column

时间:2017-10-02 18:34:19

标签: r dplyr purrr

我理解如何使用map迭代df中的参数并创建新的列表列。

例如,

params <- expand.grid(param_a = c(2, 4, 6)
                  ,param_b = c(3, 6, 9)
                  ,param_c = c(50, 100)
                  ,param_d = c(1, 0)
                  )

df.preprocessed <- dplyr::as.tbl(params) %>%
  dplyr::mutate(test_var = purrr::map(param_a, function(x){
      rep(5, x)
      }
    ))

但是,如果我想指定2个以上的参数,如何在pmap中使用类似的语法?

df.preprocessed <- dplyr::as.tbl(params) %>%
  dplyr::mutate(test_var = purrr::pmap(list(x = param_a
                                     ,y = param_b
                                     ,z = param_c
                                     ,u = param_d), function(x, y){
                                        rep(5,x)*y
                                     }
  )
  )

错误输出:

  

mutate_impl(.data,dots)中的错误:     评估错误:未使用的参数(z = .l [[c(3,i)]],u = .l [[c(4,i)]])。

4 个答案:

答案 0 :(得分:9)

使用pmap时,第一个参数是一个列表,因此您可以直接将数据框传递给它,然后在函数中使用与数据框中列相同的名称命名参数。您需要unnest()来解包pmap()返回的列表元素:

df.preprocessed <- dplyr::as.tbl(params) %>%
    dplyr::mutate(test_var = purrr::pmap(., function(param_a, param_b, ...){
                                        rep(5, param_a) * param_b
                                     })) %>%
    tidyr::unnest()


> df.preprocessed
# A tibble: 144 x 5
   param_a param_b param_c param_d test_var
     <dbl>   <dbl>   <dbl>   <dbl>    <dbl>
 1       2       3      50       1       15
 2       2       3      50       1       15
 3       4       3      50       1       15
 4       4       3      50       1       15
 5       4       3      50       1       15
 6       4       3      50       1       15
 7       6       3      50       1       15
 8       6       3      50       1       15
 9       6       3      50       1       15
10       6       3      50       1       15
# ... with 134 more rows

答案 1 :(得分:2)

我们可以试试

f1 <- function(x, y, ...) rep(5, x)*y

df.preprocessed <- dplyr::as.tbl(params) %>%
        dplyr::mutate(test_var = purrr::pmap(list(x = param_a
                                 ,y = param_b
                                 ,z = param_c
                                 ,u = param_d),f1
    )
   )
df.preprocessed
# A tibble: 36 x 5
#   param_a param_b param_c param_d  test_var
#     <dbl>   <dbl>   <dbl>   <dbl>    <list>
# 1       2       3      50       1 <dbl [2]>
# 2       4       3      50       1 <dbl [4]>
# 3       6       3      50       1 <dbl [6]>
# 4       2       6      50       1 <dbl [2]>
# 5       4       6      50       1 <dbl [4]>
# 6       6       6      50       1 <dbl [6]>
# 7       2       9      50       1 <dbl [2]>
# 8       4       9      50       1 <dbl [4]>
# 9       6       9      50       1 <dbl [6]>
#10       2       3     100       1 <dbl [2]>
# ... with 26 more rows

答案 2 :(得分:2)

你可以这样做:

df.preprocessed <- dplyr::as.tbl(params) %>%
  dplyr::mutate(test_var = purrr::pmap(list(x = param_a
                                            ,y = param_b
                                            ,z = param_c
                                            ,u = param_d),
                                              ~ rep(5,.x)*.y                                                
  )
  )

df.preprocessed <- dplyr::as.tbl(params) %>%
  dplyr::mutate(test_var = purrr::pmap(list(x = param_a
                                            ,y = param_b
                                            ,z = param_c
                                            ,u = param_d),
                                       ~ rep(5,..1)*..2                                       
  )
  )

第二种方式更为通用,因为您可以使用..3..4等...

答案 3 :(得分:1)

如果没有rowwise直接使用mutatemap

my_fun <- function(param_a, param_b){
  rep(5, param_a) * param_b
}
df.preprocessed <- dplyr::as.tbl(params) %>%
  rowwise() %>% 
  dplyr::mutate(test_var = list(my_fun(param_a, param_b))) %>% 
  tidyr::unnest()