按值选择多个观察值

时间:2015-08-08 13:08:37

标签: r dataframe dplyr

我有一个数据框,每个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

现在我想以下列方式选择每个ID的所有行:

  • 如果ID对&#34; A&#34;有观察,请选择这些行
  • 如果ID对&#34; B&#34;有观察,请选择这些行
  • 如果ID对两者都有观察结果&#34; A&#34;和&#34; B&#34;,只选择&#34; A&#34;

在我的例子中,我想要这个:

    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解决方案。

2 个答案:

答案 0 :(得分:3)

以下是dplyr的一个选项。我们按照ID&#39;分组列,filter具有&#39; A&#39;的行或者&#39; B&#39;行,再做filter来检查&#39; V1&#39;中的唯一元素的数量。 (n_distinct(V1))。如果它大于1,则元素是&#39; A&#39;我们选择它(n_distinct(V1)>1 & V1=='A')或我们选择所有独特元素的长度为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来修改版本。我们检查&#39; V1&#39;中是否有独特元素的数量。大于1,如果没有元素是&#39; A&#39; (all(V1!='A'))如果元素是&#39; B&#39;,我们选择该行,或者如果不同元素的数量大于1并且有一个&#39; A&#39;在其中的元素,选择该行或如果唯一元素的数量是1并且该元素是&#39; A&#39;或者&#39; B&#39;,选择行。

 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的帖子)。我们将&#39; ID&#39;和filter分组为V1和&#39; A&#39;行或&#39; B&#39;没有任何&#39; A&#39;行。

 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

答案 1 :(得分:2)

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 A V1中没有其他ID元素(即by ID); $V1提取这些索引并将其传递回外部df

(我们提取V1可能会让人感到困惑,因为原始表中有一列名为V1,但我们提取的V1不同;要看到这一点,请考虑这个替代方案我们在哪里命名结果变量:

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

在这里,我们将索引变量命名为ind,因此我们必须提取ind而不是V1