vitallish vitallish - 1 year ago 138
R Question

Use Negation with Select in dplyr 0.7.x

I'm trying to write a function that needs to exclude a user passed variable from the resultant data frame. I'm also taking this opportunity to learn a bit more about the new dplyr syntax.

The function acts like a cross join for data frames. I want to use it as a clean way of duplicating data across parameters of a function.

The function works as follows:

crossjoin_df <- function(df1, df2, temp_col = ".k") {
df1 <- df1 %>%
mutate(!!temp_col := 1)

df2 <- df2 %>%
mutate(!!temp_col := 1)

out <- left_join(df1, df2, by = temp_col)

# I'm trying to replace the next line
out[,!names(out)==temp_col]
}

params <- data.frame(k = c(11,10),
n = c(27,26))

data <- data.frame(a = 1:3,
b = 4:6)

crossjoin_df(params, data) # 6 row data set


I want to see if it's possible to replace the last statement with a piped select statement. However, the negation does not seem to be working.

I am able to get something like:

out %>% select(!!temp_col)


to work, but that obviously only selects
.k
. I am not able to get anything like:

out %>% select(-!!temp_col)


to work.

Answer Source

You'll need rlang, the backend package for dplyr that enables tidy eval, whether you want to keep using strings, in which case you'll need sym to turn a string into a quosure:

library(dplyr)

params <- data.frame(k = c(11,10),
                     n = c(27,26))

data <- data.frame(a = 1:3,
                   b = 4:6)

crossjoin_df <- function(df1, df2, temp_col = ".k") {
    df1 <- df1 %>% mutate(!!temp_col :=  1)

    df2 <- df2 %>% mutate(!!temp_col :=  1)

    left_join(df1, df2, by = temp_col) %>% 
        select(-!!rlang::sym(temp_col))
}

crossjoin_df(params, data)
#>    k  n a b
#> 1 11 27 1 4
#> 2 11 27 2 5
#> 3 11 27 3 6
#> 4 10 26 1 4
#> 5 10 26 2 5
#> 6 10 26 3 6

...or switch to full tidy eval, in which case you'll need quo_name to turn a quosure into a name:

crossjoin_df <- function(df1, df2, temp_col = .k) {
    temp_col <- enquo(temp_col)

    df1 <- df1 %>% mutate(!!rlang::quo_name(temp_col) :=  1)

    df2 <- df2 %>% mutate(!!rlang::quo_name(temp_col) :=  1)

    left_join(df1, df2, by = rlang::quo_name(temp_col)) %>% 
        select(-!!temp_col)
}

crossjoin_df(params, data)
#>    k  n a b
#> 1 11 27 1 4
#> 2 11 27 2 5
#> 3 11 27 3 6
#> 4 10 26 1 4
#> 5 10 26 2 5
#> 6 10 26 3 6

Alternatively, just use tidyr::crossing:

tidyr::crossing(params, data)
#>    k  n a b
#> 1 11 27 1 4
#> 2 11 27 2 5
#> 3 11 27 3 6
#> 4 10 26 1 4
#> 5 10 26 2 5
#> 6 10 26 3 6
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download