在R的data.table中添加带最小阈值的累积求和列
基于data.table实现带最小阈值的累积求和
我有一个包含score列的data.table,score列是正负实数。需要新增sum列实现带最小阈值的累积求和:每一步计算的累积和若低于设定的最小阈值,则将其重置为该阈值,后续的累积求和从这个阈值开始计算。
尝试1:直接使用cumsum
dt <- data.table(score = c(10, -13, 8, -12, 6)) dt[, sum := cumsum(score)] print(dt)
输出结果(不符合预期,无阈值限制):
score sum 1: 10 10 2: -13 -3 3: 8 5 4: -12 -7 5: 6 -1
尝试2:直接替换低于阈值的累积和
min_value <- -3 dt[, sum := { temp_sum <- cumsum(score) temp_sum[temp_sum < min_value] <- min_value temp_sum }] print(dt)
输出结果(不符合预期,后续求和未基于重置后的阈值计算):
score sum 1: 10 10 2: -13 -3 3: 8 5 4: -12 -3 5: 6 -1 # 预期sum值为3
尝试3:参考方案的accumulate实现
sum_score <- function(thresh) { function(x) { purrr::accumulate(x, ~dplyr::if_else(.x<=thresh, .y, .x+.y)) } } dt[, sum := sum_score(-3)(score)] print(dt)
输出结果(不符合预期,逻辑错误:低于阈值时直接取当前score而非基于阈值相加):
score sum 1: 10 10 2: -13 -3 3: 8 8 4: -12 -4 5: 6 6
预期输出
score sum 1: 10 10 2: -13 -3 3: 8 5 4: -12 -3 5: 6 3
正确解决方案
核心是迭代累积计算,每一步先算出临时和,再判断是否低于阈值,若低于则重置为阈值,作为下一步的起始值。以下提供两种实现方式:
方案1:purrr::accumulate实现(推荐)
library(data.table) library(purrr) dt <- data.table(score = c(10, -13, 8, -12, 6)) min_value <- -3 dt[, sum := accumulate(score, function(prev, curr) { current_sum <- prev + curr max(current_sum, min_value) })] print(dt)
输出结果:
score sum 1: 10 10 2: -13 -3 3: 8 5 4: -12 -3 5: 6 3
方案2:基础R循环实现(无依赖)
library(data.table) dt <- data.table(score = c(10, -13, 8, -12, 6)) min_value <- -3 sum_vec <- numeric(nrow(dt)) sum_vec[1] <- max(dt$score[1], min_value) for (i in 2:nrow(dt)) { sum_vec[i] <- max(sum_vec[i-1] + dt$score[i], min_value) } dt[, sum := sum_vec] print(dt)
输出结果与方案1完全一致。
逻辑说明
- 第一步:取第一个
score与阈值的较大值作为初始累积和 - 后续每一步:计算
前一步累积和 + 当前score得到临时值 - 用
max()函数判断:若临时值低于阈值则取阈值,否则取临时值 - 确保后续所有累积计算都基于上一步的有效结果(正常累积和或阈值)
内容的提问来源于stack exchange,提问作者zhang
相关产品推荐
相关产品推荐

