在 dplyr 0.7.x 中对 Select 使用否定

Use Negation with Select in dplyr 0.7.x

我正在尝试编写一个函数,该函数需要从结果数据框中排除用户传递的变量。我也借此机会进一步了解新的 dplyr 语法。

该函数的作用类似于数据框的交叉连接。我想将它用作跨函数参数复制数据的干净方式。

函数的工作原理如下:

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

我想看看是否可以用管道 select 语句替换最后一条语句。但是,否定似乎不起作用。

我可以得到类似的东西:

out %>% select(!!temp_col)

可以工作,但显然只有 selects .k。我无法得到类似的东西:

out %>% select(-!!temp_col)

上班。

可以用one_of,然后用-取反:

out %>% select(-one_of(temp_col))

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

  # `$`(df2, temp_col) <- 1
  df2 <- df2 %>% 
    mutate(!!temp_col :=  1)

  left_join(df1, df2, by = temp_col) %>% select(-one_of(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)

#   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

这也应该有效:

out %>% select_(paste0("-",temp_col))

您将需要 rlang,dplyr 的后端包,可启用整洁的 eval,是否要继续使用字符串,在这种情况下,您将需要 sym 将字符串转换为 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

...或切换到完全整洁的 eval,在这种情况下,您需要 quo_name 将 quosure 转换为名称:

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

或者,只需使用 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