Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dplyr: deselecting columns given by

Tags:

r

dplyr

tidyverse

How can I deselect columns given in the ... argument of a self written function. (I also need to select the columns at another point, so just specifying the columns with - in ... does not solve my problem.)

Any soltions are apreciated, select-helpers, manipulating quosures or expressions, ...

# very simple example data
test <- data.frame(a=1:3, b=1:3, c=1:3)

# function skeleton
testfun <- function(x, ...){
  y <- select(x, ...)
  z <- select(x, -...) # does of course not work like this
  return(list(y, z))   # just as an example
}

# calling the function to select different columns
testfun(test, a)
testfun(test, a, b)
like image 850
snaut Avatar asked Oct 19 '17 10:10

snaut


People also ask

How do I deselect a column by name in R?

You can also drop or deselect columns by prepending the character vector of column names with the - or ! operators. For e.g., dt[, -c("col1", "col2")] or dt[, !

How do I drop certain columns in R?

The most easiest way to drop columns is by using subset() function. In the code below, we are telling R to drop variables x and z. The '-' sign indicates dropping variables. Make sure the variable names would NOT be specified in quotes when using subset() function.

How do I delete multiple columns in R?

We can delete multiple columns in the R dataframe by assigning null values through the list() function.


Video Answer


3 Answers

These easiest solution would be to select the positive columns, and then compare names to figure out which columns to drop, as in this answer.

To work on the dots directly,

  1. We will capture them in a list of quosures (quos).
  2. Unquote and splice the dots in with UQS for the positive selection.
  3. Do the same thing inside of c() so that we have a vector of selection.
  4. Negate that vector to do the negative selection.

This is the transformation described by (3) and (4).

library(dplyr)
dots <- quos(a, b)
quos(-c(UQS(dots)))
#> [[1]]
#> <quosure: frame>
#> ~-c(~a, ~b)
#> 
#> attr(,"class")
#> [1] "quosures"

The full solution then would be

test <- data.frame(a = 1:3, b = 1:3, c = 1:3)

# function skeleton
testfun <- function(x, ...) {
  dots <- quos(...)
  y <- select(x, UQS(dots))
  z <- select(x, -c(UQS(dots)))
  return(list(y, z))   
}

testfun(test, a)
#> [[1]]
#>   a
#> 1 1
#> 2 2
#> 3 3
#> 
#> [[2]]
#>   b c
#> 1 1 1
#> 2 2 2
#> 3 3 3

testfun(test, a, b)
#> [[1]]
#>   a b
#> 1 1 1
#> 2 2 2
#> 3 3 3
#> 
#> [[2]]
#>   c
#> 1 1
#> 2 2
#> 3 3

Test on selection helpers.

testfun(test, starts_with("b"), one_of("c"))
#> [[1]]
#>   b c
#> 1 1 1
#> 2 2 2
#> 3 3 3
#> 
#> [[2]]
#>   a
#> 1 1
#> 2 2
#> 3 3
like image 123
TJ Mahr Avatar answered Oct 24 '22 03:10

TJ Mahr


You can use this trick with purrr::modify_at

library(purrr)
testfun <- function(x, ...){
  y <- select(x, ...)
  z <- modify_at(x,c(...),~NULL)
  return(list(y, z))   # just as an example
}

testfun(test,"a")
# [[1]]
#   a
# 1 1
# 2 2
# 3 3
# 
# [[2]]
#   b c
# 1 1 1
# 2 2 2
# 3 3 3
like image 2
Moody_Mudskipper Avatar answered Oct 24 '22 04:10

Moody_Mudskipper


What about that one?

testfun <- function(x, ...){
  y <- select(x, ...)
  z <- x[, !names(x) %in% names(y)]
  return(list(y, z))
}
like image 1
Tino Avatar answered Oct 24 '22 05:10

Tino