Я изучаю функциюthrough(), представленную в последних версиях dplyr, и пытаюсь понять, как использовать ее для применения пользовательской функции, возвращающей несколько столбцов. В частности, я хочу применить функцию, которая вычисляет среднее и стандартное отклонение для выбранных числовых столбцов в моем фрейме данных и возвращает их как отдельные столбцы.
Например, учитывая следующий фрейм данных:
library(dplyr)
df <- data.frame(
Group = rep(letters[1:3], each = 4),
Value1 = rnorm(12, mean = 10, sd = 2),
Value2 = rnorm(12, mean = 5, sd = 1)
)
Я хочу создать новый фрейм данных, включающий среднее и стандартное отклонение для каждого столбца значений, примерно так:
Group Mean_Value1 SD_Value1 Mean_Value2 SD_Value2
1 a 9.812 2.034 4.955 1.085
2 b 10.231 1.987 5.023 0.923
3 c 10.032 2.121 4.998 1.098
Я попробовал следующий подход, но не уверен, как заставить его правильно работать с across()
:
df_summary <- df %>%
group_by(Group) %>%
summarise(across(starts_with("Value"), ~ c(mean = mean(.), sd = sd(.))))
Это вызывает ошибку, поскольку функцияthrough(), похоже, не обрабатывает естественным образом функции, возвращающие несколько столбцов.
Мои конкретные вопросы:
across()
для функций, возвращающих несколько значений?dplyr
или другой пакет в R?across()
при работе с такими пользовательскими функциями?Любые рекомендации о том, как это сделать, будут очень признательны!
Кроме того, вы можете переместить group_by(Group)
в summarise()
, выполнив .by=Group
.
Спасибо всем за вашу помощь! Я видел пример, и это было очень полезно... Спасибо.
Ваш вопрос фактически указан в качестве примера на странице документации сайта across
.
Вам следует использовать list
, чтобы включить несколько функций для across
.
library(dplyr)
df %>%
group_by(Group) %>%
summarise(across(starts_with("Value"), list(mean = mean, sd = sd)))
# A tibble: 3 × 5
Group Value1_mean Value1_sd Value2_mean Value2_sd
<chr> <dbl> <dbl> <dbl> <dbl>
1 a 8.61 0.837 5.57 0.581
2 b 8.90 2.08 5.22 0.479
3 c 10.3 1.98 4.36 0.465
Вы можете сделать across(starts_with("Value"), list(Mean = mean, SD = sd), .names = "{.fn}_{.col}")
, чтобы получить точный результат, указанный в вопросе.
Можно использовать lst
и .by=
вот так: df %>% summarize(across(everything(), lst(mean, sd)), .by = Group)
По адресу
Есть ли лучший способ добиться этого, используя dplyr или другой пакет в R?
Существует несколько пакетов, предоставляющих такие функции группировки. Если мы определим «лучше» как без использования внешних пакетов, мы сможем сделать:
aggregate(df[grepl("Value", names(df))], df["Group"], \(x) c(Mean=mean(x), SD=sd(x)))
предоставление
Group Value1.Mean Value1.SD Value2.Mean Value2.SD
1 a 10.901248 2.365063 4.5826417 0.8582879
2 b 9.358671 2.549811 4.9142623 1.0512226
3 c 11.040255 1.491652 5.2339545 1.0130163
Это может быть альтернативой, если вас не беспокоит способ отображения aggregate()
названий столбцов [отредактированный глагол].
Обратите внимание, что результатом здесь является фрейм данных из трех столбцов, столбцы которого — Group
, Value1
и Value2
. Value1
— это матрица с двумя столбцами с именами Mean
и SD
и аналогично для Value2
. Value1.Mean
не является названием какого-либо столбца. Чтобы получить к этому доступ, можно использовать df2$Value1[, "Mean"]
или df2[["Value1"]][, "Mean"]
, предполагая, что df2
является результатом aggregate
.
взгляните на документы. Если вы хотите применить несколько функций, вам необходимо передать их в виде списка, например.
summarise(across(starts_with("Value"), list(mean = mean, sd = sd)))