Выполнение другой простой пользовательской функции на основе группы

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

Например, скажем, мне нужно среднее значение для группы A:

library(tidyverse)

data(iris)

iris$Group <- c(rep("A", 50), rep("B", 50), rep("C", 50))

f_a <- function(df){
  out <- df %>% 
    group_by(Species) %>% 
    summarise(mean = mean(Sepal.Length))
  return(out)
}

Медиана для группы B

f_b <- function(df){
  out <- df %>% 
    group_by(Species) %>% 
    summarise(median = median(Sepal.Length))
  return(out)
}

И стандартное отклонение для группы C

f_c <- function(df){
  out <- df %>% 
    group_by(Species) %>% 
    summarise(sd= sd(Sepal.Length))
  return(out)
}

Есть ли способ объединить вышеуказанные функции и запустить их в соответствии с параметром группы ?? Например: fx(df, group = "A") Что даст результаты вышеупомянутой функции f_a ??

Имея в виду, что в моем реальном контексте использования я не могу просто group_by (group) в исходной функции, поскольку фактические функции более сложные. Спасибо!!


person Lachlan    schedule 29.01.2021    source источник


Ответы (2)


Мы создаем switch внутри функции, чтобы выбрать соответствующую функцию для применения на основе совпадающего ввода от group. Эта функция передается в summarise для применения после groupihg с помощью 'Species'

fx <- function(df, group) {
           fn_selector <- switch(group,
                        A = "mean",
                        B = "median",
                       C = "sd")
          
                       
                       
             
          df %>%
             group_by(Species) %>%
             summarise(!! fn_selector :=
             match.fun(fn_selector)(Sepal.Length), .groups = 'drop')
        }

-тестирование

fx(iris, "A")
# A tibble: 3 x 2
#  Species     mean
#  <fct>      <dbl>
#1 setosa      5.01
#2 versicolor  5.94
#3 virginica   6.59
 
fx(iris, "B")
# A tibble: 3 x 2
#  Species    median
#  <fct>       <dbl>
#1 setosa        5  
#2 versicolor    5.9
#3 virginica     6.5

fx(iris, "C")
# A tibble: 3 x 2
#  Species       sd
#  <fct>      <dbl>
#1 setosa     0.352
#2 versicolor 0.516
#3 virginica  0.636
person akrun    schedule 29.01.2021
comment
Это полезно само по себе, но не совсем то, что я ищу. Я действительно хочу выполнять совершенно разные функции для каждой группы. Как и три функции выше (f_a, f_b, f_c), можно ли их объединить в одну большую функцию ?? Возможно использование if else ?? - person Lachlan; 30.01.2021
comment
@Lachlan Извините, вам нужна функция switch или вы применяете три функции на основе уже созданного столбца «группа»? - person akrun; 30.01.2021
comment
@Lachlan, не могли бы вы проверить, действительно ли это обновление то, что вы ищете. Я думал, что вы хотите передать аргумент в group_by. Простите, это моя ошибка. - person akrun; 30.01.2021
comment
Это та часть, которую мне нужно уточнить в моем вопросе. Я не спрашивал прямо, так как думал, что более простой пример может решить эту проблему (возможно, там не так). Каждый df, который я загружаю в эту функцию, имеет только одну группу. Итак, я хочу выполнить одну из трех функций, в зависимости от того, какую группу содержит df (A, B или C). Я уточню свой вопрос сейчас - person Lachlan; 30.01.2021
comment
@Lachlan Да, тогда обновление должно работать. Пожалуйста, проверьте результат, который я показал - person akrun; 30.01.2021
comment
@Lachlan Нам не нужно изменять данные, создавая групповой столбец. С switch проще - person akrun; 30.01.2021
comment
Да, спасибо, что познакомили меня с переключателем - это та функция, которую я искал! - person Lachlan; 30.01.2021

Я не понимаю смысла наличия group столбца в наборе данных. Когда мы передаем group = "A" в функцию, это не имеет ничего общего с group столбцом, который был создан.

Вместо того, чтобы передавать group = "A" в функцию, а затем отображать A какой-либо функции, вы можете напрямую передать функцию, которую хотите применить.

library(dplyr)

f_a <- function(df, fn){
  out <- df %>% 
          group_by(Species) %>% 
          summarise(out = fn(Sepal.Length))
  return(out)
}

f_a(iris, mean)

# A tibble: 3 x 2
#  Species      out
#* <fct>      <dbl>
#1 setosa      5.01
#2 versicolor  5.94
#3 virginica   6.59

f_a(iris, median)
# A tibble: 3 x 2
#  Species      out
#* <fct>      <dbl>
#1 setosa       5  
#2 versicolor   5.9
#3 virginica    6.5
person Ronak Shah    schedule 30.01.2021
comment
Думаю, я слишком упростил свой вопрос и сделал его слишком расплывчатым. В моих реальных данных каждый отдельный набор данных имеет столбец с A, B или C. И в зависимости от этого значения я хочу использовать другую функцию. Итак, я читаю фрейм данных, а затем применяю функцию A, если данные относятся к группе A, функцию B, если данные относятся к группе B и т. Д. Я новичок в написании функций, поэтому выполнение таких сложных вещей, как это, немного выше меня. - person Lachlan; 31.01.2021