我有一个数据集
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
首次超过指定限制的行。
对于此示例,对于5
的限制,dtf应减少为:
A 6
B 6
这是一个很好的方法吗?
非常感谢
答案 0 :(得分: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
答案 1 :(得分: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感觉更舒服。
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
根据您对某些答案的评论,似乎您的“价值”列可能不会像您的示例中那样进行排序,并且您的{{1}中还有其他列}}
以下是这些方案的两种备选方案,一种是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
其次,基础R的常见“分裂 - 应用 - 组合”方法:
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
答案 2 :(得分:2)
使用aggregate
的另一种方法:
> aggregate(value~id, dtf[dtf[,'value'] > 5,], min)
id value
1 A 6
2 B 6
这取决于要排序的元素,因为它将是min
答案 3 :(得分:2)
也可能是plyr
和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
答案 4 :(得分:1)
这取决于您的data.frame正在排序:
threshold <- 5
foo <- dtf[dtf$value>=threshold,]
foo[c(1,which(diff(as.numeric(as.factor(foo$id)))>0)),]