z-score离群检测需对数值列单独计算并设合理阈值,isolationforest适用于多维组合异常,去重不等于离群检测,应保留标签并记录依据。

用 scipy.stats.zscore 做快速 Z-score 离群点标记
Z-score 是最轻量、最易上手的离群检测方式,适合单变量业务指标(如订单金额、用户停留时长)的初步清洗。它假设数据近似正态分布,计算每个点偏离均值的标准差倍数。
实际使用时要注意:阈值别硬写 3,业务数据常有偏态,2.5 或 2 更稳妥;而且必须对每列单独计算,不能直接传入 DataFrame 整体——zscore 默认按列操作,但若传入含非数值列的 DataFrame 会报 TypeError: ufunc 'isfinite' not supported for the input types。
推荐做法:
- 先用
select_dtypes(include=[np.number])提取数值列 - 用
np.abs(zscore(df_num)) > threshold得布尔掩码 - 用
df[~mask]过滤掉离群行(注意是取反)
示例:
from scipy.stats import zscore import numpy as np mask = np.abs(zscore(df[['amount', 'duration']])) > 2.5 df_clean = df[~mask.any(axis=1)]
用 sklearn.ensemble.IsolationForest 处理多维业务特征
当异常由多个字段组合触发(比如“高金额 + 低停留时长 + 新设备”),Z-score 就失效了。这时 IsolationForest 是更贴合业务逻辑的选择:它不依赖分布假设,训练快,对高维稀疏特征也鲁棒。
关键参数要调:n_estimators 默认 100 足够;contamination 别设成全局比例(如 0.1),而应根据历史人工标注或业务容忍率来定——比如风控场景可设 0.01,推荐系统冷启动数据可放宽到 0.05;random_state 务必固定,否则每次运行结果不一致,没法复现问题样本。
注意:fit_predict 返回的是 1(正常)和 -1(异常),不是布尔值,过滤时得写 clf.fit_predict(X) == 1,写成 != -1 语义不清且易出错。
警惕 pandas.DataFrame.drop_duplicates 被误当成离群过滤工具
有人看到重复订单 ID 就直接用 drop_duplicates(subset=['order_id']),以为是在“去异常”,其实这是去重,不是离群检测。真正异常可能是同一用户 1 秒内提交 50 笔相同金额订单——这种模式靠去重发现不了,反而会把本该报警的批量行为“洗掉”。
更危险的是:如果用 keep=False 删除所有重复项,可能把合法的高频行为(如秒杀抢购)全干掉。业务上,“重复”不等于“异常”,得结合时间窗口、行为序列、IP 聚类等维度判断。
正确思路是:先用规则(如 df.groupby('user_id').size().sort_values(ascending=False).head(10))定位可疑群体,再抽样人工校验,最后固化为模型或规则引擎条件。
离群点不是删完就完事——保留原始标签并记录过滤依据
线上业务中,被过滤的数据往往要回溯分析:是上游采集错误?还是新业务模式导致分布漂移?所以不要用 df = df[~mask] 直接覆盖原变量。
建议三步走:
- 新增列
is_outlier_z或is_outlier_if存布尔标记 - 另存一份带标签的中间表(如 Parquet 文件),字段包含原始值 + 检测方法 + 阈值 + 时间戳
- 在后续 pipeline 开头加断言:
assert df['is_outlier_z'].mean() ,超阈值就告警,而不是静默跳过
最容易被忽略的一点:不同检测方法的结果可能冲突。比如某条记录被 Z-score 判为正常,却被 IsolationForest 标为异常——这时候不能简单投票,得看业务上下文:如果是支付失败率监控,优先信无监督模型;如果是财务对账,优先信基于业务规则的阈值判断。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











