【零基础玩转Python】Day51:常用统计图 – 直方图、箱线图、热力图,洞悉数据分布的三个视角
大家好,我是[知识充电宝的灵感日记]。
昨天我们学习了 Seaborn 的基础美化,今天我们将深入三种最常用的统计图表:直方图(分布)、箱线图(离散与异常)、热力图(相关性)。掌握这些图表,你就能快速理解一个数据集的整体面貌。
今天的目标:
- ✅ 实战:对泰坦尼克数据集进行完整的分布与相关性分析
难度:⭐⭐(理解统计概念即可,绘图有现成函数
一、直方图(Histogram)
直方图用于展示连续变量的分布情况(频数或频率)。横轴是数值区间(bins),纵轴是落入每个区间的数据个数。
1. 基础直方图
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 加载数据
tips = sns.load_dataset('tips')
plt.figure(figsize=(8, 4))
sns.histplot(tips['total_bill'], bins=20)
plt.title('账单金额分布(频数)')
plt.xlabel('账单金额(美元)')
plt.ylabel('频数')
plt.show()

2. 调整分箱(bins)
分箱数量直接影响直方图的表现:
fig, axes = plt.subplots(1, 3, figsize=(12, 3))
sns.histplot(tips['total_bill'], bins=5, ax=axes[0])
axes[0].set_title('bins=5 (过粗)')
sns.histplot(tips['total_bill'], bins=20, ax=axes[1])
axes[1].set_title('bins=20 (适中)')
sns.histplot(tips['total_bill'], bins=50, ax=axes[2])
axes[2].set_title('bins=50 (过细)')
plt.tight_layout()
plt.show()
3. 核密度估计(KDE):平滑分布
添加 kde=True可以绘制概率密度曲线。
sns.histplot(tips['total_bill'], bins=20, kde=True, color='skyblue')
plt.title('频数直方图 + KDE 密度曲线')
plt.show()
4. 累积分布图(CDF)
展示数据在各区间的累积比例,不依赖于分箱。
sns.histplot(tips['total_bill'], cumulative=True, stat='density', bins=30)
plt.title('累积分布函数')
plt.ylabel('累积密度')
plt.show()
5. 多组数据的直方图对比
可以用 hue参数进行分组,或使用 displot创建分面直方图。
sns.histplot(data=tips, x='total_bill', hue='time', multiple='stack', bins=20)
plt.title('按用餐时段堆叠的账单金额分布')
plt.show()
multiple 参数可选:'layer'(叠加)、'stack'(堆叠)、'dodge'(并排)、'fill'(归一化堆叠)。
二、箱线图(Boxplot)
箱线图展示数据的五数概括(最小值、Q1、中位数、Q3、最大值)以及异常值,是识别离群点的利器。
1. 基础箱线图
plt.figure(figsize=(6, 5))
sns.boxplot(y='total_bill', data=tips)
plt.title('账单金额箱线图')
plt.ylabel('账单金额(美元)')
plt.show()
图中:
- 须(whisker):通常延伸到
Q1-1.5*IQR和 Q3+1.5*IQR,但不超出数据范围
2. 分组箱线图(按类别)
plt.figure(figsize=(8, 5))
sns.boxplot(x='day', y='total_bill', data=tips, palette='Set2', hue='day', legend=False)
plt.title('不同日期的账单金额分布')
plt.xlabel('星期')
plt.ylabel('账单金额')
plt.show()
3. 箱线图 + 散点叠加(stripplot 或 swarmplot)
为了看到实际数据点,可以叠加散点图:
plt.figure(figsize=(8, 5))
sns.boxplot(x='day', y='total_bill', data=tips, palette='Set2', hue='day', legend=False)
sns.stripplot(x='day', y='total_bill', data=tips, color='black', alpha=0.5, size=8)
plt.title('箱线图 + 原始数据点')
plt.show()
4. 小提琴图(Violinplot)——箱线图 + KDE
小提琴图结合了箱线图和密度曲线,能更细致地显示分布形状。
plt.figure(figsize=(8, 5))
sns.violinplot(x='day', y='total_bill', data=tips, palette='muted', hue='day', legend=False)
plt.title('小提琴图:箱线图 + 密度曲线')
plt.show()
三、热力图(Heatmap)
热力图常用于可视化相关性矩阵,也可以用颜色表示任意二维数值表的大小。
1. 相关性热力图
# 选择数值列
numeric_cols = tips.select_dtypes(include=[np.number])
corr = numeric_cols.corr()
plt.figure(figsize=(6, 5))
sns.heatmap(corr, annot=True, cmap='coolwarm', center=0, square=True)
plt.title('数值变量相关性热力图')
plt.show()
cmap:颜色映射('coolwarm', 'viridis', 'RdBu' 等)center=0:将颜色映射的中心设为0,适合显示正负相关fmt:数值格式,如 fmt='.2f'(保留两位小数)
2. 自定义颜色映射
sns.heatmap(corr, annot=True, cmap='RdYlBu_r', center=0, vmin=-1, vmax=1)
vmin和 vmax控制颜色映射的范围。
3. 热力图用于展示数据表(比如透视表结果)
# 创建透视表
pivot = tips.pivot_table(index='day', columns='time', values='total_bill', aggfunc='mean')
plt.figure(figsize=(5, 4))
sns.heatmap(pivot, annot=True, cmap='YlGnBu', fmt='.1f')
plt.title('不同星期/用餐时段的平均账单')
plt.show()
# 创建透视表
pivot = tips.pivot_table(index='day', columns='time', values='total_bill', aggfunc='mean', observed=False)
plt.figure(figsize=(5, 4))
sns.heatmap(pivot, annot=True, cmap='YlGnBu', fmt='.1f')
plt.title('不同星期/用餐时段的平均账单')
plt.show()
4. 聚类热力图(clustermap)
除了展示数值本身,clustermap 还会对行和列进行层次聚类,便于发现分组模式。
sns.clustermap(corr, annot=True, cmap='coolwarm', center=0)
plt.show()
四、实战小案例:tips数据探索
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
# 加载 tips 数据集(内置,无需联网)
tips = sns.load_dataset('tips')
# Mac 系统中文 + 负号修复
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 创建画布
plt.figure(figsize=(12, 4))
# 1. 账单金额分布直方图 + KDE
plt.subplot(1, 3, 1)
sns.histplot(tips['total_bill'].dropna(), bins=30, kde=True, color='skyblue')
plt.title('账单金额分布')
# 2. 不同日期的账单箱线图(修复Seaborn警告)
plt.subplot(1, 3, 2)
sns.boxplot(x='day', y='total_bill', data=tips, palette='Set2', hue='day', legend=False)
plt.title('不同日期账单分布')
# 3. 数值列相关性热力图
plt.subplot(1, 3, 3)
num_cols = tips.select_dtypes(include=[np.number])
corr = num_cols.corr()
sns.heatmap(corr, annot=True, cmap='coolwarm', center=0)
plt.title('特征相关性热力图')
plt.tight_layout()
plt.show()
五、今日练习
- 加载
iris数据集,绘制 sepal_length的直方图,设置 bins=20,添加 KDE 曲线,并用不同颜色显示不同种类(hue='species')。 - 绘制
iris数据集中 sepal_length按 species分组的箱线图,并叠加 stripplot展示原始数据点。 - 计算
iris所有数值列的相关矩阵,绘制热力图,要求显示数值、使用 'coolwarm'颜色,并且中心为 0。 - (挑战)使用
penguins数据集,绘制一个 2×2 的子图: - 左上:
body_mass_g的直方图(分箱20,带 KDE) - 右上:按
species分组的 bill_length_mm箱线图 - 右下:按
species分组的 flipper_length_mm小提琴图
六、常见错误与提示
- 直方图
bins过少或过多:过少会掩盖分布细节,过多会产生噪声。可使用 numpy.histogram_bin_edges或 bins='auto'自动选择。 - 箱线图异常值判断依赖于 IQR:对于偏态分布,异常值可能误判,可考虑使用对数变换后再绘图。
- 热力图数据范围差异大:若数值不在 [-1,1] 区间(如单位不同),不适合直接用于相关性展示,应先标准化。
heatmap中 annot数值过多导致拥挤:可减小字体 annot_kws={'size':8}。- 直方图的纵轴:
stat参数可以控制纵轴类型,默认为 count(频数),还可以选 'density'(密度)、'probability'(概率)、'percent'(百分比)。
七、明日预告
Day52:Pandas内置绘图 – 快速探索数据
我们将学习如何使用 Pandas 自带的绘图方法,一行代码快速生成图表,适合数据探索阶段。