dplyr通过多个列的不同函数汇总(折叠)数据集

时间:2019-09-08 13:09:11

标签: r group-by dplyr summarize

我试图通过不同的dplyr::summarise / summarise_at函数summarise_if {折叠}一个数据集,以使我在输出数据集中具有相同的命名变量。示例:

library(tidyverse)
data(iris)
iris$year <- rep(c(2000,3000),each=25) ## for grouping
iris$color <- rep(c("red","green","blue"),each=50) ## character column
iris$letter <- as.factor(rep(c("A","B","C"),each=50)) ## factor column
head(iris, 3)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species year color letter
1          5.1         3.5          1.4         0.2  setosa 2000   red      A
2          4.9         3.0          1.4         0.2  setosa 2000   red      A
3          4.7         3.2          1.3         0.2  setosa 2000   red      A

结果数据集应如下所示:

full
  Species     year Sepal.Width Petal.Width Sepal.Length Petal.Length letter color
  <fct>      <dbl>       <dbl>       <dbl>        <dbl>        <dbl> <fct>  <chr>
1 setosa      2000        87           6.2          5.8          1.9 A      red  
2 setosa      3000        84.4         6.1          5.5          1.9 A      red  
3 versicolor  2000        69.4        33.6          7            4.9 B      green
4 versicolor  3000        69.1        32.7          6.8          5.1 B      green
5 virginica   2000        73.2        51.1          7.7          6.9 C      blue 
6 virginica   3000        75.5        50.2          7.9          6.4 C      blue 

我可以通过重复以下操作来实现此目的:

sums <- iris %>% 
  group_by(Species, year) %>% 
  summarise_at(vars(matches("Width")), list(sum))
max <- iris %>% 
  group_by(Species, year) %>% 
  summarise_at(vars(matches("Length")), list(max))
last <- iris %>% 
  group_by(Species, year) %>% 
  summarise_if(is.factor, list(last))
first <- iris %>% 
  group_by(Species, year) %>% 
  summarise_if(is.character, list(first))

full <- full_join(sums, max) %>% full_join(last) %>%  full_join(first) 

我在下面找到了类似的方法,但是无法弄清楚我在这里尝试过的方法。我不希望自己发挥作用,因为我认为通过将所有内容传递到管道并加入连接,这样的方法会更干净:

test <- iris %>%
  #group_by(.vars = vars(Species, year)) %>% #why doesnt this work?
  group_by_at(.vars = vars(Species, year))  %>% #doesnt work 
    {left_join(
    summarise_at(., vars(matches("Width")), list(sum)),
    summarise_at(., vars(matches("Length")), list(max)),
    summarise_if(., is.factor, list(last)),
    summarise_if(., is.character, list(first))
    )
      } #doesnt work

这行不通,有什么建议或其他方法吗?

有用: How can I use summarise_at to apply different functions to different columns? Summarize different Columns with different Functions Using dplyr summarize with different operations for multiple columns

2 个答案:

答案 0 :(得分:1)

默认情况下,dplyr::left_join()函数仅接受两个数据帧。如果要对两个以上的数据帧使用此函数,则可以使用Reduce函数(基本R函数)对其进行迭代:


iris %>%
  group_by(Species, year) %>%
  {
    Reduce(
      function(x, y) left_join(x, y),
      list(
        summarise_at(., vars(matches("Width")), base::sum),
        summarise_at(., vars(matches("Length")), base::max),
        summarise_if(., is.factor, dplyr::last),
        summarise_if(., is.character, dplyr::first)
      ))
  }
#   Species     year Sepal.Width Petal.Width Sepal.Length Petal.Length letter color
#   <fct>      <dbl>       <dbl>       <dbl>        <dbl>        <dbl> <fct>  <chr>
# 1 setosa      2000        87           6.2          5.8          1.9 A      red  
# 2 setosa      3000        84.4         6.1          5.5          1.9 A      red  
# 3 versicolor  2000        69.4        33.6          7            4.9 B      green
# 4 versicolor  3000        69.1        32.7          6.8          5.1 B      green
# 5 virginica   2000        73.2        51.1          7.7          6.9 C      blue 
# 6 virginica   3000        75.5        50.2          7.9          6.4 C      blue 

此外,请注意,我必须使用::从其包中调用函数,以避免名称与先前创建的数据帧重叠。

答案 1 :(得分:1)

劫持@Ulises想法并使用purrr::reduce代替Reduce是另一种选择:

iris %>%
  group_by(Species, year) %>%
  list(
    summarise_at(., vars(matches("Width")), base::sum),
    summarise_at(., vars(matches("Length")), base::max),
    summarise_if(., is.factor, dplyr::last),
    summarise_if(., is.character, dplyr::first)
  ) %>%
  .[c(2:5)] %>%
  reduce(left_join)

OR 解决方案,使用大括号隐藏第一个参数:

iris %>%
  group_by(Species, year) %>%
  {
  list(
    summarise_at(., vars(matches("Width")), base::sum),
    summarise_at(., vars(matches("Length")), base::max),
    summarise_if(., is.factor, dplyr::last),
    summarise_if(., is.character, dplyr::first)
  )
  } %>%
  reduce(left_join)