3

我有一个数据集

dtf<-data.frame(id=c("A","A","A","A","B","B","B","B"), value=c(2,4,6,8,4,6,8,10))

对于每个 id,值按升序排序

我想减少 dtf 以仅包含每个id值超过指定限制的第一行。每行只有一行id,那应该是第一个value超过指定限制的行。

对于这个例子和5dtf 的限制应该减少到:

A 6
B 6

这是一个很好的方法吗?

非常感谢

4

5 回答 5

5

可以通过以下方式完成aggregate

dtf<-data.frame(id=c("A","A","A","A","B","B","B","B"), value=c(2,4,6,8,4,6,8,10))

limit <- 5

aggregate(value ~ id, dtf, function(x) x[x > limit][1])

结果:

  id value
1  A     6
2  B     6

更新:多列的解决方案:

一个示例数据框dtf2

dtf2 <- data.frame(id=c("A","A","A","A","B","B","B","B"), 
                   value=c(2,4,6,8,4,6,8,10),
                   col3 = letters[1:8],
                   col4 = 1:8)

解决方案包括ave

with(dtf2, dtf2[ave(value, id, FUN = function(x) cumsum(x > limit)) == 1, ])

结果:

  id value col3 col4
3  A     6    c    3
6  B     6    f    6
于 2012-12-22T18:18:40.457 回答
4

这是一个“不错”的选项,使用data.table

library(data.table)
DT <- data.table(dft, key = "id")

DT[value > 5, head(.SD, 1), by = key(DT)]
#    id value
# 1:  A     6
# 2:  B     6

而且,本着分享的精神,sqldf根据您是否对 SQL 感觉更舒服,使用 which 的选项可能会更好。

sqldf("select id, min(value) as value from dtf where value > 5 group by id")
#   id value
# 1  A     6
# 2  B     6

更新:无序的源数据,以及data.frame多列

根据您对某些答案的评论,您的“价值”列可能不像您的示例中那样排序,并且您的data.frame.

对于这些场景,这里有两种替代方案,一种是data.table,我发现它最容易阅读并且很可能是最快的,另一种是这种任务通常需要的典型“拆分-应用-组合”方法。

首先,一些示例数据:

dtf2 <- data.frame(id = c("A","A","A","A","B","B","B","B"),
                   value = c(6,4,2,8,4,10,8,6),
                   col3 = letters[1:8],
                   col4 = 1:8)
dtf2 # Notice that the value column is not ordered
#   id value col3 col4
# 1  A     6    a    1
# 2  A     4    b    2
# 3  A     2    c    3
# 4  A     8    d    4
# 5  B     4    e    5
# 6  B    10    f    6
# 7  B     8    g    7
# 8  B     6    h    8

二、data.table做法:

library(data.table)
DT <- data.table(dtf2)
DT # Verify that the data are not ordered
#    id value col3 col4
# 1:  A     6    a    1
# 2:  A     4    b    2
# 3:  A     2    c    3
# 4:  A     8    d    4
# 5:  B     4    e    5
# 6:  B    10    f    6
# 7:  B     8    g    7
# 8:  B     6    h    8
DT[order(value)][value > 5, head(.SD, 1), by = "id"]
#    id value col3 col4
# 1:  A     6    a    1
# 2:  B     6    h    8

二、base R 常用的“split-apply-combine”方法:

do.call(rbind,
        lapply(split(dtf2, dtf2$id), 
               function(x) x[x$value > 5, ][which.min(x$value[x$value > 5]), ]))
#   id value col3 col4
# A  A     6    a    1
# B  B     6    h    8
于 2012-12-22T18:36:03.853 回答
2

另一种方法aggregate

> aggregate(value~id, dtf[dtf[,'value'] > 5,], min)
  id value
1  A     6
2  B     6

这确实取决于被排序的元素,因为这将是返回的条目min

于 2012-12-22T18:21:35.177 回答
2

plyr也可以用and替代head

library(plyr)
dtf<-data.frame(id=c("A","A","A","A","B","B","B","B"), value=c(2,4,6,8,4,6,8,10))
limit <- 5
result <- ddply(dtf, "id", function(x) head(x[x$value > limit ,],1) )


    > result
  id value
1  A     6
2  B     6
于 2012-12-22T18:54:40.880 回答
1

这取决于您的 data.frame 被排序:

threshold <- 5
foo <- dtf[dtf$value>=threshold,]
foo[c(1,which(diff(as.numeric(as.factor(foo$id)))>0)),]
于 2012-12-22T18:18:51.260 回答