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

基于条件忽略行的特定值连续运行计数器构建(R语言)

问题解决:基于规则的连续组计数与行过滤

原始数据集

# A tibble: 987 × 2
   time   counts
   <time> <chr> 
 1 07:33  1358  
 2 07:34  1072  
 3 07:35  112   
 4 07:36  316   
 5 07:37  0     
 6 07:38  16    
 7 07:39  32    
 8 07:40  0     
 9 07:41  0     
10 07:42  92    
# … with 977 more rows

需求说明

  • 创建counter变量:为连续运行的组分配唯一值,当counts等于0时重置计数
  • 规则化标记“视为0”的行:
    • 若counts == 0的行后紧跟2行counts < 100,这2行需当作0处理
    • 若counts == 0的行后紧跟1行counts > 1000,这行需当作0处理
  • 最终目标:删除包含上述“视为0”行在内的连续60行及以上的0值行

已尝试的代码

用rleid分组(无法处理规则化“视为0”的行)

db %>% 
  mutate(consec_id = rleid(counts==0))

循环实现(未得到预期结果)

# Loop through the dataset and update the "wear_status" variable
for (i in 2:nrow(day1)) {
  # Check if current counts = 0
  if (db$counts[i] == 0) {
    consec_counts <- 0
    db$wear_status[i] <- 0
  } else {
    # Check if current counts are between 1 and 100
    if (db$counts[i] > 1 || db$counts[i] < 100) {
      consec_counts <- consec_counts + 1
    } else {
      consec_counts <- 0
    }
    # Check if current counts > 100 or 3 consecutive rows of counts = 1 or 100
    if (db$counts[i] > 100 || consec_counts <= 2) {
      consec_counts <- 0
      db$wear_status[i] <- 1
    }
  }
}

预期输出

# A tibble: 987 × 3
   time   counts counter
   <time> <chr>     <dbl>
 1 07:33  1358         1
 2 07:34  1072         1
 3 07:35  112          1
 4 07:36  316          1
 5 07:37  0            2
 6 07:38  16           2
 7 07:39  32           2
 8 07:40  0            2
 9 07:41  0            2
10 07:42  92           3
11 07:43  80           3
12 07:44  78           3
13 07:45  0            4
# … with 977 more rows

解决方案

使用dplyr结合data.table::rleid实现规则标记与分组,步骤如下:

1. 加载依赖包

library(dplyr)
library(data.table) # 用于rleid函数,也可替换为dplyr::consecutive_id

2. 数据处理与分组代码

db_clean <- db %>%
  # 先将字符型counts转为数值型,方便计算
  mutate(counts_num = as.numeric(counts)) %>%
  # 标记原始0值行
  mutate(is_raw_zero = counts_num == 0) %>%
  # 标记需要视为0的行:
  # - 原始0值
  # - 前1/2行是原始0,且当前counts<100
  # - 前1行是原始0,且当前counts>1000
  mutate(
    prev1_raw_zero = lag(is_raw_zero, n = 1, default = FALSE),
    prev2_raw_zero = lag(is_raw_zero, n = 2, default = FALSE),
    treat_as_zero = is_raw_zero |
      ((prev1_raw_zero | prev2_raw_zero) & counts_num < 100) |
      (prev1_raw_zero & counts_num > 1000)
  ) %>%
  # 生成counter:非0组(不满足视为0规则)连续为同一组,切换时counter递增
  mutate(counter = rleid(!treat_as_zero)) %>%
  # 按counter分组,计算每组行数
  group_by(counter) %>%
  mutate(group_size = n()) %>%
  ungroup() %>%
  # 过滤掉连续60行及以上的视为0的组
  filter(!(treat_as_zero & group_size >= 60)) %>%
  # 保留需要的列
  select(time, counts, counter)

代码逻辑说明

  1. 类型转换:将字符型的counts转为数值型,避免字符比较的错误
  2. 规则标记:通过lag函数查看前1、2行是否为原始0值,结合当前行的counts值,标记出所有需要视为0的行
  3. 分组计数:用rleid对!treat_as_zero分组,连续的非0行(或不满足视为0规则的行)为同一组,每次状态切换时counter自动递增
  4. 过滤长序列:计算每组的行数,删除连续60行及以上的视为0的组

如果需要调整规则(比如仅针对连续紧跟的行),可修改treat_as_zero的判断条件,例如仅考虑连续0之后的行:

# 调整为仅标记连续0之后的1-2行满足条件的情况
db_clean <- db %>%
  mutate(counts_num = as.numeric(counts)) %>%
  mutate(zero_group = rleid(counts_num == 0)) %>%
  group_by(zero_group) %>%
  mutate(is_zero_group = first(counts_num == 0)) %>%
  ungroup() %>%
  mutate(prev_zero_group = ifelse(!is_zero_group, lag(zero_group), NA)) %>%
  group_by(prev_zero_group) %>%
  mutate(pos_after_zero = row_number()) %>%
  ungroup() %>%
  mutate(
    treat_as_zero = counts_num == 0 |
      (!is_zero_group & !is.na(prev_zero_group) & pos_after_zero %in% 1:2 & counts_num < 100) |
      (!is_zero_group & !is.na(prev_zero_group) & pos_after_zero == 1 & counts_num > 1000)
  ) %>%
  mutate(counter = rleid(!treat_as_zero)) %>%
  group_by(counter) %>%
  mutate(group_size = n()) %>%
  ungroup() %>%
  filter(!(treat_as_zero & group_size >= 60)) %>%
  select(time, counts, counter)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 16:15:40