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 对 "A"、select 这些行有观察结果
- 如果 ID 对 "B"、select 这些行有观察结果
- 如果 ID 对 "A" 和 "B" 都有观测值,select 只有具有 "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
如果适用,我还希望看到 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) V1
是 A
或 b) V1
是 B
并且 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
)
我有一个数据框,每个 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 对 "A"、select 这些行有观察结果
- 如果 ID 对 "B"、select 这些行有观察结果
- 如果 ID 对 "A" 和 "B" 都有观测值,select 只有具有 "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
如果适用,我还希望看到 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) V1
是 A
或 b) V1
是 B
并且 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
)