Используйте отрицание с выбором в 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)

работать, но это, очевидно, выбирает только .k. Я не могу получить что-то вроде:

out %>% select(-!!temp_col)

работать.


person vitallish    schedule 24.11.2017    source источник
comment
Поскольку temp_var является строкой, вам нужно использовать rlang::sym, чтобы превратить ее в квазуру, если вы хотите снять кавычки с !!, например. out %>% select(-!!rlang::sym(temp_col))   -  person alistaire    schedule 24.11.2017
comment
Спасибо, насколько я понимаю, я не могу сделать temp_var пустым, потому что мне нужно, чтобы он был слева от оператора mutate. Не уверен, что есть более чистый способ сделать это. Я надеялся, что смогу придерживаться только dplyr.   -  person vitallish    schedule 24.11.2017


Ответы (3)


Вам понадобится 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
person alistaire    schedule 24.11.2017

Вы можете использовать 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
person Psidom    schedule 24.11.2017
comment
Это определенно работает, но я не уверен, что это в духе нового синтаксиса/концепций квазур. - person vitallish; 24.11.2017
comment
Насколько я понимаю, quosure существует для расширения возможностей программирования с помощью dplyr в нестандартном стиле оценки, то есть для исключения *_ глаголов. Поэтому я бы предположил, что select с вспомогательными функциями select по-прежнему является одним из канонических способов сделать это. Если вы предпочитаете использовать quosure, комментарий @alistaire должен быть подходящим вариантом. - person Psidom; 24.11.2017

Это также должно работать:

out %>% select_(paste0("-",temp_col))
person Moody_Mudskipper    schedule 24.11.2017
comment
Спасибо, но я думаю, что dplyr отходит от *_ глаголов - person vitallish; 24.11.2017
comment
Они не будут поддерживаться или продвигаться, но и не будут удалены из пакета ни через несколько лет, ни когда-либо :). Но да, наверное, лучше использовать ответ @Psidom, я упомянул его для полноты картины. - person Moody_Mudskipper; 24.11.2017