Как использовать 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)
}