-1

我有一个这样的数据框

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

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

谢谢。

4

3 回答 3

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 
于 2014-09-14T04:02:01.540 回答
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
于 2014-09-14T04:45:55.917 回答
-1

如果我理解正确,您想要每个组中的最大值,直到所有这些值的总和超过某个阈值。如果是这样,我认为这段代码会做到这一点

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
于 2014-09-14T03:59:22.083 回答