这是我正在处理的数据帧的示例:
id string
1 no
1 yes
1 yes
2 no
2 yes
3 yes
3 yes
3 no
我想提取最后两行包含字符串"yes"
列string
的id
。
所以结果将是:
id string
1 yes
1 yes
而且我只有一个id
1
.
我尝试使用 for 循环执行此操作,但由于我有超过 200 000 行,循环花费了太多时间:超过 5 分钟。
我试过这个:
vec_id <- unique(df$id)
for(id in vec_id){
if( tail(df[which(df$id == id),"string"])[1] & tail(df[which(df$id == id),"string"])[2] ){
vec_id <- append(vec_id, id)
}
有什么功能或方法可以更快地完成此任务吗?
我们可以使用data.table
. 将"data.frame"转换为"data.table"(setDT(df1)
(,按"id"分组,if
all
最后两个观察中的"字符串"是",则得到最后两个"字符串"(使用tail
(。
library(data.table)
setDT(df1)[, if(all(tail(string,2)=="yes")) .(string = tail(string,2)) , id]
# id string
#1: 1 yes
#2: 1 yes
注意:数据表语法通常data.table[i, j, by]
。
一个基本的 R 替代方案是使用 split
和 lapply
(带 unlist
(来构造一个可用于执行行子集的逻辑向量:
dropper <- unlist(lapply(split(df$string, df$id),
FUN=function(i) c(rep(FALSE, length(i) - 2),
rep(all(tail(i, 2) =="yes"), 2))),
use.names=FALSE)
dropper
FALSE TRUE TRUE FALSE FALSE FALSE FALSE FALSE
在这里,split
通过 df$id
将df$string
拆分为一个列表,该列表由 lapply
馈送到匿名函数。该函数为前 n-2 个元素返回 FALSE,然后为最后两个元素返回 TRUE TRUE 或 FALSE FALSE,具体取决于它们是否都是"是"。
然后使用向量删除不需要的观测值。
df[dropper,]
id string
2 1 yes
3 1 yes