You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现基于累计和阈值的动态窗口滚动求和分组?

高效实现累计和阈值分组(data.table版)

针对大型数据集的amount列,需要按累计和达到阈值时分组的需求,以下是两种远快于逐行循环的实现方案:

示例数据

library(data.table)
dt <- data.table(amount = c(0.009288, 0.189386, 0.071265, 0.137387, 0.032742, 0.000003, 0.071265, 0.122247, 0.124920, 0.032743))
threshold <- 0.2

方案一:基于区间查找的矢量化方法

核心思路是先确定所有分组的阈值断点,再用findInterval一次性完成分组,避免逐行操作:

# 计算累计和
dt[, cum := cumsum(amount)]

# 生成分组断点
breaks <- numeric(0)
current_threshold <- threshold
max_cum <- dt[, max(cum)]

while (current_threshold <= max_cum) {
  # 找到当前阈值对应的第一个累计和位置
  current_break <- dt[cum >= current_threshold, cum][1]
  breaks <- c(breaks, current_break)
  # 更新下一组的阈值
  current_threshold <- current_break + threshold
}

# 补全断点首尾,用于findInterval
breaks <- c(0, breaks, Inf)
# 分配分组标识
dt[, indicator := findInterval(cum, breaks)]

方案二:基于组定位的快速循环

循环次数等于分组数(远小于数据行数),通过批量更新分组标识提升效率:

# 计算累计和
dt[, cum := cumsum(amount)]
dt[, indicator := 0]

current_group <- 1
current_threshold <- threshold
max_cum <- dt[, max(cum)]

while (current_threshold <= max_cum) {
  # 找到当前组的结束位置
  end_pos <- dt[cum >= current_threshold, which = TRUE][1]
  
  if (current_group == 1) {
    # 第一组从第1行开始
    dt[1:end_pos, indicator := current_group]
  } else {
    # 后续组从上一组结束位置的下一行开始
    last_end <- dt[indicator == current_group - 1, max(.I)]
    dt[(last_end + 1):end_pos, indicator := current_group]
  }
  
  # 更新阈值和组号
  current_threshold <- dt[end_pos, cum] + threshold
  current_group <- current_group + 1
}

# 处理最后一组未达到阈值的剩余行
dt[indicator == 0, indicator := current_group]

效果验证

两种方案最终生成的indicator列均为:1,1,1,2,2,2,2,3,3,4,符合需求。相比原逐行循环方案,大数据集下效率可提升数十至数百倍。

内容的提问来源于stack exchange,提问作者lewkiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:10:00