How to use unite with map2 in R?

91 Views Asked by At

I am trying to use unite() within a map function but cannot get this to work when using the pipe chains. Specifically, I would like to unite 2 sets of 4 columns to yield 2 merged columns, and bind this to the current tibble. Here is an example using toy data.

library(tidyverse)
    df <- tibble(a_col1=sample(letters,10), a_col2=sample(letters,10), b_col1=sample(letters,10), b_col2=sample(letters,10)) %>%
    bind_cols(.,    
    map2(.x = c("merged_a", "merged_b"), .y=c("a_col", "b_col"), ~ unite(select(.data, starts_with(.y)), col=!!.x,  sep = ",", na.rm = TRUE,  remove = TRUE)))

Error in map2(): ℹ In index: 1. Caused by error in UseMethod(): ! no applicable method for 'select' applied to an object of class "rlang_fake_data_pronoun" Run rlang::last_trace() to see where the error occurred.

Doing this outside the pipe seems to work so I think it might be an issue with passing the current tibble through to the unite() function within map2? I have tried using curly braces to try and pass on the tibble to unite() but nothing seems to work!

Update

This seems to work (though I don't fully understand why!)

df <- tibble(a_col1=sample(letters,10), a_col2=sample(letters,10), b_col1=sample(letters,10), b_col2=sample(letters,10)) %>%
bind_cols(.,    
map2(.x = c("merged_a", "merged_b"), .y=c("a_col", "b_col"), \(.x,.y) unite(select(., starts_with(.y)), col=!!.x,  sep = ",", na.rm = TRUE,  remove = TRUE)))
1

There are 1 best solutions below

2
Andy Baxter On

There's a few ways around it but the key thing is to find a way to unambiguously refer to either the dataframe or the columns in a set of nested functions. Perhaps an overall anonymous function would be a clear way of saying where you want the whole dataframe to be referred to and processed before binding the rows:

library(tidyverse)

tibble(
  a_col1 = sample(letters, 10),
  a_col2 = sample(letters, 10),
  b_col1 = sample(letters, 10),
  b_col2 = sample(letters, 10)
) |>
  (\(my_data) {
    bind_cols(my_data,
              map2(
                .x = c("merged_a", "merged_b"),
                .y = c("a_col", "b_col"),
                ~ unite(
                  select(my_data, starts_with(.y)),
                  col = !!.x,
                  sep = ",",
                  na.rm = TRUE,
                  remove = TRUE
                )
              ))
  })()
#> # A tibble: 10 × 6
#>    a_col1 a_col2 b_col1 b_col2 merged_a merged_b
#>    <chr>  <chr>  <chr>  <chr>  <chr>    <chr>   
#>  1 r      l      g      q      r,l      g,q     
#>  2 b      j      u      d      b,j      u,d     
#>  3 c      i      q      c      c,i      q,c     
#>  4 s      w      p      m      s,w      p,m     
#>  5 x      k      f      g      x,k      f,g     
#>  6 a      d      a      l      a,d      a,l     
#>  7 v      e      z      n      v,e      z,n     
#>  8 e      o      k      v      e,o      k,v     
#>  9 g      x      n      e      g,x      n,e     
#> 10 w      a      o      w      w,a      o,w