Forward the dots to drop variables from a tibble

Hey there,

I have been trying a few ways to create a custom function that takes a tibble and drops the columns named in the function. I know that for select commands you can pass the dots and select those columns, but how to unselect them?

requires(rlang)
df <- tibble(
  g1 = c(1, 1, 2, 2, 2),
  g2 = c(1, 2, 1, 2, 1),
  a = sample(5),
  b = sample(5)
)
df_output <-
df %>%
select(-g1, -g2)

my_select <- function(df, ...) {
  group_sel <- enquos(...)
  
  df %>%
    select(!!!group_sel)
}

my_select(df, g1, g2)

# Works like a charm

my_second_select <- function(df, ...) {
 df %>% 
    select(...)
}



my_second_select(df, g1, g2)


# Works too

## But for unselecting

my_unselect1 <- function(df, ...) {
  group_sel <- enquos(...)
  
  df %>%
    select(-!!!group_sel)

}

my_unselect1(df, g1,g2)

#NOPE

my_unselect2 <- function(df, ...) {
 
  df %>%
    select(-...)
  
}

my_unselect2(df, g1,g2)

# NOPE


my_unselect3 <- function(df, ...) {
  sel <- tidyselect::vars_select(tbl_vars(.data), ...)
 
  df %>%
    select(-!!!sel)
}

my_unselect3(df, g1,g2)
#NOPE

Any clues on how to do this? It seems like it should be super easy, but I can't get my head around it

I'm not sure if this is the tidyverse-approved approach, but...

In the code below, we capture the names of the columns to remove and convert them to strings with rlang::as_label(). Now we can use select_at with setdiff to keep all columns except the ones provided to the function.

my_unselect <- function(df, ...) {
  
  cols_to_remove = map_chr(enquos(...), as_label)
  
  message("\nRemoving columns ", paste(cols_to_remove, collapse=", "), "\n")
  
  df %>%
    select_at(setdiff(names(.), cols_to_remove))
}

my_unselect(df, g1, g2)

Removing columns g1, g2

# A tibble: 5 x 2
      a     b
  <int> <int>
1     1     5
2     4     4
3     2     3
4     5     1
5     3     2
2 Likes

Great solution ! Know that you can use ensyms to prevent the map_chr

library(tidyverse)
df <- tibble(
  g1 = c(1, 1, 2, 2, 2),
  g2 = c(1, 2, 1, 2, 1),
  a = sample(5),
  b = sample(5)
)

my_unselect <- function(df, ...) {
  cols_to_remove = ensyms(...)
  message("\nRemoving columns ", paste(cols_to_remove, collapse=", "), "\n")
  df %>%
    # select_at(setdiff(names(.), cols_to_remove))
    select_at(setdiff(names(.), cols_to_remove))
}

my_unselect(df, g1, g2)
#> 
#> Removing columns g1, g2
#> # A tibble: 5 x 2
#>       a     b
#>   <int> <int>
#> 1     5     3
#> 2     4     1
#> 3     1     5
#> 4     3     2
#> 5     2     4

Created on 2019-05-14 by the reprex package (v0.2.1.9000)

2 Likes

Thanks joels and Christophe!

1 Like

If your question's been answered, would you mind choosing a solution? It helps other people see which questions still need help, or find solutions if they have similar problems. Here’s how to do it:

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