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

Следующий набор данных представляет мои ситуации:

library(dplyr)
df <- data_frame(
  G1 = rep(1:2, each = 10),
  G2 = rep(1:10, 2),
  C1 = rnorm(20),
  C2 = rnorm(20),
  C3 = rnorm(20),
  C4 = rnorm(20)
)

Я хочу выполнить следующую операцию,

df %>%
  group_by(G1, G2) %>%
  mutate(
    C1 = C1 - C2,
    C2 = C2 - C2,
    C3 = C3 - C2,
    C4 = C4 - C2
  )

Если есть только 4 столбца (C1, C2, C3 и C4), я могу применить вышеуказанное решение. Однако у меня много столбцов, и для каждого из них мне нужно выполнить одну и ту же операцию. Есть ли какое-нибудь краткое и простое решение, которое могло бы распространить эту проблему на многие столбцы?


person TheRimalaya    schedule 17.04.2017    source источник


Ответы (2)


Если вы можете найти некоторое сходство в именах столбцов, которые вы хотите изменить, вы можете воспользоваться dplyr::mutate_at() :

df %>%
    group_by(G1, G2) %>%
    mutate_at(vars(starts_with("C")), funs(. - C2))

Редактировать

Поскольку mutate() работает и последовательно сохраняет результат для каждого столбца, у вас есть два варианта решения проблемы. Вы можете использовать reorder(df, everything(), C2), чтобы ваш C2 был последним в вашем data.frame, или добавить вторую строку следующим образом:

set.seed(1)
library(dplyr)
df <- data_frame(
    G1 = rep(1:2, each = 10),
    G2 = rep(1:10, 2),
    C1 = rnorm(20, 0),
    C2 = rnorm(20, 1),
    C3 = rnorm(20, 10),
    C4 = rnorm(20, 100)
)


df %>%
    mutate_at(vars(starts_with("C"), -C2), funs(. - C2)) %>%
    mutate_at(vars(C2), funs(. - C2))

Это просто мутирует для каждого столбца, кроме C2 в первой строке. Затем вторая строка возвращается и изменяет C2 после того, как другие столбцы успешно вычтены.

person Nate    schedule 17.04.2017
comment
Очень хороший ответ. В моей исходной ситуации у меня нет столбцов, начинающихся с C в этой ситуации, как я могу выбрать все переменные, кроме переменных группировки? - person TheRimalaya; 17.04.2017
comment
вы можете настроить на vars(-G1, -G2) - person Nate; 17.04.2017
comment
Итак, в этом случае мне даже не нужно группировать. Спасибо - person TheRimalaya; 17.04.2017
comment
Извините, но это не работает. Когда я использую (. - C2), C3 и C4 фактически вычитаются из 0, что составляет C2 - C2. Пожалуйста, помогите мне с альтернативным решением. - person TheRimalaya; 23.04.2017
comment
@TheRimalaya дайте мне знать, если мое редактирование вернет его к работе - person Nate; 25.04.2017

Как насчет использования data.table для указания нужных столбцов с помощью .SDcols?

library(data.table)
cols <- colnames(df)[which(grepl("C",colnames(df)))]
dt <- setDT(df)[, lapply(.SD, function(x) x - C2), by=.(G1,G2), .SDcols = cols]
person Mike H.    schedule 17.04.2017
comment
Спасибо за решение, я уже сделал это с data.table. - person TheRimalaya; 17.04.2017