【问题标题】:R how to take top values by group until its sum exceeds a valueR如何按组取最高值,直到其总和超过一个值
【发布时间】:2014-09-14 03:25:07
【问题描述】:

我有一个这样的数据框

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

最好的方法是什么?

谢谢。

【问题讨论】:

  • 那么您能否为您的样本数据提供所需的输出?我真的很困惑结果应该是什么。
  • 假设如果组 a 小计一行的 11 变为 1000。而下一行是 0,那么,下一行 15 又是 1000。那么,你是说你想要最多 13 行?
  • @santoku 我更新了代码。我希望这对你有用

标签: r sum dataframe cumsum


【解决方案1】:

你也可以这样做:(使用有序的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

或者在订购的df上使用data.table

 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 

【讨论】:

  • 谢谢。我想使用第一种方法,但是,它不会返回总和超过该值的行,而是返回低于该值的行。
【解决方案2】:

这会拆分和限制数据框中的项目。下一行将选择最后一行:

> 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

【讨论】:

    【解决方案3】:

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

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-18
      • 2020-05-31
      • 2021-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-10
      相关资源
      最近更新 更多