Как я могу применить функцию в `mutate_at`, которая последовательно строит значения в других столбцах? - PullRequest
2 голосов
/ 06 февраля 2020

У меня есть фрейм данных, в котором я хотел бы преобразовать значения одного набора столбцов, при условии наличия значений в другом наборе столбцов в той же строке. Я пытаюсь и не могу сделать это в tidyverse с комбинацией rowwise и mutate_at. Вот воспроизводимый пример.

library(dplyr)

set.seed(20912)
dat <- data.frame(cat1 = sample(LETTERS[1:2], 10, replace = TRUE), cat2 = sample(LETTERS[1:2], 10, replace = TRUE), id = 3, sim_1 = rnorm(10), sim_2 = rnorm(10), stringsAsFactors = FALSE)

> dat
   cat1 cat2 id      sim_1       sim_2
1     A    A  3 -0.1054062 -0.47563580
2     B    A  3 -1.7198921  0.76713640
3     A    B  3 -0.5946627 -0.33958464
4     B    B  3 -1.6547488 -0.13026564
5     B    B  3 -0.3779149  1.29590315
6     B    B  3  0.6271939  0.08707965
7     B    B  3  1.6376711  1.02151753
8     A    B  3  1.7675520  1.66983954
9     B    A  3 -0.3284081 -1.28175621
10    B    B  3  0.8431148 -0.15415091

В этой таблице я хочу преобразовать значения всех столбцов, которые начинаются с "sim_", в зависимости от значений cat1 и cat2. Скажем, например, я хочу заменить значения во всех столбцах "sim_*" на NA, но только в строках, где cat1 == cat2. Итак, мой ожидаемый результат будет:

   cat1 cat2 id      sim_1      sim_2
1     A    A  3         NA         NA
2     B    A  3 -1.7198921  0.7671364
3     A    B  3 -0.5946627 -0.3395846
4     B    B  3         NA         NA
5     B    B  3         NA         NA
6     B    B  3         NA         NA
7     B    B  3         NA         NA
8     A    B  3  1.7675520  1.6698395
9     B    A  3 -0.3284081 -1.2817562
10    B    B  3         NA         NA

Я попробовал несколько вариантов на тему rowwise плюс mutate_at без удачи. Например:

> dat %>% rowwise() %>% mutate_at(vars(starts_with("sim_")), function(x) { ifelse(cat1 == cat2, NA, x) })
Error in ifelse(cat1 == cat2, x, 0) : object 'cat1' not found

Что мне не хватает? Я понимаю, что это было бы проще, если бы я сначала изменил данные с широкого на длинный, но я надеюсь узнать что-нибудь о tidyverse функциях или синтаксисе и найти способ сделать это без изменения формы данных.

1 Ответ

5 голосов
/ 06 февраля 2020

Мы можем использовать replace и ifelse/replace векторизовано, поэтому можно избежать rowwise

library(dplyr)
dat %>%
   mutate_at(vars(starts_with('sim')), ~ replace(., cat1 == cat2, NA_real_))

Или, поскольку это столбцы с цифрами c, можно напрямую выполнить преобразование

dat %>% 
   mutate_at(vars(starts_with('sim')),  ~.* NA^(cat1 == cat2))
...