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

如何让孤立森林在差分峰值处检测异常而非首个触发点

问题:孤立森林异常标记位置偏移的解决办法

我用孤立森林(Isolation Forest)在大型数据框里识别异常。数据存在噪声,所以执行了多项滤波操作去噪以凸显真实异常;随后对数据集使用.diff()生成异常发生时会出现峰值的序列,再用孤立森林识别异常。目前的问题是:孤立森林会在最早检测到异常的位置标记,而我需要它在差分峰值处标记异常。我尝试用.shift()手动调整,但仅对部分数据有效,且不愿调整平滑数据的窗口大小(这会严重影响精度)。

相关代码:

df["Ref Wt. Denoised"] = denoise(df["Ref Wt."].values, level=2)
df["Ref Wt. Savgol"] = apply_savgol_filter(df["Ref Wt. Denoised"], window_length=101, polyorder=3)
df["Ref Wt. Smoothed"] = df["Ref Wt. Savgol"].rolling(window=indexer).mean()
df["Ref Wt. Diff"] = df["Ref Wt. Smoothed"].diff(periods=300).fillna(0)

df["WOB Anomaly"] = detect_wob.predict(df["Ref Wt. Diff"].values.reshape(-1, 1))

df["WOB Zero Event"] = df["WOB Anomaly"] == -1

问题及期望修复效果见示意图(原链接已移除)

解决思路

核心是让异常标记和差分峰值位置对齐,不用手动调shift或修改平滑窗口,试试以下几种方案:

1. 先定位差分峰值,再映射异常标记

先找出差分序列的峰值位置,再把孤立森林检测到的异常映射到最近的峰值上:

import numpy as np

# 识别差分序列的局部峰值(可根据数据调整阈值和判断逻辑)
def find_local_peaks(arr, threshold=0):
    peaks = []
    for i in range(1, len(arr)-1):
        if arr[i] > arr[i-1] and arr[i] > arr[i+1] and arr[i] > threshold:
            peaks.append(i)
    return peaks

# 获取差分序列的峰值索引
diff_peaks = find_local_peaks(df["Ref Wt. Diff"].values)

# 把孤立森林标记的异常位置,匹配到最近的峰值
anomaly_idx = df[df["WOB Zero Event"]].index.tolist()
aligned_anomalies = [min(diff_peaks, key=lambda x: abs(x - idx)) for idx in anomaly_idx]

# 更新对齐后的异常标记列
df["WOB Zero Event Aligned"] = False
df.loc[aligned_anomalies, "WOB Zero Event Aligned"] = True

2. 给模型添加峰值位置特征

如果孤立森林误判是因为单特征信息不足,试试同时输入差分序列和滑动窗口内的峰值相对位置特征,让模型更关注峰值区域:

# 添加滑动窗口内差分最大值的相对位置特征(窗口大小可根据diff的periods=300调整)
window_size = 500
df["Diff Peak_Rel_Pos"] = df["Ref Wt. Diff"].rolling(window=window_size).apply(
    lambda x: x.argmax() - window_size//2  # 标记窗口内最大值相对中心的偏移
).fillna(0)

# 用多特征训练和预测
features = df[["Ref Wt. Diff", "Diff Peak_Rel_Pos"]].values
df["WOB Anomaly"] = detect_wob.predict(features)
df["WOB Zero Event"] = df["WOB Anomaly"] == -1

3. 先识别异常段,再在段内找峰值标记

不用孤立森林直接标记单个点,而是先识别连续的异常段,再在每个段内找出差分峰值作为最终标记点:

# 给连续的异常段分组
df["Anomaly_Segment_ID"] = (df["WOB Anomaly"] == -1).astype(int).diff().ne(0).cumsum()
anomaly_segments = df[df["WOB Anomaly"] == -1].groupby("Anomaly_Segment_ID")

# 每个异常段内取差分最大的位置作为标记
aligned_indices = []
for _, seg in anomaly_segments:
    peak_idx = seg["Ref Wt. Diff"].idxmax()
    aligned_indices.append(peak_idx)

df["WOB Zero Event Aligned"] = False
df.loc[aligned_indices, "WOB Zero Event Aligned"] = True

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 19:55:16