【问题标题】:Retaining observations inside a group_id that meet multiple conditions将满足多个条件的观察结果保留在 group_id 中
【发布时间】:2022-02-19 02:25:14
【问题描述】:

我正在尝试对一些数据进行排序,这些数据标有 id、group_id 和状态代码。这是一个例子:

library(tidyverse)
sample <- tibble(id = c(1:20),
                 group_id = c(rep(1,3),rep(4,4),rep(8,5),rep(13,3),rep(16,1),rep(17,1),rep(18,3)),
                 status_code = c("initial","initial","final","initial","initial","initial","sold","initial","initial","initial","initial","error",
                            "initial","initial","final","final","error","initial","final","final")
)


sample %>%
  head()

# A tibble: 6 x 3
     id group_id status_code 
  <int>    <dbl> <chr>  
1     1        1 initial
2     2        1 initial
3     3        1 final  
4     4        4 initial
5     5        4 initial
6     6        4 initial

我想做的是按group_id 对它们进行分组,并仅保留满足以下条件的观察结果:

  • 状态代码(最终、已售、错误)在group_id 中出现多次
  • “final”、“sold”或“error”出现不止一次

在我上面的例子中,group_id == 18 应该被过滤,因为代码“final”出现了两次。但这也应该是“最终”代码之一被替换为“已售”或“错误”的情况。

基本上,我希望能够轻松地拆分数据,如下所示:

# Conditions met
# A tibble: 3 x 3
     id group_id status_code
  <int>    <dbl> <chr>      
1    18       18 initial    
2    19       18 final      
3    20       18 final   

# Conditions not met
# A tibble: 17 x 3
      id group_id status_code
   <int>    <dbl> <chr>      
 1     1        1 initial    
 2     2        1 initial    
 3     3        1 final      
 4     4        4 initial    
 5     5        4 initial    
 6     6        4 initial    
 7     7        4 sold       
 8     8        8 initial    
 9     9        8 initial    
10    10        8 initial    
11    11        8 initial    
12    12        8 error      
13    13       13 initial    
14    14       13 initial    
15    15       13 final      
16    16       16 final      
17    17       17 error    

我的数据显然有更多的列,应该都保留在每个子帧中。到目前为止,我已经能够通过计数、保留 status_code 并再次过滤主要数据来实现这一点:

condition <- sample %>%
  filter(status_code != "initial") %>% # Removing "initial" status_code
  count(group_id) %>% # Counting the number of remaining occurences in each group
  filter(n > 1) %>% # Keeping groups where more than one occurence
  select(group_id) # Selecting the group_ids

fitlered_sample <- left_join(condition,sample, by ="group_id")

# A tibble: 3 x 3
  group_id    id status_code
     <dbl> <int> <chr>      
1       18    18 initial    
2       18    19 final      
3       18    20 final   

它有效,但我希望这可以在不创建“条件”数据框的情况下实现。我更喜欢 dplyr 解决方案,但我也可以使用 base 或 data.table

【问题讨论】:

    标签: r dplyr data.table tidyverse filtering


    【解决方案1】:

    我们可以通过 'group_id' 分组,然后 filter 计数 'status_code' 不等于 'initial'

    library(dplyr)
    sample %>% 
     group_by(group_id) %>%
     filter(sum(status_code != "initial") > 1) %>%
     ungroup
    

    其他数据

    sample %>% 
      group_by(group_id) %>% 
      filter(sum(status_code != "initial") == 1) %>%
      ungroup
    

    或者使用group_split创建一个list的数据集

    lst1 <- sample %>% 
     group_by(group_id) %>% 
     mutate(n = sum(status_code != "initial") != 1) %>% 
     ungroup %>% 
     group_split(n, .keep = FALSE)
    

    -输出

    lst1
    [[1]]
    # A tibble: 17 × 3
          id group_id status_code
       <int>    <dbl> <chr>      
     1     1        1 initial    
     2     2        1 initial    
     3     3        1 final      
     4     4        4 initial    
     5     5        4 initial    
     6     6        4 initial    
     7     7        4 sold       
     8     8        8 initial    
     9     9        8 initial    
    10    10        8 initial    
    11    11        8 initial    
    12    12        8 error      
    13    13       13 initial    
    14    14       13 initial    
    15    15       13 final      
    16    16       16 final      
    17    17       17 error      
    
    [[2]]
    # A tibble: 3 × 3
         id group_id status_code
      <int>    <dbl> <chr>      
    1    18       18 initial    
    2    19       18 final      
    3    20       18 final      
    

    【讨论】:

    • 谢谢!优雅的解决方案。我不知道你可以sum() filter() 条件。
    【解决方案2】:

    data.table:

    library(data.table)
    setDT(sample)
    
    sample[,.SD[sum(status_code=="final")>1|
                sum(status_code=="sold") >1|
                sum(status_code=="error")>1],
           by=group_id]
    
       group_id    id status_code
          <num> <int>      <char>
    1:       18    18     initial
    2:       18    19       final
    3:       18    20       final
    

    相反的:

    sample[,.SD[!(sum(status_code=="final")>1|
                  sum(status_code=="sold") >1|
                  sum(status_code=="error")>1)],
           by=group_id]
    
    
        group_id    id status_code
           <num> <int>      <char>
     1:        1     1     initial
     2:        1     2     initial
     3:        1     3       final
     4:        4     4     initial
     5:        4     5     initial
     6:        4     6     initial
     7:        4     7        sold
     8:        8     8     initial
     9:        8     9     initial
    10:        8    10     initial
    11:        8    11     initial
    12:        8    12       error
    13:       13    13     initial
    14:       13    14     initial
    15:       13    15       final
    16:       16    16       final
    17:       17    17       error
    
    

    【讨论】:

    • 谢谢!很高兴获得data.table 解决方案。查看@akrun 的解决方案,我建议:sample[,.SD[sum(status_code != "initial")&gt;1], by=group_id]
    • @James,如果你确认你只有这 4 个选项,这确实更短!
    • 是的,我没有说得很清楚。我可以有四个以上,但“初始”状态是我一直想摆脱的状态。
    猜你喜欢
    • 2016-01-29
    • 2014-10-09
    • 1970-01-01
    • 2020-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多