Как я могу использовать функциюthrough() в dplyr для применения пользовательских функций, возвращающих несколько столбцов?

Я изучаю функцию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(), похоже, не обрабатывает естественным образом функции, возвращающие несколько столбцов.

Мои конкретные вопросы:

  1. Как я могу изменить этот подход, чтобы правильно использовать across() для функций, возвращающих несколько значений?
  2. Есть ли лучший способ добиться этого, используя dplyr или другой пакет в R?
  3. Каковы ограничения across() при работе с такими пользовательскими функциями?

Любые рекомендации о том, как это сделать, будут очень признательны!

взгляните на документы. Если вы хотите применить несколько функций, вам необходимо передать их в виде списка, например. summarise(across(starts_with("Value"), list(mean = mean, sd = sd)))

stefan 04.09.2024 10:27

Кроме того, вы можете переместить group_by(Group) в summarise(), выполнив .by=Group.

Friede 04.09.2024 10:30

Спасибо всем за вашу помощь! Я видел пример, и это было очень полезно... Спасибо.

Antreas Stefopoulos 04.09.2024 12:42
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ваш вопрос фактически указан в качестве примера на странице документации сайта 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}"), чтобы получить точный результат, указанный в вопросе.

SamR 04.09.2024 10:30

Можно использовать lst и .by= вот так: df %>% summarize(across(everything(), lst(mean, sd)), .by = Group)

G. Grothendieck 04.09.2024 11:25
Ответ принят как подходящий

По адресу

Есть ли лучший способ добиться этого, используя 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.

G. Grothendieck 04.09.2024 13:59

Другие вопросы по теме