我有一个像这样的数据框
set.seed(500)
df=data.frame(group=c(rep("A",20),rep("B",20),rep("C",20),rep("D",20)),value=round(runif(80,min=1,max=100)))
对于每个组,我想获取最高值行,直到它们的总和超过/达到目标值
target=data.frame(group=c("A","B","C","D"),value=c(1000,400,500,300))
并将新组输出为4个数据帧。
我将它们从最大到最小排序
df=df[with(df, order(group,-value)), ]
所需的输出是
group value
a 98
a 93
...
a (sum from 98 to here, the group a subtotal should exceed 1000)
b 93
...
c 99
这样做的最佳方式是什么?
感谢。
答案 0 :(得分:2)
你也可以这样做:(使用有序的df
)
indx <- rep(target$value, table(df$group))
val1 <- with(df, ave(value, group, FUN=cumsum))
df[val1 <=indx,]
# group value
#3 A 98
#8 A 93
#12 A 89
#1 A 84
#9 A 83
#5 A 81
#13 A 77
#2 A 73
#15 A 73
#10 A 71
#18 A 62
#19 A 61
#7 A 52
#39 B 93
#28 B 90
#36 B 84
#37 B 83
#52 C 99
#59 C 96
#45 C 86
#43 C 84
#58 C 81
#65 D 93
#75 D 87
#63 D 85
或在订购的data.table
df
library(data.table)
setkey(setDT(df), group)
setkey(setDT(target), group)
DT1 <- df[df[target, value1:= i.value][,
cumsum(value) <value1, by=group]$V1, 1:2, with=FALSE]
我想你想要这样的东西:
indx2 <- which(val1 <=indx)
indx3 <- unname(tapply(indx2,cumsum(c(TRUE,diff(indx2)!=1)), tail,1)+1)
df1 <- df[sort(c(indx2,indx3)),]
tapply(df1$value, df1$group, FUN=sum)
# A B C D
#1048 432 518 342
答案 1 :(得分:1)
这会拆分并限制数据框中的项目。下一个单行将选择最后一行:
> lapply( split(df, df[[1]] ) , function(d) d[ cumsum( d[[2]]) < 200 , ] )
$A
group value
1 A 84
2 A 73
$B
group value
21 B 9
22 B 81
23 B 5
24 B 54
25 B 28
$C
group value
41 C 20
42 C 43
43 C 84
44 C 49
$D
group value
61 D 4
62 D 77
63 D 85
然后使用tail
> lapply( split(df, df[[1]] ) , function(d) tail( d[ cumsum( d[[2]]) < 200 , ] ,1))
$A
group value
2 A 73
$B
group value
25 B 28
$C
group value
44 C 49
$D
group value
63 D 85
如果你想选择“最大值”,那么在进行求和之前订购数据帧:
> lapply( split(df[order(df[[2]], decreasing=TRUE), ] , df[[1]] ) , function(d) tail( d[ cumsum( d[[2]]) < 200 , ] ,1))
$A
group value
3 A 98
$B
group value
62 D 77
$C
group value
71 D 34
$D
group value
74 D 2
答案 2 :(得分:-1)
如果我理解正确,您希望得到每组中的最大值,直到所有thsoe值的总和超过某个阈值。如果是这样,我认为这段代码会做到这一点
newdfs<-Map(function(d, m) {
d <-d[order(-d$value), ]
d[cumsum(d$value) < m, ]
}, split(df, df$group), target$value[match(levels(df$group), target$group)])
newdfs
这会重新生成列表中的data.frames,这比创建一堆新的data.frames更好。如果要将结果合并到单个data.frame中,可以执行
do.call(rbind, newdfs)
获取
group value
A.3 A 98
A.8 A 93
A.12 A 89
A.1 A 84
A.9 A 83
A.5 A 81
A.13 A 77
A.2 A 73
A.15 A 73
A.10 A 71
A.18 A 62
A.19 A 61
A.7 A 52
B.39 B 93
B.28 B 90
B.36 B 84
B.37 B 83
C.52 C 99
C.59 C 96
C.45 C 86
C.43 C 84
C.58 C 81
D.65 D 93
D.75 D 87
D.63 D 85