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

如何在Python中检测数据中的水平线(停滞段)

区分极值点与平坦段的实用方法

已经用scipy.signal.find_peaks()找到极值点后,可通过以下几种方法过滤掉平坦段的伪峰值:

1. 利用峰值突出度(Prominence)过滤

find_peaks()本身支持prominence参数,这是最直接的方式。平坦段内的伪峰值没有明显的垂直落差,突出度极低,设置最小突出度阈值即可过滤:

import numpy as np
from scipy.signal import find_peaks

# 示例数据(含平坦段)
x = np.linspace(0, 20, 1000)
y = np.sin(x) + np.where((x > 5) & (x < 7), 0.5, 0)

# 仅保留突出度≥0.2的极大值
peaks, props = find_peaks(y, prominence=0.2)
# 可通过props['prominences']查看每个峰值的突出度数值

突出度的定义是峰值到其左右两侧最低谷的垂直距离,真正的极值点会有显著大于平坦段伪峰值的突出度。

2. 基于斜率阈值过滤

平坦段的斜率接近0,通过计算极值点前后的一阶差分(斜率),判断是否有明显的上升-下降趋势:

# 先找到所有初始峰值
peaks, _ = find_peaks(y)
dy = np.diff(y)  # 计算相邻点的斜率
slope_threshold = 0.01  # 可根据数据尺度调整

valid_peaks = []
for p in peaks:
    if p == 0 or p == len(y)-1:
        continue
    # 峰值前应为上升斜率(正),峰值后应为下降斜率(负),且绝对值超过阈值
    if dy[p-1] > slope_threshold and dy[p] < -slope_threshold:
        valid_peaks.append(p)

valid_peaks = np.array(valid_peaks)

3. 窗口方差过滤

平坦段的数据波动极小,在极值点周围的滑动窗口内计算方差,低于阈值的判定为伪峰值:

window_size = 5
variance_threshold = 0.001

valid_peaks = []
for p in peaks:
    start = max(0, p - window_size)
    end = min(len(y), p + window_size)
    if np.var(y[start:end]) > variance_threshold:
        valid_peaks.append(p)

4. 预处理平滑数据

如果平坦段有噪声导致误判,先对数据做平滑处理,再找峰值:

from scipy.signal import savgol_filter

# 用Savitzky-Golay滤波器平滑数据(窗口长度和多项式阶数按需调整)
y_smoothed = savgol_filter(y, window_length=11, polyorder=2)
# 基于平滑后的数据找峰值
peaks, _ = find_peaks(y_smoothed, prominence=0.15)

实际使用时,建议组合多种方法(比如先平滑,再结合突出度和斜率阈值),能更精准地过滤平坦段伪峰值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:45:46