Select 按因素水平排列
Select row by level of a factor
我有一个数据框 df2
,其中包含按 ID factor
分组的观察结果,我想对其进行子集化。我使用了另一个函数来确定我想要 select 每个因子组 中的哪些行 。如下所示 df
:
df <- data.frame(ID = c("A","B","C"),
pos = c(1,3,2))
df2 <- data.frame(ID = c(rep("A",5), rep("B",5), rep("C",5)),
obs = c(1:15))
在df
中,pos
对应于我想要select在ID
中提到的因子级别内的行的索引,而不是在整个数据框中df2
。我正在寻找一种方法 select 每个 ID
的行根据正确的索引(因此它们的行号在 df2
的每个因素的水平内).
所以,在这个例子中,我想 select df2
中的第一个值 ID == 'A'
,df2
中的第三个值 ID == 'B'
df2
和 ID == 'C'
.
中的第二个值
这会给我:
df3 <- data.frame(ID = c("A", "B", "C"),
obs = c(1, 8, 12))
dplyr
library(dplyr)
merge(df,df2) %>%
group_by(ID) %>%
filter(row_number() == pos) %>%
select(-pos)
# ID obs
# 1 A 1
# 2 B 8
# 3 C 12
基础 R
df2m <- merge(df,df2)
do.call(rbind,
by(df2m, df2m$ID, function(SD) SD[SD$pos[1], setdiff(names(SD),"pos")])
)
by
将合并后的数据帧df2m
拆分为df2m$ID
,并对每一部分进行操作;它 returns 会生成一个列表,因此最后它们必须 rbind
在一起。数据的每个子集(与 ID
的每个值相关联)由 pos
过滤并使用正常 data.frame 语法取消选择 "pos"
列。
data.table @DavidArenburg 在评论中建议
library(data.table)
setkey(setDT(df2),"ID")[df][,
.SD[pos[1L], !"pos", with=FALSE]
, by = ID]
第一部分——setkey(setDT(df2),"ID")[df]
——是合并。之后,将得到的table拆分为by = ID
,并对每个数据子集.SD
进行操作。 pos[1L]
以正常方式进行子集化,而 !"pos", with=FALSE
对应于删除 pos
列。
请参阅@eddi 的回答以获得更好的 data.table 方法。
这是基本的 R 解决方案:
df2$pos <- ave(df2$obs, df2$ID, FUN=seq_along)
merge(df, df2)
ID pos obs
1 A 1 1
2 B 3 8
3 C 2 12
如果df2
按ID
排序,你可以只对第一行做df2$pos <- sequence(table(df2$ID))
。
使用 data.table
版本 1.9.5+:
setDT(df2)[df, .SD[pos], by = .EACHI, on = 'ID']
合并 ID
列,然后为 df
的每一行选择 pos
行。
我有一个数据框 df2
,其中包含按 ID factor
分组的观察结果,我想对其进行子集化。我使用了另一个函数来确定我想要 select 每个因子组 中的哪些行 。如下所示 df
:
df <- data.frame(ID = c("A","B","C"),
pos = c(1,3,2))
df2 <- data.frame(ID = c(rep("A",5), rep("B",5), rep("C",5)),
obs = c(1:15))
在df
中,pos
对应于我想要select在ID
中提到的因子级别内的行的索引,而不是在整个数据框中df2
。我正在寻找一种方法 select 每个 ID
的行根据正确的索引(因此它们的行号在 df2
的每个因素的水平内).
所以,在这个例子中,我想 select df2
中的第一个值 ID == 'A'
,df2
中的第三个值 ID == 'B'
df2
和 ID == 'C'
.
这会给我:
df3 <- data.frame(ID = c("A", "B", "C"),
obs = c(1, 8, 12))
dplyr
library(dplyr)
merge(df,df2) %>%
group_by(ID) %>%
filter(row_number() == pos) %>%
select(-pos)
# ID obs
# 1 A 1
# 2 B 8
# 3 C 12
基础 R
df2m <- merge(df,df2)
do.call(rbind,
by(df2m, df2m$ID, function(SD) SD[SD$pos[1], setdiff(names(SD),"pos")])
)
by
将合并后的数据帧df2m
拆分为df2m$ID
,并对每一部分进行操作;它 returns 会生成一个列表,因此最后它们必须 rbind
在一起。数据的每个子集(与 ID
的每个值相关联)由 pos
过滤并使用正常 data.frame 语法取消选择 "pos"
列。
data.table @DavidArenburg 在评论中建议
library(data.table)
setkey(setDT(df2),"ID")[df][,
.SD[pos[1L], !"pos", with=FALSE]
, by = ID]
第一部分——setkey(setDT(df2),"ID")[df]
——是合并。之后,将得到的table拆分为by = ID
,并对每个数据子集.SD
进行操作。 pos[1L]
以正常方式进行子集化,而 !"pos", with=FALSE
对应于删除 pos
列。
请参阅@eddi 的回答以获得更好的 data.table 方法。
这是基本的 R 解决方案:
df2$pos <- ave(df2$obs, df2$ID, FUN=seq_along)
merge(df, df2)
ID pos obs
1 A 1 1
2 B 3 8
3 C 2 12
如果df2
按ID
排序,你可以只对第一行做df2$pos <- sequence(table(df2$ID))
。
使用 data.table
版本 1.9.5+:
setDT(df2)[df, .SD[pos], by = .EACHI, on = 'ID']
合并 ID
列,然后为 df
的每一行选择 pos
行。