How to select columns when using pmap inside of mutate for rowwise operation

purrr

#1

I have some data where I'd like to work rowwise and calculate the value of a new column by applying a function to a subset of the columns in my data frame. I understand that I can pass the unquoted names of the columns I want to operate on to pmap(), but in my case I have a large number of columns and it would be quite cumbersome to type them all out.

So, I'm trying to figure out if there is a way to pass a character vector of the column names (that I have previously created) to pmap, but I can't quite get it to work. Here is a toy example that illustrates where I'm getting stuck:

library(tidyverse)
df <- tribble(
  ~a, ~b, ~c,
  1, 2, 3,
  4, 5, 6
)

sum_cols <- c("a", "b")

df %>% mutate(total = pmap_dbl(list(a, b), sum))
#> # A tibble: 2 x 4
#>       a     b     c total
#>   <dbl> <dbl> <dbl> <dbl>
#> 1     1     2     3     3
#> 2     4     5     6     9

df %>% mutate(total = pmap_dbl(list(sum_cols), sum))
#> Error in .Primitive("sum")(..., na.rm = na.rm): invalid 'type' (character) of argument

df %>% mutate(total = pmap_dbl(list(rlang::parse_exprs(sum_cols)), sum))
#> Error in .Primitive("sum")(..., na.rm = na.rm): invalid 'type' (symbol) of argument

Created on 2019-02-04 by the reprex package (v0.2.1)


#2

When in doubt - bang bang (bang):

library(tidyverse)
df <- tribble(
  ~a, ~b, ~c,
  1, 2, 3,
  4, 5, 6
)

sum_cols <- c("a", "b")

desired <- df %>% mutate(total = pmap_dbl(list(a, b), sum))

res <- df %>% mutate(total = pmap_dbl(list(!!!rlang::parse_exprs(sum_cols)), sum))

dplyr::all_equal(desired, res)
#> [1] TRUE

Created on 2019-02-05 by the reprex package (v0.2.1)


#3

Ahh!!! Thank you, @mishabalyasin. I'm still very slow to understand tidyeval and correct parsing of expressions/quosures. Could you give a simple explanation in words what the !!!rlang::parse_exprs(x) construction is doing in this case?


#4

I can probably only explain it in words, so that's good that that is what you want :slight_smile:

The way I think about it is that I look at what you want (in your case, list(a, b)) and think how this can be achieved with tidyeval. One thing that !!! does is that it splices arguments from a list into the call, so something like !!!rlang::parse_exprs(x) becomes a, b that you then use in a list and it produces exactly what you need (list(a, b)).


closed #5

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.