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

R语言大样本数据:带豁免规则的连续0值区间识别需求

问题需求

我有按id分组的count数据(约1.5亿条观测),需要识别每个id下满足以下条件的区间:

  • 区间内至少有60行连续的count值为0
  • 允许区间内存在最多2行连续的count值介于0到100之间(即0 < count ≤ 100)

示例数据中id=1的区间符合要求,id=3的区间不符合。已用cumsum实现基础逻辑,但无法处理上述豁免规则,由于数据量庞大,优先采用data.table方案。

示例数据

test_df <- tibble::tibble(
  id = c(rep(1,100), rep(2,100), rep(3,100)),
  count = c(rep(0,2), 22,55, rep(0,69), 33,44,55,66,77, rep(0,22),
                rep(0,61), rep(250, 39), 
                rep(0,2), 22,55, 22,55, rep(0,94))
)

数据预览:

id count
   <dbl> <dbl>
 1     1     0
 2     1     0
 3     1    22
 4     1    55
 5     1     0
 6     1     0
 7     1     0

现有dplyr代码

library(dplyr)
test_df %>% 
  group_by(id) %>% 
  mutate(check = cumsum(c(F, abs(diff(count)) > 0))) %>% 
  group_by(id, check) %>% 
  mutate(create_identifier = ifelse((count == 0 & n() >= 60), 1,0)) 

解决方案(data.table)

核心思路

  1. 按count值给每行打分类标签:
    • 0:count == 0(合规行)
    • 1:0 < count ≤ 100(允许的豁免行,最多连续2行)
    • 2:count > 100(无效行,直接打断区间)
  2. 用rleid()按id和分类标签生成连续相同类型的块ID
  3. 汇总每个块的类型、长度和起止位置
  4. 在每个id内筛选符合条件的块序列:总合规行长度≥60,无无效块,且所有豁免块长度≤2
  5. 批量标记原始数据中符合条件的行

代码实现

library(data.table)

# 转换为data.table格式(处理大数据的基础)
setDT(test_df)

# 1. 给每行打分类标签
test_df[, type := fcase(
  count == 0, 0,
  count > 0 & count <= 100, 1,
  count > 100, 2
)]

# 2. 生成连续相同类型的块ID
test_df[, rl := rleid(type), by = id]

# 3. 汇总每个块的关键信息
block_summary <- test_df[, .(
  type = first(type),
  block_len = .N,
  start_row = .I[1],
  end_row = .I[.N]
), by = .(id, rl)]

# 4. 计算块序列的累积指标,筛选有效块组
block_summary[, `:=`(
  # 累积合规块(type=0)的总长度
  cum_valid_len = cumsum(ifelse(type == 0, block_len, 0)),
  # 标记是否出现过无效块(type=2)
  has_invalid = cumsum(ifelse(type == 2, 1, 0)) > 0,
  # 标记是否出现过长于2行的豁免块
  has_over_exempt = cumsum(ifelse(type == 1 & block_len > 2, 1, 0)) > 0
), by = id]

# 反向累积检查,确保后续块也没有无效内容
block_summary[, `:=`(
  reverse_has_invalid = rev(cumsum(rev(ifelse(type == 2, 1, 0)))) > 0,
  reverse_has_over_exempt = rev(cumsum(rev(ifelse(type == 1 & block_len > 2, 1, 0)))) > 0
), by = id]

# 筛选所有符合条件的块
valid_blocks <- block_summary[
  cum_valid_len >= 60 & !has_invalid & !has_over_exempt & !reverse_has_invalid & !reverse_has_over_exempt
]

# 5. 批量标记原始数据中的有效行
test_df[, is_valid := FALSE]
for (idx in seq_len(nrow(valid_blocks))) {
  test_df[valid_blocks$start_row[idx]:valid_blocks$end_row[idx], is_valid := TRUE]
}

# 查看结果示例
# test_df[id == 1, .(id, count, is_valid)]
# test_df[id == 3, .(id, count, is_valid)]

效率说明

  • data.table的fcase()和rleid()都是针对大数据优化的函数,比dplyr对应操作快数倍
  • 采用块级汇总而非逐行计算,避免了1.5亿行的循环操作,大幅提升效率
  • 最后通过块起止索引批量更新,减少内存开销

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 19:10:34