mutate_at не создает переменные суффиксы в некоторых случаях?

Я играл с dplyr::mutate_at создать новые переменные, применив ту же функцию к некоторым столбцам. Когда я называю свою функцию в .funs В качестве аргумента, вызов mutate создает новые столбцы с суффиксом вместо замены существующих, что является отличным вариантом, который я обнаружил в этой теме.

df = data.frame(var1=1:2, var2=4:5, other=9)
df %>% mutate_at(vars(contains("var")), .funs=funs('sqrt'=sqrt))
####   var1 var2 other var1_sqrt var2_sqrt
#### 1    1    4     9  1.000000  2.000000
#### 2    2    5     9  1.414214  2.236068

Тем не менее, я заметил, что когда vars Аргумент, используемый для указания моих столбцов, возвращает только один столбец вместо нескольких, полученный новый столбец удаляет исходное имя: ему присваивается имя sqrt вместо other_sqrt Вот:

df %>% mutate_at(vars(contains("other")), .funs=funs('sqrt'=sqrt))
####   var1 var2 other sqrt
#### 1    1    4     9    3
#### 2    2    5     9    3

Я хотел бы понять, почему такое поведение происходит, и как его избежать, потому что я не знаю заранее, сколько столбцов contains() вернусь.

РЕДАКТИРОВАТЬ: Вновь созданные столбцы должны наследовать исходное имя исходных столбцов, а также суффикс "sqrt" в конце.

Спасибо

2 ответа

Решение

Вот еще одна идея. Мы можем добавить setNames(sub("^sqrt$", "other_sqrt", names(.))) после mutate_at вызов. Идея состоит в том, чтобы заменить имя столбца sqrt с other_sqrt, Шаблон ^sqrt$ должен соответствовать только производный столбец sqrt если есть только один столбец с именем otherЭто показано в примере 1. Если имеется более одного столбца с otherтакой как Пример 2, setNames не будет изменять имена столбцов.

library(dplyr)

# Example 1
df <- data.frame(var1 = 1:2, var2 = 4:5, other = 9)

df %>% 
  mutate_at(vars(contains("other")), funs("sqrt" = sqrt(.))) %>%
  setNames(sub("^sqrt$", "other_sqrt", names(.)))
#   var1 var2 other other_sqrt
# 1    1    4     9          3
# 2    2    5     9          3

# Example 2
df2 <- data.frame(var1 = 1:2, var2 = 4:5, other1 = 9, other2 = 16)

df2 %>% 
  mutate_at(vars(contains("other")), funs("sqrt" = sqrt(.))) %>%
  setNames(sub("^sqrt$", "other_sqrt", names(.)))
#   var1 var2 other1 other2 other1_sqrt other2_sqrt
# 1    1    4      9     16           3           4
# 2    2    5      9     16           3           4

Или мы можем разработать функцию для проверки, сколько столбцов содержат строку other перед манипулированием фреймом данных.

mutate_sqrt <- function(df, string){
  string_col <- grep(string, names(df), value = TRUE)
  df2 <- df %>% mutate_at(vars(contains(string)), funs("sqrt" = sqrt(.)))
  if (length(string_col) == 1){
    df2 <- df2 %>%  setNames(sub("^sqrt$", paste(string_col, "sqrt", sep = "_"), names(.)))
  }
  return(df2)
}

mutate_sqrt(df, "other")
#   var1 var2 other other_sqrt
# 1    1    4     9          3
# 2    2    5     9          3

mutate_sqrt(df2, "other")
#   var1 var2 other1 other2 other1_sqrt other2_sqrt
# 1    1    4      9     16           3           4
# 2    2    5      9     16           3           4 

Я только что нашел (не очень чистый) способ сделать это; Я добавляю дополнительную фиктивную переменную к набору данных с именем, которое гарантирует, что он будет выбран, и что мы не попадем в случай с 1 переменной, и после вычисления я удалю 2 манекена, например так:

df %>% mutate(other_fake=NA) %>% 
  mutate_at(vars(contains("other")), .funs=funs('sqrt'=sqrt)) %>% 
  select(-contains("other_fake"))
####   var1 var2 other other_sqrt
#### 1    1    4     9          3
#### 2    2    5     9          3
Другие вопросы по тегам