R如何按组取最高值,直到其总和超过一个值

时间:2014-09-14 03:25:07

标签: r sum dataframe cumsum

我有一个像这样的数据框

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

这样做的最佳方式是什么?

感谢。

3 个答案:

答案 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