4 探索性数据分析:可视化异常值、箱线图、直方图
说实话,我以前带团队的时候,发现很多人拿到数据后直接上手建模。结果模型跑出来,效果一塌糊涂。为什么?数据里藏着脏东西。异常值就是最常见的“脏东西”之一。
我个人习惯,拿到任何数据集,第一件事不是算均值、不是跑回归,而是画图。把数据摊开来看,你才能知道它到底长什么样。今天咱们就聊聊怎么用箱线图和直方图,把异常值揪出来。
4.1 箱线图:异常值识别的最直观工具
箱线图,说白了就是用五个数值把数据的分布概括出来。哪五个?最小值、第一四分位数(Q1)、中位数(Q2)、第三四分位数(Q3)、最大值。但这里的“最大值”和“最小值”,指的是非异常范围内的最大、最小值。
我见过不少新手,上来就看不懂箱线图。觉得那个“小箱子”加上两根“胡须”,看着很抽象。其实你记住:箱子里的那条线是中位数,箱子本身代表了中间50%的数据集中在哪里。
# Python 示例:用 seaborn 绘制箱线图
import seaborn as sns
import matplotlib.pyplot as plt
# 加载示例数据
df = sns.load_dataset('tips')
# 绘制单变量箱线图
sns.boxplot(y=df['total_bill'])
plt.title('消费金额箱线图')
plt.show()
# 分组箱线图,对比不同类别的分布
sns.boxplot(x='day', y='total_bill', data=df)
plt.title('不同日期的消费金额分布')
plt.show()
那怎么通过箱线图识别异常值呢?看“胡须”外面的点。这些点就是候选异常值。具体判断规则是用 IQR(四分位距)来定的。IQR = Q3 - Q1。然后设定一个“门槛”:
- 小于 Q1 - 1.5×IQR
- 大于 Q3 + 1.5×IQR
超过这两个边界的点,就会被标记为异常值。
注意:这个1.5倍IQR的规则是Tukey提出来的经验值。它适用于近似正态分布的数据。如果数据分布非常偏斜,这个阈值可能不准确。我在处理电商订单金额数据时遇到过,因为存在极少数的超大额订单,箱线图上一堆异常点,但其实那些是正常的VIP客户行为。
4.2 直方图:分布形态和离群点的辅助验证
箱线图告诉你“有没有异常”,直方图告诉你“为什么会有异常”。
直方图把数据切成若干个等宽的区间(bins),然后数每个区间里有多少个数据点。这样一画,数据的分布形态就一目了然了。
# Python 示例:用 matplotlib 绘制直方图
plt.hist(df['total_bill'], bins=30, edgecolor='black', alpha=0.7)
plt.xlabel('消费金额')
plt.ylabel('频数')
plt.title('消费金额直方图')
plt.show()
# 叠加核密度估计曲线(KDE),更容易看出分布形状
sns.histplot(df['total_bill'], bins=30, kde=True)
plt.title('消费金额分布(含KDE曲线)')
plt.show()
你想想看,如果一个直方图的右侧有长长的尾巴,或者左侧有孤零零的几个柱子远离主体,那这些区域大概率就是异常值。我曾经在分析用户停留时长数据时,直方图显示大部分用户在30秒内离开,但右侧有一个小高峰集中在600秒左右。这些不是异常,而是忠诚用户的特征。所以,异常值识别不能脱离业务背景。
小技巧:调整bins的数量很重要。bins太少,形状信息丢失;bins太多,锯齿状严重。我个人习惯先试20、30、50,选一个能看清分布趋势又不过度平滑的值。
4.3 箱线图 vs 直方图:什么时候用哪个?
很多人问过我这个。其实两者不是替代关系,是互补关系。我做异常分析时,通常是先用箱线图快速筛查,再用直方图深入分析。
| 特性 | 箱线图 | 直方图 |
|---|---|---|
| 数据维度 | 适合单变量、分组对比 | 适合单变量 |
| 异常值标记 | 自动标注离群点 | 需手动观察尾部 |
| 分布细节 | 仅显示分位数,丢失中间细节 | 显示完整分布形态 |
| 多重比较 | 方便,可在一张图上画多个箱子 | 不适合直接比较多个分布 |
| 适用场景 | 初步筛选、多组对比、报告展示 | 深入研究分布特征、模式发现 |
4.4 实战中的异常值分析流程
好,纸上谈兵没意思。说说我在实际项目中是怎么操作的。
- 第一步:快速扫描——对所有数值型字段绘制箱线图,初步定位可能有异常的字段。
- 第二步:深度探查——对可疑字段绘制直方图,判断异常是“伪异常”(数据本身特征)还是“真异常”(数据错误/特殊事件)。
- 第三步:交叉验证——用 IQR 规则或 Z-score 定量计算阈值,与可视化结论对比。
- 第四步:业务确认——把候选异常值列表交给业务方,确认是保留还是清洗。
重点:异常值不是垃圾。我处理银行交易数据时,发现一笔远高于平均值的交易金额,直觉告诉我可能是异常。结果一查,是合规风控标记的高风险交易。这种“异常”反而要保留分析。所以,可视化只是第一步,业务理解才是关键。
嗯,这里要注意,不要一次性对所有字段做箱线图。我见过有人一口气画了50个箱线图堆在一起,根本看不清楚。建议分批处理,一次最多看10个字段。
# 批量绘制箱线图的简化方法
import pandas as pd
# 选取数值型列
numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns
# 分批绘制,每批10个字段
for i in range(0, len(numeric_cols), 10):
cols_batch = numeric_cols[i:i+10]
df[cols_batch].boxplot(figsize=(12, 6), rot=45)
plt.suptitle(f'箱线图批次 {i//10 + 1}')
plt.tight_layout()
plt.show()
4.5 本章知识体系总览
我把本章的知识结构画成了一张流程图。你可以看一下,整个异常值可视化的逻辑是这样的:
画得不够好看,但逻辑是很清楚的。从左到右,从上到下:先用箱线图做快速筛选,用IQR规则确定阈值;箱线图发现的疑点,用直方图做分布验证;最后两步合并,进行交叉验证和业务确认。
你可能会问,为什么不在箱线图旁边直接放数据表格?我试过,但我们的大脑处理视觉图形的速度比处理数字快至少10倍。所以,可视化总是优先于表格。
总结一下核心要点:
- 箱线图看“有没有”:快速发现偏离主流的数据点
- 直方图看“什么样”:理解异常产生的分布背景
- 业务理解看“为什么”:同样的统计结果,不同业务含义不同
- 交叉验证定“怎么做”:确定清洗、保留还是标记
好,这一章的内容就到这里。记住,工具是死的,数据是活的。别让箱线图和直方图替你下结论,它们只是帮你发现问题的手段。最终判断,还是得靠你对业务的理解和对数据的直觉,而直觉,是从反复练习中来的。