如何有条件地从数据框中删除行

时间:2012-02-29 14:40:23

标签: r

我有以下数据框

id<-c(1,1,1,1,2,2,2,2,3,3,3,3)
time<-c(0,1,2,3,0,1,2,3,0,1,2,3)
value<-c(1,1,6,1,2,6,2,2,1,1,6,1)

d<-data.frame(id, time, value)

每个ID只显示一次值6。对于每个id,我想删除时间大于值6的时间的所有行

我希望最终的数据框能够显示所有ID的所有观察结果,而不是“6”。对于具有“6”观察值的那些ID,我希望所有观察到的时间&lt;那次观察的时间。

我搜索了SO,关于条件行删除有几个问题(和答案),但我发现没有什么接近我需要的。

在上述情况下,最终数据框应为

  id time value
1   1    0     1
2   1    1     1
3   1    2     6
5   2    0     2
6   2    1     6
9   3    0     1
10  3    1     1
11  3    2     6

非常感谢。

3 个答案:

答案 0 :(得分:1)

为每个ID选择值6的时间:

mt <- d[d$value == 6, c("id","time")]
names(mt) <- c("id", "max.time")

合并d和mt以获得每个id的最大时间:

d <- merge(d,mt)

子集和清理:

d <- subset(d, time <= max.time)
d$max.time <- NULL

答案 1 :(得分:1)

这是使用plyr

建立安德烈的答案
library(plyr)
ddply(d, "id", function(x) subset(x, time <= x[x$value == 6, "time"]))
  id time value
1  1    0     1
2  1    1     1
3  1    2     6
4  2    0     2
5  2    1     6
6  3    0     1
7  3    1     1
8  3    2     6

更新以解释说明中的评论

样本数据集以匹配以下描述:

id<-c(1,1,1,1,2,2,2,2,3,3,3,3,4,4,4)
time<-c(0,1,2,3,0,1,2,3,0,1,2,3,3,2,1)
value<-c(1,1,6,1,2,6,2,2,1,1,6,1,1,2,3)
d<-data.frame(id, time, value)

在匿名函数中添加一些额外的检查:

ddply(d, "id", 
      function(x) {
        if (any(x$value == 6)) {
          subset(x, time <= x[x$value == 6, "time"])
        } else {
          x
        }
      }
)

检查结果

   id time value
1   1    0     1
2   1    1     1
3   1    2     6
4   2    0     2
5   2    1     6
6   3    0     1
7   3    1     1
8   3    2     6
9   4    3     1
10  4    2     2
11  4    1     3

答案 2 :(得分:0)

我不确定我是否理解您的选择方法6.如果用户已定义,则以下内容将为您提供所选行:

x <- max(d[d$value==6, 'time']) #find the max time associate with value =6
subset(d, time<=x)   #subset and select only time less than or = to 6

如果您希望自动化6的值,并且正在寻找所有ID的最大价值份额,那么我在这里做了一个令人费解的方式。任何时候你看到unlist通常我知道sapply将是一个betetr选择,可能是一个完整的其他方法,但不知道如何选择6这是我现在提出的:

y <- with(d, by(value, id, FUN=rle))
z <- lapply(seq_along(y), function(x) unlist(y[[x]][1])==1)
j <- lapply(seq_along(y), function(x) unlist(y[[x]][2])[z[[x]]])
mv <- max(as.numeric(as.character(unlist(subset(data.frame(table(unlist(j))), 
    Freq==length(j))['Var1']))))

x <- max(d[d$value==mv, 'time'])
subset(d, time<=x)