有条件地从数据框中删除行(多个条件)

6

我在SO上搜索了许多有关条件删除行的QA,但是没有一个适合我的问题。

我有一个data.frame,其中包含变量xy等的纵向测量值,以及各个时间点time和几个主题id。一些主题在某个time经历了一个事件ev(表示为1,否则为0)。我想将初始的data.frame减少为:

  • 1)所有未经历事件的主题行(好的,那很容易),还要包括
  • 2)对于经历了事件的主题,所有在事件之前的行(即所有时间小于该主题事件的时间的行)。

如此,

testdf<-data.frame(id=c(rep("A",4),rep("B",4),rep("C",4) ),
                   x=c(NA, NA, 1,2, 3, NA, NA, 1, 2, NA,NA, 5), 
                   y=rev(c(NA, NA, 1,2, 3, NA, NA, 1, 2, NA,NA, 5)),
                   time=c(1,2,3,4,0.1,0.5,10,20,3,2,1,0.5),
                   ev=c(0,0,0,0,0,1,0,0,0,0,0,1))

会减少至
   id  x  y time ev
1   A NA  5  1.0  0
2   A NA NA  2.0  0
3   A  1 NA  3.0  0
4   A  2  2  4.0  0
5   B  3  1  0.1  0
6   C  2  2  3.0  0
7   C NA  1  2.0  0
8   C NA NA  1.0  0

1
请注意,条件2意味着条件1,如果将条件2写为“事件之前的所有行”。 - Matthew Lundberg
4个回答

4
一种基本解决方案:
> do.call(rbind, by(testdf, testdf$id, function(x) x[cumsum(x$ev) == 0,]))
     id  x  y time ev
A.1   A NA  5  1.0  0
A.2   A NA NA  2.0  0
A.3   A  1 NA  3.0  0
A.4   A  2  2  4.0  0
B     B  3  1  0.1  0
C.9   C  2  2  3.0  0
C.10  C NA  1  2.0  0
C.11  C NA NA  1.0  0

4
或者,testdf[with(testdf, ave(ev, id, FUN = cumsum)) == 0, ] 的意思是在DataFrame中选择ev列累加之和为零的行,并根据id列进行分组。 - A5C1D2H2I1M1N2O1R2T1

4
这里有一个使用“subset”和“ave”的解决方案:
subset(testdf, !ave(ev, id, FUN = cumsum))

3
这个解决方案使用data.table,似乎可以在你的testdf上运行。其思路是使用cumsum来跟踪首个事件开始后的位置。
require(data.table)
dt <- data.table(testdf, key=c("id"))
dt.out <- dt[, .SD[cumsum(ev) == 0], by=id]
> dt.out

#    id  x  y time ev
# 1:  A NA  5  1.0  0
# 2:  A NA NA  2.0  0
# 3:  A  1 NA  3.0  0
# 4:  A  2  2  4.0  0
# 5:  B  3  1  0.1  0
# 6:  C  2  2  3.0  0
# 7:  C NA  1  2.0  0
# 8:  C NA NA  1.0  0

3

这里是一个例子:

> ddply(testdf, .(id), function(z) z[cumsum(z$ev) == 0, ])
  id  x  y time ev
1  A NA  5  1.0  0
2  A NA NA  2.0  0
3  A  1 NA  3.0  0
4  A  2  2  4.0  0
5  B  3  1  0.1  0
6  C  2  2  3.0  0
7  C NA  1  2.0  0
8  C NA NA  1.0  0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接