在 purrr map() 中使用 dplyr summarise() 对分组数据的特定列进行汇总。

3

我有一个问题需要解决,但是我似乎找不到简洁的解决方案。虽然Stack Overflow上有一些类似的问题,但并没有完全符合我的情况。

拿一些示例数据:

library(dplyr)

dat <- tibble(
  group1 = factor(sample(c("one", "two"), 10, replace = T)),
  group2 = factor(sample(c("alpha", "beta"), 10, replace = T)),
  var1 = rnorm(10, 20, 2),
  var2 = rnorm(10, 20, 2),
  var3 = rnorm(10, 20, 2),
  other1 = sample(c("a", "b", "c"), 10, replace = T),
  other2 = sample(c("a", "b", "c"), 10, replace = T),
)

我想要总结仅数值变量(即忽略other1other2),但输出需要按group1group2进行分组。
我尝试了以下的代码,但它返回一个错误,因为它试图将我的summarise()函数应用于分组变量。
dat %>%
  group_by(group1, group2) %>%
  select(where(is.numeric)) %>%
  map(~ .x %>%
        filter(!is.na(.x)) %>%
        summarise(mean = mean(.x),
                  sd = sd(.x),
                  median = median(.x),
                  q1 = quantile(.x, p = .25),
                  q3 = quantile(.x, p = .75))
  )

我期望的输出应该是这样的

  group1  group2  mean    sd    median   q1     q3
  <fct> <fct>     <dbl>  <dbl>   <dbl>  <dbl>  <dbl>
1 one   alpha       ?      ?       ?      ?      ?
2 one   beta        ?      ?       ?      ?      ?
3 two   alpha       ?      ?       ?      ?      ?
4 two   beta        ?      ?       ?      ?      ?

任何解决方案都将不胜感激。

谢谢, Sam


1
那么使用 group_by(group1, group2),然后配合新的 across 使用 summarise_at / summarise_if / summarise?我认为你让你的代码变得比必要的更加复杂了。 - camille
是的,我想我根本不需要这张地图! - Sam
2个回答

3

尝试:

dat %>% group_by(group1,group2) %>%
        summarize(across(is.numeric,c(sd = sd,
                                      mean = mean, 
                                      median =median,
                                      q1 = function(x) quantile(x,.25),
                                      q3 = function(x) quantile(x,.75))))

group1 group2 var1_sd var1_mean var1_median var1_q1 var1_q3 var2_sd var2_mean var2_median var2_q1 var2_q3 var3_sd
  <fct>  <fct>    <dbl>     <dbl>       <dbl>   <dbl>   <dbl>   <dbl>     <dbl>       <dbl>   <dbl>   <dbl>   <dbl>
1 one    alpha    4.06       20.6        19.3    18.3    22.2   1.12       17.9        17.3    17.2    18.2  1.09  
2 one    beta     0.726      18.7        18.7    18.4    18.9   0.348      18.8        18.8    18.7    18.9  0.604 
3 two    alpha    1.31       19.9        20.0    19.3    20.6   1.10       17.8        18.3    17.4    18.5  0.624 
4 two    beta     0.777      21.2        21.2    21.0    21.5   1.13       19.6        19.6    19.2    20.0  0.0161

太棒了,谢谢@Waldi。看起来我刚刚把事情复杂化了,我还在逐渐习惯使用新的across()函数和整个tidyverse。你知道是否有一种方法可以向summarise()内的所有函数提供na.rm = T,还是我需要在每次调用中指定它? - Sam
@Sam,很高兴我能帮到你。你应该能够将na.rm = T作为额外参数提供给across函数,参见https://www.tidyverse.org/blog/2020/04/dplyr-1-0-0-colwise/。 - Waldi

1

您还可以将列传递给summarise函数:

dat %>%
  group_by(group1, group2) %>%
  summarise(mean = mean(var1:var3),
            sd = sd(var1:var3),
            median = median(var1:var3),
            q1 = quantile(var1:var3, p = .25),
            q3 = quantile(var1:var3, p = .75))
dat
# A tibble: 4 x 7
# Groups:   group1 [2]
#   group1 group2  mean     sd median    q1    q3
#   <fct>  <fct>  <dbl>  <dbl>  <dbl> <dbl> <dbl>
# 1 one    alpha   19.1  0.707   19.1  18.8  19.3
# 2 one    beta    17.5  1.29    17.5  16.8  18.3
# 3 two    alpha   17.1 NA       17.1  17.1  17.1
# 4 two    beta    19.9 NA       19.9  19.9  19.9

这真的很有用。我更喜欢Waldi的答案,因为我不需要经常指定变量名称,但我没有想到使用:选择多个变量,我忘记了这是一个tidyverse的概念。 - Sam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接