select 多个观察值

select multiple observations by value

我有一个数据框,每个 ID 都有多个观察值,如下所示:

编辑:更新数据框

df <- data.frame(ID=c(1,1,1,2,2,3,3,3,4), V1=c("A","B","C","A","A","B","B","C","A"),
             V2=rnorm(9))

> df
  ID V1          V2
1  1  A  1.57707547
2  1  B -0.76022296
3  1  C -0.82693346
4  2  A  1.80888747
5  2  A -0.53173950
6  3  B -1.18705727
7  3  B  0.04325324
8  3  C -0.33361802
9  4  A -0.02358198

现在我想按以下方式 select 每个 ID 的所有行:

在我的示例中,我想要这样:

    ID V1          V2
  1  1  A  1.57707547
  2  2  A  1.80888747
  3  2  A -0.53173950
  4  3  B -1.18705727
  5  3  B  0.04325324
  6  4  A -0.02358198

如果适用,我还希望看到 dplyr 解决方案。

这是 dplyr 的一个选项。我们按 'ID' 列分组,filter 具有 'A' 或 'B' 行的行,执行另一个 filter 以检查 [= 中唯一元素的数量30=](n_distinct(V1))。如果它大于 1,并且元素是 'A' 我们 select 它 (n_distinct(V1)>1 & V1=='A') 或者我们 select 所有唯一元素的长度都为 1。

 library(dplyr)
 df %>% 
    group_by(ID) %>% 
    filter(V1 %in% c('A', 'B'))%>%
    filter(n_distinct(V1)>1 & V1=='A'|n_distinct(V1)==1)
 #  ID V1          V2
 #1  1  A  1.57707547
 #2  2  A  1.80888747
 #3  2  A -0.53173950
 #4  3  B -1.18705727
 #5  3  B  0.04325324
 #6  4  A -0.02358198

也许我们可以使用单个 filter 的修改版本。我们检查 'V1' 中的唯一元素的数量是否大于 1,并且元素中的 none 是否为 'A' (all(V1!='A')) 以及元素是否为 'B', 我们 select 那行,或者如果不同元素的数量大于 1 并且其中有一个 'A' 元素,那么 select 那行或者如果唯一元素的数量是1 并且元素是 'A' 或 'B',select 行。

 df %>% 
   group_by(ID) %>% 
   filter(n_distinct(V1)>1 & all(V1 !='A') & V1=='B'|n_distinct(V1)>1 & 
            V1=='A' |n_distinct(V1)==1 & V1 %in% c('A', 'B') )
 #   ID V1          V2
 #1  1  A  1.57707547
 #2  2  A  1.80888747
 #3  2  A -0.53173950
 #4  3  B -1.18705727
 #5  3  B  0.04325324
 #6  4  A -0.02358198

或者更紧凑一点(灵感来自@MichaelChirico 的post)。我们按 'ID' 和 filter 分组,V1 有 'A' 行或 'B' 且没有任何 'A' 行。

 df %>%
     group_by(ID) %>%
     filter(V1=='A'|V1=='B'&!any(V1=='A'))
 #  ID V1          V2
 #1  1  A  1.57707547
 #2  2  A  1.80888747
 #3  2  A -0.53173950
 #4  3  B -1.18705727
 #5  3  B  0.04325324
 #6  4  A -0.02358198

data.table 中,这可以很容易地完成:

library(data.table); setDT(df)
df[df[,.I[V1=="A"|(V1=="B"&!"A"%in%unique(V1))],by=ID]$V1]

内部 df 调用选择索引 (.I),其中 a) V1A 或 b) V1B 并且 V1 中没有其他 A 元素对应于那个 ID (也就是说,这样做 by ID); $V1 提取这些索引并将它们传递回外部 df.

(我们提取V1可能会混淆,因为原来table中有一列叫V1,但我们提取的V1是不同的;到看到这个,考虑这个我们命名结果变量的替代方案:

df[df[,.(ind=.I[V1=="A"|(V1=="B"&!"A"%in%unique(V1))]),by=ID]$ind]

这里,我们将索引变量命名为ind,所以我们要提取ind而不是V1)