Как использовать Tidyeval на столбце, чтобы изменить?

Прошу прощения за путаницу, но в конечном итоге первый пример, который я разместил (внизу страницы), не помог мне понять, как tidyeval работает с mutate, поэтому я добавляю новый пример.

Я хотел бы создать функцию, которая принимает три аргумента:

  • кадр данных
  • столбцы для изменения
  • переменная (из кадра данных), чтобы заменить изменяемые значения

Например, чтобы заменить значения в mpg со значениями из carb Я попробовал это:

I tried this
colToX <- function(dt, ..., repl) {
  cols <- quos(...)
  repl <- quo(repl)
  mutate_at(dt, vars(!!!cols), funs(function(x) !!repl))
}

colToX(mtcars, mpg, repl = carb)

который не работает с тех пор:

Ошибка в mutate_impl(.data, точки): столбец mpg имеет неподдерживаемую функцию типа

Мой первый пример (@MrFlick's и @UseR оба отлично работают для этого):

Например, приведенный ниже mutate() присваивая все 1 переменной, переданной в ...

colTo1 <- function(dt, ...) {
col <- quo(...)
mutate(mtcars, !!col := 1)
}

colTo1(mtcars, mpg)

Ошибка: LHS должен быть именем или строкой

В конце концов, результат должен быть таким же, как mutate(mtcars, mpg = 1)

2 ответа

Решение

Решение @MrFlick работает для случая с одним столбцом, но, поскольку используется OP ... в качестве аргумента я предполагаю, что OP также хотел бы, чтобы функция могла принимать несколько столбцов. Например, следующее не будет работать:

colTo1 <- function(dt, ...) {
  col <- quo_name(quo(...))
  mutate(dt, !!col := 1)
}

colTo1(mtcars, mpg, cyl)

Ошибка в наследовании (x, "quosure"): объект 'cyl' не найден

Что мы можем сделать, это использовать quos вместо quo а также mutate_at вместо mutate:

colTo1 <- function(dt, ...) {
  cols <- quos(...)
  mutate_at(dt, vars(!!!cols), function(x) x=1)
}

quos преобразует каждый аргумент из ... в вектор предложений. С помощью mutate_at"s vars синтаксис и явное соединение с !!! от rlangмы можем расставить каждое предложение в colsи мутировать на указанных столбцах.

Теперь это работает как задумано:

colTo1(mtcars, mpg, cyl)

Результат:

   mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1    1   1 160.0 110 3.90 2.620 16.46  0  1    4    4
2    1   1 160.0 110 3.90 2.875 17.02  0  1    4    4
3    1   1 108.0  93 3.85 2.320 18.61  1  1    4    1
4    1   1 258.0 110 3.08 3.215 19.44  1  0    3    1
5    1   1 360.0 175 3.15 3.440 17.02  0  0    3    2
6    1   1 225.0 105 2.76 3.460 20.22  1  0    3    1
7    1   1 360.0 245 3.21 3.570 15.84  0  0    3    4
8    1   1 146.7  62 3.69 3.190 20.00  1  0    4    2
9    1   1 140.8  95 3.92 3.150 22.90  1  0    4    2
10   1   1 167.6 123 3.92 3.440 18.30  1  0    4    4
...

Это также достаточно легко, чтобы позволить1"быть еще одним аргументом для передачи в функцию:

colToX <- function(dt, ..., X) {
  cols <- quos(...)
  mutate_at(dt, vars(!!!cols), function(x) x=X)
}

colToX(mtcars, mpg, cyl, X = 2)

Изменить: OP изменил вопрос, требуя, чтобы X должен быть другой столбец в том же кадре данных. Ниже мое новое решение:

colToX <- function(dt, ..., X) {
  cols <- quos(...)
  X_quo <- enquo(X)
  mutate_at(dt, vars(!!!cols), funs(.data$`!!`(X_quo)))
}

colToX(mtcars, mpg, cyl, X = hp)

Здесь я использую funs функция для создания списка вызовов функций для каждого столбца, указанного в vars, .data относится к входному кадру данных в mutate_at (в этом случае dt). я использовал enquo конвертировать то, что называется из X в цитату и расстаться с кавычками, используя !!,

Результат:

   mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1  110 110 160.0 110 3.90 2.620 16.46  0  1    4    4
2  110 110 160.0 110 3.90 2.875 17.02  0  1    4    4
3   93  93 108.0  93 3.85 2.320 18.61  1  1    4    1
4  110 110 258.0 110 3.08 3.215 19.44  1  0    3    1
5  175 175 360.0 175 3.15 3.440 17.02  0  0    3    2
6  105 105 225.0 105 2.76 3.460 20.22  1  0    3    1
7  245 245 360.0 245 3.21 3.570 15.84  0  0    3    4
8   62  62 146.7  62 3.69 3.190 20.00  1  0    4    2
9   95  95 140.8  95 3.92 3.150 22.90  1  0    4    2
10 123 123 167.6 123 3.92 3.440 18.30  1  0    4    4
...

Поскольку ошибка говорит "Ошибка: LHS должен быть именем или строкой", где LHS означает левую часть, и это конкретно относится к !!col := 1 часть. Вам нужно превратить сделанное вами предложение в строку или символ. Вероятно, проще всего получить строковую версию фразы с quo_name

colTo1 <- function(dt, ...) {
    col <- quo_name(quo(...))
    mutate(mtcars, !!col := 1)
}
Другие вопросы по тегам