默认 plt.boxplot 会显示离群点,前提是数据中存在落在 [Q1−1.5×IQR, Q3+1.5×IQR] 外的值;常见原因包括无真实异常、showfliers=False、含 NaN 未处理、插值方式不一致或样本量过小。

用 plt.boxplot 画箱线图,但离群点总不显示?
默认情况下 plt.boxplot 确实会计算并标出离群点(outliers),但前提是数据里真有落在 [Q1 - 1.5×IQR, Q3 + 1.5×IQR] 区间外的值。常见误判是:数据本身没异常,或被缩放/归一化过,导致 IQR 过小、阈值太严。
- 检查原始数据分布,先用
np.quantile(data, [0.25, 0.75])和np.iqr(data)手动算一遍,确认是否真有超出范围的点 - 如果用了
showfliers=False(默认是True),离群点会被隐藏——删掉这个参数或显式设为True - Matplotlib 3.8+ 对极小样本(
n )可能跳过离群点计算,建议确保 <code>len(data) >= 20再画 - 若数据含
np.nan,boxplot默认丢弃它们,但不会报错;用np.isnan(data).sum()先清查缺失值
scipy.stats.iqr 和手算 Q3 - Q1 结果不一样?
差异来自插值方式:scipy.stats.iqr 默认用 interpolation='linear'(线性插值),而 np.percentile(data, 75) - np.percentile(data, 25) 在 NumPy 1.22+ 后也默认同策略,但旧版本用的是 'midpoint'。实际业务中这点差异通常可忽略,但做自动化异常判定时必须统一。
- 明确指定插值方式:用
np.percentile(data, 25, interpolation='linear')和np.percentile(data, 75, interpolation='linear')手算,结果就和iqr(data, rng=(25,75), interpolation='linear')一致 - 避免混用库:别一边用
scipy.stats.iqr,另一边用pd.Series.quantile(0.25)(pandas 默认interpolation='linear',但method参数名不同,易漏) - IQR 本身对极端值鲁棒,但对小样本敏感——样本量
3σ 原则在 Python 里怎么稳稳落地?
直接套公式 abs(x - mean) > 3 * std 很危险:一旦数据含明显异常值,mean 和 std 就被污染,导致漏判。得先用稳健统计量兜底。
- 用
np.median替代np.mean,用scipy.stats.median_abs_deviation(MAD)替代np.std,再按abs(x - median) > 3 * 1.4826 * MAD判定(1.4826 是正态下 MAD 与 σ 的换算系数) - 如果坚持用 3σ,至少做两轮:第一轮粗筛去掉明显离群点(比如先用 IQR 法剔除),再用剩余数据重算
mean和std,二次过滤 - 注意
np.std默认是总体标准差(ddof=0),而样本标准差应设ddof=1;对 >50 个点的数据,差别不大,但小样本必须明确
同一组数据,IQR 和 3σ 标出的异常点完全不重合?
这非常正常,不是 bug。IQR 基于顺序统计,对分布形状不敏感;3σ 隐含正态假设。当数据左偏、右偏或双峰时,两者天然分歧。
立即学习“Python免费学习笔记(深入)”;
- 右偏数据(如用户停留时长):3σ 容易把右侧长尾全判为异常,IQR 更宽容;此时优先信 IQR,或改用对数变换后再用 3σ
- 双峰数据(如 AB 测试混在一起):IQR 可能压根找不到“箱体”,因为中位数卡在两个峰之间,IQR 虚高;这时先聚类(比如用
sklearn.cluster.KMeans分两组),再分组跑 IQR - 真正该警惕的是:两个方法都标不出异常,但直方图明显有孤立尖峰——那可能是采集错误或埋点重复,得查原始日志,而不是调统计阈值
事情说清了就结束。异常检测没有银弹,IQR 和 3σ 都只是工具,关键是你是否清楚当前数据的生成逻辑和业务容忍边界。






