按分组变量维护顺序过滤

时间:2018-12-12 08:49:40

标签: r dplyr

我有一个数据框:

df <- data.frame(
        Group=c('A','A','A','A','B','B','B','B'),
        Activity = c('EOSP','NOR','EOSP','COSP','NOR','EOSP','WL','NOR'),
        TimeLine=c(1,2,3,4,1,2,3,4)
      )

我只想针对每个组 过滤两个活动,并按照我过滤的顺序进行过滤。例如,我只在搜索活动EOSPNOR,但顺序也是如此。这段代码:

df %>% group_by(Group) %>% 
        filter(all(c('EOSP','NOR') %in% Activity) & Activity %in% c('EOSP','NOR'))

导致:

# A tibble: 6 x 3
# Groups:   Group [2]
  Group Activity TimeLine
  <fct> <fct>       <dbl>
1 A     EOSP            1
2 A     NOR             2
3 A     EOSP            3
4 B     NOR             1
5 B     EOSP            2
6 B     NOR             4

我不希望第3行,因为EOSPNOR之后出现。同样,对于B组,我也不需要第4行,因为NOR发生在EOSP之前。我该如何实现?

3 个答案:

答案 0 :(得分:3)

您可以使用match获取Activity == EOSP的第一个实例,并使用slice删除之前的所有内容。完成此操作后,您就可以删除重复项并在EOSPNOR(即

)上进行过滤
library(tidyverse)

df %>% 
 group_by(Group) %>% 
 mutate(new = match('EOSP', Activity)) %>% 
 slice(new:n()) %>% 
 distinct(Activity, .keep_all = TRUE) %>% 
 filter(Activity %in% c('EOSP', 'NOR'))

给出,

# A tibble: 4 x 4
# Groups:   Group [2]
  Group Activity TimeLine   new
  <fct> <fct>       <dbl> <int>
1 A     EOSP            1     1
2 A     NOR             2     1
3 B     EOSP            2     2
4 B     NOR             4     2

注释1:您可以ungroup()select(-new)

注意2:此处发出警告消息

  

(警告消息:   1:在new:4L中:数值表达式包含4个元素:仅第一个使用   2:在new:4L中:数值表达式包含4个元素:仅第一个使用   )

不影响我们,因为我们都只需要第一个元素就可以使用

答案 1 :(得分:3)

这是软件包的一个选项:您将df与自身结合在一起,对其进行了子集化,仅保留EOSP Activity并计算TimeLine的最小值按组划分,则只能保留TimeLine大于或等于此TimeLine的行,以确保仅在之前有NOR时保留EOSP。然后,如果每个组只保留2个活动,则删除重复的“组”和“活动”:

df[df[Activity=="EOSP", min(TimeLine), by=Group], on="Group"][Activity %in% c("NOR", "EOSP") & TimeLine >= V1][!duplicated(paste(Group, Activity))]

#   Group Activity TimeLine V1
#1:     A     EOSP        1  1
#2:     A      NOR        2  1
#3:     B     EOSP        2  2
#4:     B      NOR        4  2

答案 2 :(得分:1)

这是一个dplyr的想法:

df %>%
  filter(Activity %in% c('EOSP','NOR')) %>%
  group_by(Group) %>%
  mutate(tmp = which(Activity == 'EOSP' & !duplicated(Activity))) %>%
  filter(row_number() %in%  c(tmp, tmp+1)) 

# A tibble: 4 x 4
# Groups:   Group [2]
  Group Activity TimeLine   tmp
  <fct> <fct>       <dbl> <int>
1 A     EOSP            1     1
2 A     NOR             2     1
3 B     EOSP            2     2
4 B     NOR             4     2