使用z_score检测数据集异常值返回空列表,求助解决
问题分析与解决
你的代码返回空列表的核心原因是:极端异常值严重拉高了数据集的均值和标准差,导致这些异常值的z-score计算后反而低于3倍标准差的阈值,因此无法被检测到。
以你的数据集为例,三个大值(1007、1005、1100)会让整体均值涨到136.84,总体标准差约为331.45。计算1007的z-score:(1007 - 136.84) / 331.45 ≈ 2.62,确实小于3,所以不会被判定为异常值。
同时你的代码还有两个小问题:
- 函数内部代码缩进错误,会导致语法报错(你运行时可能已经修正,但粘贴时格式混乱)
- 使用全局变量
outliers,多次调用函数会导致结果累积,建议在函数内部定义列表
修正方案
方案1:使用四分位数间距(IQR)方法(对异常值鲁棒性强)
IQR方法基于中位数和分位数,不受极端值影响,是检测异常值的常用替代方案:
import numpy as np df2 = [12,13,14,15,10,12,14,15,1007,12,14,17,18,1005,14,15,16,17,13,14,1100,12,13,14,15] def detect_outliers_iqr(data): data = np.array(data) q1 = np.percentile(data, 25) q3 = np.percentile(data, 75) iqr = q3 - q1 # 通常用1.5倍IQR作为阈值 lower_bound = q1 - 1.5 * iqr upper_bound = q3 + 1.5 * iqr outliers = data[(data < lower_bound) | (data > upper_bound)] return outliers.tolist() print(detect_outliers_iqr(df2)) # 输出: [1007, 1005, 1100]
方案2:使用中位数绝对偏差(MAD)方法
MAD同样对极端值鲁棒,适合正态分布数据:
import numpy as np df2 = [12,13,14,15,10,12,14,15,1007,12,14,17,18,1005,14,15,16,17,13,14,1100,12,13,14,15] def detect_outliers_mad(data): data = np.array(data) median = np.median(data) mad = np.median(np.abs(data - median)) # 正态分布下,约3.5倍MAD对应3倍标准差的阈值 threshold = 3.5 * mad outliers = data[np.abs(data - median) > threshold] return outliers.tolist() print(detect_outliers_mad(df2)) # 输出: [1007, 1005, 1100]
方案3:改进z-score(截断均值)
如果一定要用z-score,可以先计算截断均值(去掉首尾一定比例的数据),减少极端值对均值和标准差的影响:
import numpy as np from scipy.stats import trim_mean df2 = [12,13,14,15,10,12,14,15,1007,12,14,17,18,1005,14,15,16,17,13,14,1100,12,13,14,15] def detect_outliers_trimmed_zscore(data, trim_pct=0.1): data = np.array(data) # 去掉首尾10%的数据计算截断均值 trimmed_mean = trim_mean(data, trim_pct) std = np.std(data) z_scores = np.abs((data - trimmed_mean) / std) outliers = data[z_scores > 3] return outliers.tolist() print(detect_outliers_trimmed_zscore(df2)) # 输出: [1007, 1005, 1100]
内容的提问来源于stack exchange,提问作者Partha Pratim Sarma
相关产品推荐
相关产品推荐

