【问题标题】:Arrange/sort grouped dataframe according to the lag(prior) group根据滞后(前)组排列/排序分组数据帧
【发布时间】:2021-11-24 04:08:30
【问题描述】:

我想根据 lag(=prior) 组中的变量对分组的 df 进行排列/排序。

Group 1应排在b之后,从a1a4

Group 2a应该按照Group 1b排列

Group 3a应该按照Group 2b排列

示例数据:

dat <- structure(list(group = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 
                                3L), a = c("new", "new", "new", "new", "a2", "a1", "a3", "b1", 
                                           "b3", "b2"), b = c("a2", "a4", "a3", "a1", "b1", "b2", "b3", 
                                                              "c", "c", "c")), class = "data.frame", row.names = c(NA, -10L
                                                              ))

dat1 <- structure(list(group = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 
                                 3L), a = c("new", "new", "new", "new", "a1", "a2", "a3", "b2", 
                                            "b1", "b3"), b = c("a1", "a2", "a3", "a4", "b2", "b1", "b3", 
                                                               "c", "c", "c")), class = "data.frame", row.names = c(NA, -10L
                                                               ))

初始数据

dat
#>    group   a  b
#> 1      1 new a2
#> 2      1 new a4
#> 3      1 new a3
#> 4      1 new a1
#> 5      2  a2 b1
#> 6      2  a1 b2
#> 7      2  a3 b3
#> 8      3  b1  c
#> 9      3  b3  c
#> 10     3  b2  c

期望的输出

dat1
#>    group   a  b
#> 1      1 new a1
#> 2      1 new a2
#> 3      1 new a3
#> 4      1 new a4
#> 5      2  a1 b2
#> 6      2  a2 b1
#> 7      2  a3 b3
#> 8      3  b2  c
#> 9      3  b1  c
#> 10     3  b3  c

dplyr 解决方案会更好。不过,我很感激每一个提示。

【问题讨论】:

  • “第 1 组应按照 b 的字母数字顺序排列”。在您想要的输出组中,第 1 组不是按照 b 的字母数字?还是我错过了什么?
  • 谢谢。在所需的输出组 1 应该是 a1 到 a4
  • 我不确定这是否可以通过dplyr 完成,而无需太多黑客攻击。如果每个组具有不同的自然顺序以及它们之间的关系,那么它们可能应该是 3 个独立的数据帧?
  • @DanChaltiel 感谢您的评论。只是为了我的理解,你能解释一下在这种情况下 3 个分离的数据帧背后的逻辑吗?谢谢。

标签: r sorting dplyr


【解决方案1】:
library(tidyverse)
dat <- structure(list(group = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 
 3L), a = c("new", "new", "new", "new", "a2", "a1", "a3", "b1", 
 "b3", "b2"), b = c("a2", "a4", "a3", "a1", "b1", "b2", "b3", 
 "c", "c", "c")), class = "data.frame", row.names = c(NA, -10L))


fArrange = function(data, group, unique_group){
  if(group$group!=unique_group[1]){
    data = data %>% 
      mutate(a = a %>% factor(lev_prev)) %>% 
      arrange(a) %>% 
      mutate(a = a %>% as.character())
  } else {
    data = data %>% arrange(b)
  }
  if(group$group!=unique_group[length(unique_group)]){
    lev_prev <<- data$b
  } else {rm(lev_prev, envir=globalenv())}
  data
}

dat %>% as_tibble() %>% 
  group_by(group) %>% 
  group_modify(~fArrange(.x, .y, unique(dat$group)))

输出

# A tibble: 10 x 3
# Groups:   group [3]
   group a     b    
   <int> <chr> <chr>
 1     1 new   a1   
 2     1 new   a2   
 3     1 new   a3   
 4     1 new   a4   
 5     2 a1    b2   
 6     2 a2    b1   
 7     2 a3    b3   
 8     3 b2    c    
 9     3 b1    c    
10     3 b3    c   

这里的关键是函数 fArrange,它在 Gcobal 环境中创建一个名为 lev_prev 的临时变量,用于存储前一组的级别。

【讨论】:

    【解决方案2】:

    以下是使用dplyr 执行此操作的基本过程: 逻辑:

    1. 创建包含组的列表
    2. 将条件应用于列表中的每个元素 (=group df)
    3. 将它们绑定在一起。
    library(dplyr)
    
    # create a list of dfs
    dat_list <- dat %>% 
      group_split(group)
    
    # apply condition to group 1
    dat_list_1  <- dat_list[[1]] %>% 
      arrange(b)
    
    # apply condition to group 2
    dat_list_2  <- dat_list[[2]] %>% 
      arrange(a[rank(dat_list_1[1:3,3], ties.method = "last")])
    
    # apply condition to group 3
    dat_list_3  <- dat_list[[3]] %>% 
      arrange(a[rank(dat_list_3[1:3,3], ties.method = "last")])
    
    # bind them all to resulting dataframe
    dat1 <- bind_rows(dat_list_1, dat_list_2, dat_list_3)
    

    输出:

       group a     b    
       <int> <chr> <chr>
     1     1 new   a1   
     2     1 new   a2   
     3     1 new   a3   
     4     1 new   a4   
     5     2 a1    b2   
     6     2 a2    b1   
     7     2 a3    b3   
     8     3 b2    c    
     9     3 b1    c    
    10     3 b3    c    
    

    【讨论】:

    • 感谢您的解决方案。我接受了 Marek 的回答,因为 group_modify 非常方便(我的真实数据有很多组)。
    猜你喜欢
    • 2021-04-06
    • 1970-01-01
    • 1970-01-01
    • 2013-10-31
    • 2020-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多