信号异常值过滤:如何提取核心趋势信号?
无硬编码阈值的时间序列异常值去除与趋势提取方案
1. 局部加权回归(LOWESS)
LOWESS通过对每个数据点附近的样本拟合局部线性回归,自动给邻域内的点分配不同权重——异常值会被赋予极低权重,不会干扰整体趋势,天然适配区间趋势差异大的场景,还能直接输出平滑后的趋势曲线,无需额外处理连续异常。
Python实现示例:
import numpy as np from statsmodels.nonparametric.smoothers_lowess import lowess # 假设已完成0值插值的信号数组为y,时间轴用索引数组x表示 x = np.arange(len(y)) # frac参数控制局部拟合的邻域比例,无需硬编码阈值 smoothed_trend = lowess(y, x, frac=0.1, return_sorted=False) # smoothed_trend即为去除异常后的核心趋势信号
frac可根据信号波动程度调整,数值越大平滑效果越强,全程无需手动设置异常判定阈值。
2. 滑动中位数滤波 + 局部离群因子(LOF)
滑动中位数本身对异常值鲁棒,再结合LOF基于局部密度检测异常点(无需依赖全局标准差),能精准定位连续异常并替换为中位数滤波后的合理值。
Python实现示例:
import numpy as np from sklearn.neighbors import LocalOutlierFactor from scipy.ndimage import median_filter # 预处理后的信号数组y window_size = 5 # 滑动窗口大小可根据信号周期调整,非硬编码阈值 # 先做滑动中位数滤波得到基准趋势 median_trend = median_filter(y, size=window_size) # 用LOF自动推断异常比例,无需手动设阈值 lof = LocalOutlierFactor(n_neighbors=window_size, contamination='auto') # 标记异常点(-1为异常,1为正常) outlier_labels = lof.fit_predict(y.reshape(-1, 1)) # 将异常点替换为中位数趋势值 cleaned_signal = np.where(outlier_labels == -1, median_trend, y)
3. 自适应核密度估计(KDE)局部异常替换
通过KDE估计每个点在局部邻域内的概率密度,密度远低于邻域平均的点判定为异常,替换为邻域内的密度加权均值,完全基于数据分布自适应,无需硬编码阈值。
Python实现示例:
import numpy as np from scipy.stats import gaussian_kde def kde_local_clean(y, window_size=7): cleaned = y.copy() for i in range(len(y)): # 取当前点的局部邻域 start = max(0, i - window_size//2) end = min(len(y), i + window_size//2 + 1) window = y[start:end] # 估计邻域的核密度 kde = gaussian_kde(window) # 基于局部密度分位数判定异常,无需硬编码绝对阈值 density = kde(y[i]) low_density_threshold = np.percentile(kde(window), 5) if density < low_density_threshold: # 用邻域密度加权均值替换异常点 weights = kde(window) cleaned[i] = np.average(window, weights=weights) return cleaned # 处理后的核心趋势信号 cleaned_signal = kde_local_clean(y)
内容的提问来源于stack exchange,提问作者Vincent
相关产品推荐
相关产品推荐

