【问题标题】:summarise_at using different functions for different variablessummarise_at 对不同的变量使用不同的函数
【发布时间】:2018-02-21 14:44:29
【问题描述】:

当我在dplyr中使用group_by和summary时,自然可以对不同的变量应用不同的summary函数。例如:

    library(tidyverse)

    df <- tribble(
      ~category,   ~x,  ~y,  ~z,
      #----------------------
          'a',      4,   6,   8,
          'a',      7,   3,   0,
          'a',      7,   9,   0,
          'b',      2,   8,   8,
          'b',      5,   1,   8,
          'b',      8,   0,   1,
          'c',      2,   1,   1,
          'c',      3,   8,   0,
          'c',      1,   9,   1
     )

    df %>% group_by(category) %>% summarize(
      x=mean(x),
      y=median(y),
      z=first(z)
    )

输出结果:

    # A tibble: 3 x 4
      category     x     y     z
         <chr> <dbl> <dbl> <dbl>
    1        a     6     6     8
    2        b     5     1     8
    3        c     2     8     1

我的问题是,我将如何使用 summarise_at 执行此操作?显然对于这个例子来说这是不必要的,但假设我有很多变量要取平均值,很多中位数等等。

一旦我转移到 summarise_at,我会失去这个功能吗?我是否必须对所有变量组使用所有函数,然后丢弃我不想要的那些?

也许我只是遗漏了一些东西,但我无法弄清楚,而且我在文档中也没有看到任何这样的例子。任何帮助表示赞赏。

【问题讨论】:

  • 基本的Map 功能可以做到这一点,例如Map(function(f,v) f(v), c(mean,median,first), df[c("x","y","z")])。也许purrrmap 可以做类似的事情?
  • 是的,我想知道 purrr 是否可以为我们提供摆脱这种情况的方法。值得研究。但是在您的示例中,您不只是将所有函数应用于所有变量吗?以及如何将它与 group_by 一起使用?
  • 不,我正在使用Map 将每个函数依次应用于每个变量 - 查看mean(df$x); median(df$y); first(df$z) 的结果并与Map 代码进行比较。
  • 好的,我明白你的意思了,但我的问题与 ycw 相同:如果我有第一个函数的三个变量,第二个函数有 10 个变量,第三个函数有一个变量怎么办?这看起来像是 summarise_at 的替代品,而不是放在里面的东西。我想我要的是完整的代码,因为当我将您的建议应用于我的示例数据框时,我没有得到我正在寻找的答案。

标签: r dplyr tidyverse


【解决方案1】:

由于您的问题是关于“summarise_at”;

这是我的想法:

df %>% group_by(category) %>% 
 summarise_at(vars(x, y, z),
      funs(mean = mean, sd = sd, min = min),
      na.rm = TRUE)

【讨论】:

    【解决方案2】:

    这是一个想法。

    library(tidyverse)
    
    df_mean <- df %>%
      group_by(category) %>%
      summarize_at(vars(x), funs(mean(.)))
    
    df_median <- df %>%
      group_by(category) %>%
      summarize_at(vars(y), funs(median(.)))
    
    df_first <- df %>%
      group_by(category) %>%
      summarize_at(vars(z), funs(first(.)))
    
    df_summary <- reduce(list(df_mean, df_median, df_first), 
                         left_join, by = "category")
    

    就像你说的,这个例子不需要使用summarise_at。但是,如果您有很多列需​​要通过不同的功能进行汇总,则此策略可能会起作用。您需要为每个summarize_at 指定vars(...) 中的列。规则同dplyr::select函数。

    更新

    这是另一个想法。定义一个修改summarise_at 函数的函数,然后使用map2 应用此函数,并使用一个查找列表显示要应用的变量和相关函数。在此示例中,我将mean 应用于xy 列,并将median 应用于z

    # Define a function
    summarise_at_fun <- function(variable, func, data){
      data2 <- data %>%
        summarise_at(vars(variable), funs(get(func)(.)))
      return(data2)
    }
    
    # Group the data
    df2 <- df %>% group_by(category)
    
    # Create a look-up list with function names and variable to apply
    look_list <- list(mean = c("x", "y"),
                      median = "z")
    
    # Apply the summarise_at_fun
    map2(look_list, names(look_list), summarise_at_fun, data = df2) %>%
      reduce(left_join, by = "category")
    
    # A tibble: 3 x 4
      category     x     y     z
         <chr> <dbl> <dbl> <dbl>
    1        a     6     6     0
    2        b     5     3     8
    3        c     2     6     1
    

    【讨论】:

    • 这确实是可能的,而且比我考虑过的各种“长”解决方案更优雅。但是在一个命令中完成它不是很好吗?另外,在使用 summarise_at 时有什么方法可以控制结果列的名称?
    • @DavidEpstein 可以使用summarise_at 指定名称。您可以执行funs(x = mean(.)),这会导致Col_x,其中Col 是原始列名。
    • @DavidEpstein 至于你的第一个问题,我确定是否有可能。我之前开发过这个答案:stackoverflow.com/questions/45801972/… 根据不同的条件应用不同的功能。但是,由于您没有指定要测试的列的任何条件,所以我不知道如何实现类似的方法。
    • 感谢您的链接,但我仍然没有看到任何关于将一个函数应用于一个变量子集以及将另一个函数应用于另一个子集的任何内容。
    • @DavidEpstein 请查看我的更新。这可能与您想要的更相关。您需要创建一个新函数并创建一个查找表来显示变量名称和要应用的函数之间的关系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-12
    • 1970-01-01
    • 2018-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-12
    相关资源
    最近更新 更多