如何基于二元分类列非连续值创建QAQC可疑点标记列
问题描述
我正在处理一个时间序列DataFrame,包含测量值列和基于阈值划分的二元分类列(值≥300为class a,<300为class b)。需要创建新列,标记被至少10个连续class b包围的class a观测,或被至少10个连续class a包围的class b观测,以此识别可疑点。
示例数据生成代码如下:
library(tidyverse) # 生成可复现的数据框: # 生成日期时间 datetime <- seq(lubridate::ymd_hm("2015-1-1 0:00"), lubridate::ymd_hm("2015-2-1 12:00"), by = "hour") # 生成测量值 value <- runif(n = 757, min = 100, max = 1000) # 创建数据框 df <- data.frame(datetime, value) # 基于绝对数值阈值生成分类列 df <- df %>% mutate(classification = dplyr::if_else(value >= 300, "class a", "class b"))
实际数据量更大,请问如何实现该需求?
解决方案
可以借助data.table的rleid()函数识别连续的分类块,再结合前后块的长度判断是否满足“被至少10个同类别包围”的条件,具体实现代码如下:
library(tidyverse) library(data.table) # 用于生成连续分组ID df <- df %>% # 为连续相同的分类分配唯一组ID mutate(group_id = data.table::rleid(classification)) %>% # 按组ID分组,计算每组的长度和对应分类 group_by(group_id) %>% mutate( group_length = n(), group_class = first(classification) ) %>% ungroup() %>% # 获取前后组的长度和分类信息 mutate( prev_group_len = lag(group_length), prev_group_cls = lag(group_class), next_group_len = lead(group_length), next_group_cls = lead(group_class) ) %>% # 标记可疑点:当前组仅1个观测,且前后组为同一分类,长度都≥10 mutate( is_suspicious = case_when( group_length == 1 & prev_group_cls == next_group_cls & prev_group_len >= 10 & next_group_len >= 10 ~ TRUE, TRUE ~ FALSE ) ) %>% # 可选:删除中间辅助列,保留核心数据列 select(-group_id, -group_length, -group_class, -prev_group_len, -prev_group_cls, -next_group_len, -next_group_cls)
逻辑说明
- 连续分组:
rleid()会为连续的相同分类生成递增的组ID,比如连续的class a会共享同一个ID,直到出现class b时ID自动加1,快速区分所有连续分类块。 - 组信息计算:按组ID分组后,计算每个块的长度(连续观测数)和对应分类,为后续判断提供基础。
- 前后组判断:用
lag()和lead()获取当前组的前、后组信息,判断当前组是否是孤立的单个异类,且前后组都是长度≥10的同类别,满足条件则标记为可疑点。 - 效率适配:该方法基于向量操作和分组计算,处理大规模时间序列数据时效率较高,适合你的实际场景。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

