异常值平滑与检测必须联动:滚动窗口需设center=true、min_periods≥3并预处理nan,孤立森林须基于滑动窗口特征矩阵训练,contamination依差分分位数动态设定,平滑仅限确认异常点且用邻域中位数替代。

直接说结论:别先平滑再检测,也别只用孤立森林硬打——异常值平滑必须和检测联动,且滚动窗口的边界处理、min_periods 设置、孤立森林的 contamination 与 max_samples 配合,三者缺一不可。
滚动窗口平滑前必须处理 NaN 和边界对齐问题
用 pd.Series.rolling(window=5).mean() 直接平滑时,前 4 个点全是 NaN,后续异常检测(比如 IsolationForest)会因缺失值报错或跳过。更隐蔽的问题是:滚动均值默认使用左对齐窗口(即 closed='left'),导致第 5 个点的平滑值实际依赖索引 0–4,但你真正想评估的是“当前点是否偏离其局部邻域”,所以该用 closed='both' 或显式设 center=True。
实操建议:
- 先用
fillna(method='ffill')或interpolate()填补原始序列的已知缺失,避免滚动计算中途中断 - 平滑时强制指定
center=True,让每个输出值对齐原时间点,例如:ts.rolling(window=7, center=True).mean() - 务必设置
min_periods=3(而非默认None),否则窗口内只要有一个NaN就整个返回NaN,尤其在首尾段会大面积丢失数据
孤立森林不能直接喂原始时序,得构造特征矩阵
IsolationForest 是无监督模型,输入必须是二维数组——但时间序列是一维的。常见错误是把 ts.values.reshape(-1, 1) 直接丢进去,这会让模型只看单点绝对值大小,完全忽略时序上下文(比如一个缓慢上升趋势中的中等值,在绝对值上不异常,但斜率突变就是异常)。
正确做法是构造滑动窗口特征:
- 取窗口长度
n_lag=5,生成特征矩阵X = np.array([ts[i:i+n_lag] for i in range(len(ts)-n_lag)]) - 每行代表“过去 5 个点的局部模式”,模型才能识别出“本该平稳却突然翘起”这类结构异常
-
contamination别设固定0.1;先用ts.diff().abs().quantile(0.99)看下变化剧烈程度,若差分 99% 分位数很小,说明噪声低,contamination可压到0.02~0.05
平滑动作要区分“替换”和“修正”,且仅作用于确认异常的点
很多代码一上来就 ts_smoothed = ts.rolling(...).mean() 全量覆盖,结果把真实突变(如设备启停、促销爆发)也抹平了。真正的平滑应是“条件性修补”:只对被孤立森林标记为异常的索引位置,用局部统计量替代。
推荐组合策略:
- 对每个异常点
i,取邻域ts[max(0,i-3):min(len(ts),i+4)],剔除其中已被标记的其他异常点(防污染) - 用剩余点的
median()替代ts[i](中位数比均值抗干扰) - 如果邻域内有效点少于 3 个,退回到线性插值:
ts.interpolate(method='linear').loc[i] - 绝对不要用
rolling().mean()输出直接赋值——它本身不含异常判断逻辑,只是数学变换
Pandas 2.0 的 rolling 默认行为已变,axis 和 closed 必须显式声明
Pandas 2.0 中 rolling 对 Series 的 axis 默认仍是 0,但如果你后续 concat 多列或转 DataFrame,closed 参数不再默认 'right',而是引发 FutureWarning。不处理的话,2.1 版本会直接报错。
关键细节:
- 始终写全参数:
ts.rolling(window=5, closed='both', center=True, min_periods=2) - 若需保留原始索引对齐(比如做前后对比),加
method='single'不生效,正确方式是用ts.rolling(...).apply(lambda x: x.mean(), raw=True) -
raw=True能提速 3–5 倍,尤其在窗口大、序列长时;但注意它传入的是 numpy 数组,np.nanmean比x.mean()更安全
最易被忽略的一点:孤立森林的 random_state 必须固定,否则每次运行结果不同,你无法复现“哪些点被平滑”;而滚动窗口的 min_periods 若设得太小(如 1),首尾段会用极少量数据算均值,放大噪声而非抑制它。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











