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

如何用dplyr实现:累计值达阈值时保留行并重置累计

解决方案:用dplyr+purrr实现累计阈值触发的行保留逻辑

核心思路是通过状态跟踪式的累计计算,在每次累计值达到阈值时标记并保留当前行,同时重置累计计数;如果需要匹配你的预期输出,还可以强制保留最后一行(即使未达阈值)。

步骤1:加载依赖包

library(dplyr)
library(purrr)

步骤2:定义累计逻辑函数

这个函数会跟踪两个状态:当前累计和、是否保留当前行。当累计和达到阈值时,标记保留并重置累计;否则继续累计。

threshold <- 1 # 设定你的阈值

accumulate_logic <- function(current_state, x_val) {
  new_total <- current_state$total + x_val
  if (new_total >= threshold) {
    # 达到阈值:保留该行,重置累计为0
    list(total = 0, keep = TRUE)
  } else {
    # 未达阈值:不保留,继续累计
    list(total = new_total, keep = FALSE)
  }
}

步骤3:应用逻辑到数据集

全局累计(不按group分组)

如果需要按整个数据集的顺序累计:

result <- dat %>%
  # 生成累计标记
  mutate(
    # 用accumulate逐行计算状态,提取keep标记
    keep = accumulate(
      x, 
      accumulate_logic, 
      .init = list(total = 0, keep = FALSE) # 初始状态:累计0,不保留
    ) %>%
      map_lgl("keep") %>%
      tail(-1) # 去掉初始状态对应的第一个空值
  ) %>%
  # 强制保留最后一行(匹配你的预期输出,不需要可删除此步)
  mutate(keep = ifelse(row_number() == n(), TRUE, keep)) %>%
  # 过滤出保留的行
  filter(keep) %>%
  # 移除辅助列
  select(-keep)

print(result)

运行结果会和你给出的预期输出一致:

id group age    type           x
2   2     B  21  type 2 0.294720447
4   4     B  18  type 4 2.404653389
6   6     B  30  type 6 0.799009249
7   7     A  24  type 7 1.147657009
10 10     B  28 type 10 0.411510833

按group分组累计

如果需要在每个group内独立累计(比如A组和B组各自计算累计),只需添加group_by(group):

result_grouped <- dat %>%
  group_by(group) %>%
  mutate(
    keep = accumulate(
      x, 
      accumulate_logic, 
      .init = list(total = 0, keep = FALSE)
    ) %>%
      map_lgl("keep") %>%
      tail(-1)
  ) %>%
  mutate(keep = ifelse(row_number() == n(), TRUE, keep)) %>%
  filter(keep) %>%
  select(-keep) %>%
  ungroup()

print(result_grouped)

关键说明

  • accumulate函数是核心:它能逐行传递状态(累计和+保留标记),实现"累计-触发-重置"的循环逻辑,这是普通的cumsum做不到的。
  • 强制保留最后一行的逻辑是为了匹配你的预期输出,若业务不需要,可直接删除对应代码行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 06:05:20