Если предположить, что ответ Фелипе - это та функциональность, которую вы пожелали, вот вам более «нисходящий» / ориентированный на трубы / функциональный подход.
Данные
library(rlang)
library(dplyr)
library(purrr)
operations <- tibble(
old_var = exprs(A, B),
new_var = exprs(AA, BB),
test = exprs(2*A > B, 2*B <= C),
result = exprs("True", "False")
)
original <- tibble(
A = sample.int(30, 10),
B = sample.int(30, 10),
C = sample.int(30, 10)
)
original
# A tibble: 10 x 3
A B C
<int> <int> <int>
1 4 20 5
2 30 29 11
3 1 27 14
4 2 21 4
5 17 19 24
6 14 25 9
7 5 22 22
8 6 13 7
9 25 4 21
10 12 11 12
Функции
# Here's your reusable functions
generic_mutate <- function(dat, new_var, test, result, old_var) {
dat %>% mutate(!!new_var := ifelse(!!test, !!result, !!old_var))
}
generic_ops <- function(dat, ops) {
pmap(ops, generic_mutate, dat = dat) %>%
reduce(full_join)
}
generic_mutate
принимает один исходный кадр данных, один new_var
и т. Д. Он выполняет тест, добавляет новый столбец с соответствующимимя и значения.
generic_ops
- это «векторизованная» версия.Первоначальный аргумент принимает исходный фрейм данных, а второй - фрейм данных операций.Затем он параллельно отображает каждый столбец с новыми именами переменных, тестами и т. Д. И вызывает generic_mutate
для каждого из них.Это приводит к списку фреймов данных, каждый с одним добавленным столбцом.reduce
затем объединяет их все вместе с последовательными full_join
.
Результатами
original %>%
generic_ops(operations)
Joining, by = c("A", "B", "C")
# A tibble: 10 x 5
A B C AA BB
<int> <int> <int> <chr> <chr>
1 4 20 5 4 20
2 30 29 11 True 29
3 1 27 14 1 27
4 2 21 4 2 21
5 17 19 24 True 19
6 14 25 9 True 25
7 5 22 22 5 22
8 6 13 7 6 13
9 25 4 21 True False
10 12 11 12 True 11
Волшебство, которое здесь используетсяexprs(...)
, чтобы вы могли хранить имена и операции NSE в таблице, не форсируя их оценку.Я думаю, что это намного чище, чем хранить имена и операции в строках с кавычками.