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

如何按异常值切分连续数据 pd.cut/pd.qcut无法得到目标结果

实现方法

pd.cut和pd.qcut是按固定数值间隔、分位数间隔做静态分箱的工具,没法识别序列里的异常跳变做连续段切分,要实现你的需求,核心逻辑是先识别b列的异常值,再按「正常/异常」的连续段对行分组,最后提取每组对应的a值区间,步骤如下:

1. 构造示例数据

import pandas as pd
import numpy as np

df = pd.DataFrame({'a': [1, 2, 3, 4, 5, 6, 7, 8, 9], 'b': [2, 2, 4, 3, 1000, 2000, 1, 500, 3]})

示例数据截图

2. 标记b列的异常值

如果有明确的业务阈值(比如已知b列正常值都在10以内,超过的就是异常),直接按阈值标记最准确:

# 按业务阈值标记异常,示例中b>10即为异常
df['is_outlier'] = df['b'] > 10

如果没有明确阈值,可以用鲁棒性更好的MAD(中位数绝对偏差)方法自动识别离群点,避免异常值本身干扰判断:

# 用MAD方法自动识别离群点
median = df['b'].median()
mad = np.median(np.abs(df['b'] - median))
# 3倍MAD为异常阈值,可根据实际场景调整
threshold = 3 * mad
df['is_outlier'] = np.abs(df['b'] - median) > threshold

3. 按连续段生成分组ID

相邻行的异常标记发生变化的位置就是切分点,对切分标记做累加即可得到每个连续段的组ID:

# 相邻行异常状态不一致时标记为切分点,累加生成组ID
df['group_id'] = (df['is_outlier'] != df['is_outlier'].shift(1)).cumsum()

处理后的数据分组结果和预期完全一致:索引0-3(a=14)为同组,索引4-5(a=56)为同组,索引6(a=7)、索引7(a=8)、索引8(a=9)各为一组。

4. 提取a列的切分区间

按组ID聚合a列的最小值、最大值,格式化输出即可:

# 聚合得到每组a的起止值
group_info = df.groupby('group_id')['a'].agg(min_val='min', max_val='max').reset_index(drop=True)

# 格式化区间
cut_ranges = []
for _, row in group_info.iterrows():
    if row['min_val'] == row['max_val']:
        cut_ranges.append(f"{int(row['min_val'])}")
    else:
        cut_ranges.append(f"{int(row['min_val'])}-{int(row['max_val'])}")

最终cut_ranges的输出为:

['1-4', '5-6', '7', '8', '9']

如果你的异常判断逻辑不是「b值本身过大/过小」,而是b值和前序值的跳变幅度异常,只需要把第二步的异常标记逻辑替换为跳变幅度计算即可,整体分组逻辑不变。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 17:21:26