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

如何基于二元分类列非连续值创建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)

逻辑说明

  1. 连续分组:rleid()会为连续的相同分类生成递增的组ID,比如连续的class a会共享同一个ID,直到出现class b时ID自动加1,快速区分所有连续分类块。
  2. 组信息计算:按组ID分组后,计算每个块的长度(连续观测数)和对应分类,为后续判断提供基础。
  3. 前后组判断:用lag()和lead()获取当前组的前、后组信息,判断当前组是否是孤立的单个异类,且前后组都是长度≥10的同类别,满足条件则标记为可疑点。
  4. 效率适配:该方法基于向量操作和分组计算,处理大规模时间序列数据时效率较高,适合你的实际场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 16:41:09