Я знаю, что здесь есть несколько подобных вопросов, но ни один из них, кажется, не решает точную проблему, которая у меня есть.
set.seed(4)
df = data.frame(
Key = c("A", "B", "A", "D", "A"),
Val1 = rnorm(5),
Val2 = runif(5),
Val3 = 1:5
)
Я хочу обнулить значения столбцов значений для строк, где Key == "A" На имена столбцов ссылаются через grep
:
cols = grep("Val", names(df), value = TRUE)
Обычно для достижения того, что я хочу в этом случае, я бы использовал data.table
так:
library(data.table)
df = as.data.table(df)
df[Key == "A", (cols) := 0]
И желаемый результат выглядит так:
Key Val1 Val2 Val3
1 A 0.000000 0.00000000 0
2 B -1.383814 0.55925762 2
3 A 0.000000 0.00000000 0
4 D 1.437151 0.05632773 4
5 A 0.000000 0.00000000 0
Однако это время мне нужно использовать, так dplyr
как я работаю над командным проектом, где его используют все. Данные, которые я только что предоставил, являются иллюстративными, и мои реальные данные> 5 миллионов строк с 16 столбцами значений, которые необходимо обновить. Единственное решение, которое я мог бы придумать, это использовать mutate_at
так:
df %>% mutate_at(.vars = vars(cols), .funs = function(x) ifelse(df$Key == "A", 0, x))
Тем не менее, это кажется чрезвычайно медленно на моих реальных данных. Я надеялся найти решение, которое будет более элегантным и, что более важно, более быстрым.
Я пробовал много комбинаций с использованием map
, снятием кавычек, использованием !!
, использованием get
и :=
(что досадно может быть замаскировано :=
в data.table) и т. Д., Но я думаю, что мое понимание того, как эти работы просто недостаточно глубоки, чтобы построить правильное решение.
источник
Ответы:
С помощью этой команды dplyr,
Вы фактически вычисляете оператор df $ Key == "A", n раз, где n = количество столбцов, которые у вас есть.
Обходной путь - предварительно определить строки, которые вы хотите изменить:
Более понятный и лучший способ, правильно указанный @IceCreamToucan (см. Комментарии ниже), - это использовать функцию replace, передавая ей дополнительные параметры:
Мы можем проверить все эти подходы, и я думаю, что dplyr и data.table сопоставимы.
источник
df %>% mutate_at(vars(contains('Val')), replace, df$Key == 'A', 0)
replace
метод немного медленнее, чем ваш оригинальныйidx
метод.dplyr::if_else()
это быстрее, чем базаifelse()
.