【问题标题】:Collapse specific rows/cases of dataframe折叠数据框的特定行/案例
【发布时间】:2021-11-08 21:21:09
【问题描述】:

我想折叠 data.frame 的某些特定行(最好使用 dplyr in )。折叠应该通过函数 sum() 聚合一些列,而另一些则通过 mean() 聚合。

例如,让我们将一个基于字符的唯一 ID 添加到 iris 数据集。

iris_df <- iris[1:5,]
iris_df$ID <- paste("ID_",1:nrow(iris_df),sep="")

这就是我们开始的地方:

structure(list(Sepal.Length = c(5.1, 4.9, 4.7, 4.6, 5), 
               Sepal.Width = c(3.5, 3, 3.2, 3.1, 3.6),
               Petal.Length = c(1.4, 1.4, 1.3, 1.5, 1.4), 
               Petal.Width = c(0.2, 0.2, 0.2, 0.2, 0.2),
               Species = structure(c(1L, 1L, 1L, 1L, 1L),
                                   .Label = c("setosa", "versicolor", "virginica"), class = "factor"),
               ID = c("ID_1", "ID_2", "ID_3", "ID_4","ID_5")),
          row.names = c(NA, 5L), class = "data.frame")

现在,我想折叠 ID==ID_1 + ID==ID_2 的情况。为此,Sepal 值应聚合为均值,Petal 值应聚合为总和。 ID应该变成“ID_1+ID_2”(所以通过paste()聚合?)

这是最终结果的样子:

structure(list(Sepal.Length = c(5.0, 4.7, 4.6, 5), 
               Sepal.Width = c(3.25, 3.2, 3.1, 3.6),
               Petal.Length = c(2.8, 1.3, 1.5, 1.4), 
               Petal.Width = c(0.4, 0.2, 0.2, 0.2),
               Species = structure(c(1L, 1L, 1L, 1L),
                                   .Label = c("setosa", "versicolor", "virginica"), class = "factor"),
               ID = c("ID_1+ID_2", "ID_3", "ID_4","ID_5")),
          row.names = c(NA, 4L), class = "data.frame")

这可以使用dplyr(使用group_by()summarize())包来完成吗?

更新:作为一些附加说明,所需的过程应该承认行索引是先验未知的,例如只是 ID_x 和 ID_y 需要折叠(并且 ID_x 可能是第 i 行和第 j 行的 ID_y)。

【问题讨论】:

    标签: r dplyr collapse


    【解决方案1】:

    我们可以使用%in%根据这些ID的存在创建一个分组

    library(dplyr)
    library(stringr)
    df1 %>% 
       group_by(grp = case_when(ID %in% c("ID_1", "ID_2") ~ 0L, 
            TRUE ~ row_number()), Species) %>% 
       summarise(across(starts_with("Sepal"), mean), 
       across(starts_with("Petal"), sum), ID = str_c(ID, collapse="+"), 
             .groups = 'drop') %>% 
       select(-grp)
    

    -输出

    # A tibble: 4 x 6
      Species Sepal.Length Sepal.Width Petal.Length Petal.Width ID       
      <fct>          <dbl>       <dbl>        <dbl>       <dbl> <chr>    
    1 setosa           5          3.25          2.8         0.4 ID_1+ID_2
    2 setosa           4.7        3.2           1.3         0.2 ID_3     
    3 setosa           4.6        3.1           1.5         0.2 ID_4     
    4 setosa           5          3.6           1.4         0.2 ID_5     
    

    如果只有一个“物种”,那么我们也可以使用first

    df1 %>% 
       group_by(grp = case_when(ID %in% c("ID_1", "ID_2") ~ 0L, 
            TRUE ~ row_number())) %>%  
       summarise(across(starts_with("Sepal"), mean), 
       across(starts_with("Petal"), sum), Species = first(Species), 
            ID = str_c(ID, collapse="+"), 
             .groups = 'drop') %>% 
       select(-grp)
    # A tibble: 4 x 6
      Sepal.Length Sepal.Width Petal.Length Petal.Width Species ID       
             <dbl>       <dbl>        <dbl>       <dbl> <fct>   <chr>    
    1          5          3.25          2.8         0.4 setosa  ID_1+ID_2
    2          4.7        3.2           1.3         0.2 setosa  ID_3     
    3          4.6        3.1           1.5         0.2 setosa  ID_4     
    4          5          3.6           1.4         0.2 setosa  ID_5     
    

    或者另一种选择是通过折叠 ID 或对fct_collapse 的兴趣来创建新关卡

    library(forcats)
    df1 %>%
       group_by(grp = fct_collapse(ID, other = c("ID_1", "ID_2"))) %>% 
       summarise(across(starts_with("Sepal"), mean), 
       across(starts_with("Petal"), sum), Species = first(Species), 
            ID = str_c(ID, collapse="+"), 
             .groups = 'drop') %>% 
       select(-grp)
    # A tibble: 4 x 6
      Sepal.Length Sepal.Width Petal.Length Petal.Width Species ID       
             <dbl>       <dbl>        <dbl>       <dbl> <fct>   <chr>    
    1          5          3.25          2.8         0.4 setosa  ID_1+ID_2
    2          4.7        3.2           1.3         0.2 setosa  ID_3     
    3          4.6        3.1           1.5         0.2 setosa  ID_4     
    4          5          3.6           1.4         0.2 setosa  ID_5     
    

    【讨论】:

      【解决方案2】:

      这是实现所需输出的一种方法:

      library(dplyr)
      df %>% 
          slice(1:2) %>% 
          mutate(across(1:4, mean),
                 ID = paste(ID[1], ID[2], sep = "+"),
                 across(3:4, sum)) %>% 
          slice(1) %>% 
          bind_rows(df) %>% 
          slice(c(1, 4:6))
      

      输出:

        Sepal.Length Sepal.Width Petal.Length Petal.Width Species        ID
      1          5.0        3.25          2.8         0.4  setosa ID_1+ID_2
      2          4.7        3.20          1.3         0.2  setosa      ID_3
      3          4.6        3.10          1.5         0.2  setosa      ID_4
      4          5.0        3.60          1.4         0.2  setosa      ID_5
      

      【讨论】:

      • 这行得通;但是,因此需要知道行索引。那么,如果事先不知道这一点怎么办,例如只是 ID_x 和 ID_y 需要折叠(并且 ID_x 可能是第 3 行,ID_y 在第 20 行)。那么 slice() 可能不是很方便(?)
      猜你喜欢
      • 2013-12-13
      • 2017-09-16
      • 2013-08-04
      • 2016-07-07
      • 2015-03-12
      • 2012-10-04
      • 1970-01-01
      • 2018-09-25
      • 2021-01-17
      相关资源
      最近更新 更多