跳转到内容

3.4.3 Seaborn 统计可视化

Seaborn 统计图选择图

  • 理解 Seaborn 与 Matplotlib 的关系
  • 掌握分布图、关系图、分类图
  • 学会绘制热力图与相关性矩阵
  • 使用 FacetGrid 进行分面绑图

Seaborn 最适合新人的理解顺序不是“函数表”,而是先看清它最擅长的 4 类问题:

flowchart LR
A["分布"] --> B["histplot / kdeplot"]
C["关系"] --> D["scatterplot / lineplot / pairplot"]
E["分类比较"] --> F["boxplot / violinplot / barplot / countplot"]
G["矩阵关系"] --> H["heatmap"]

所以这节真正想解决的是:

  • 当你在做 EDA 时,哪种图最适合先拿出来
  • 为什么 Seaborn 会比纯 Matplotlib 更适合快速探索

如果把 Matplotlib 比作画笔和颜料,那 Seaborn 就是画笔套装 + 调色板 + 模板

flowchart LR
A["Matplotlib<br/>基础画笔"] -->|"Seaborn 封装"| B["Seaborn<br/>美观统计图表"]
B -->|"底层仍是"| A
C["Pandas<br/>DataFrame"] -->|"直接传入"| B
style A fill:#e3f2fd,stroke:#1565c0,color:#333
style B fill:#e8f5e9,stroke:#2e7d32,color:#333
style C fill:#fff3e0,stroke:#e65100,color:#333
对比MatplotlibSeaborn
定位底层绑图库高级统计绘图库
代码量多,需要手动设置少,开箱即用
默认美观度一般非常美观
数据格式数组、列表直接用 DataFrame
统计功能需要手动计算自动计算均值、置信区间等
定制能力极强中等(可借助 Matplotlib 补充)

一句话总结: Seaborn 让你用 1 行代码画出 Matplotlib 需要 10 行才能完成的美观统计图。

你可以把 Seaborn 理解成:

  • 已经帮你摆好盘的数据可视化工具

Matplotlib 像你自己从锅碗瓢盆开始摆, Seaborn 则像已经帮你配好餐具和默认风格, 你更容易把注意力放在:

  • 这张图到底想看什么统计现象

# 安装
# python -m pip install --upgrade seaborn
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# Seaborn 自带的示例数据集
tips = sns.load_dataset("tips") # 餐厅小费数据
iris = sns.load_dataset("iris") # 鸢尾花数据
titanic = sns.load_dataset("titanic") # 泰坦尼克号数据
# 设置全局风格
sns.set_theme(style="whitegrid") # 白底网格,清爽好看
风格说明适合场景
"whitegrid"白底 + 网格数值对比(推荐默认)
"darkgrid"灰底 + 网格强调数据点
"white"纯白底论文、报告
"dark"灰底艺术风格
"ticks"白底 + 刻度线简洁专业

分布图帮你回答:这组数据的值集中在哪里?分散程度如何?是否有偏斜?

第一次做 EDA 时,最稳的默认顺序

Section titled “第一次做 EDA 时,最稳的默认顺序”

更稳的顺序通常是:

  1. 先看分布图 先知道数据集中在哪、偏不偏。
  2. 再看关系图 看变量之间有没有明显关系。
  3. 再看分类图 看不同组之间差别大不大。
  4. 最后再看热力图 把整体相关性快速扫一遍。

这个顺序特别适合新人,因为它会让探索过程更有主线。

fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# 基本直方图
sns.histplot(data=tips, x="total_bill", ax=axes[0])
axes[0].set_title("基本直方图")
# 添加密度曲线
sns.histplot(data=tips, x="total_bill", kde=True, ax=axes[1])
axes[1].set_title("直方图 + 密度曲线")
# 按类别分颜色
sns.histplot(data=tips, x="total_bill", hue="time", kde=True, ax=axes[2])
axes[2].set_title("按用餐时间分组")
plt.tight_layout()
plt.show()
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
# 一维密度
sns.kdeplot(data=tips, x="total_bill", hue="sex", fill=True, ax=axes[0])
axes[0].set_title("消费金额密度分布")
# 二维密度(等高线)
sns.kdeplot(data=tips, x="total_bill", y="tip", fill=True, cmap="Blues", ax=axes[1])
axes[1].set_title("消费 vs 小费 联合密度")
plt.tight_layout()
plt.show()
fig, ax = plt.subplots(figsize=(8, 4))
sns.kdeplot(data=tips, x="total_bill", fill=True, ax=ax)
sns.rugplot(data=tips, x="total_bill", ax=ax, alpha=0.5)
ax.set_title("密度曲线 + 地毯图(每条线代表一个数据点)")
plt.show()

关系图:变量之间有什么关系?

Section titled “关系图:变量之间有什么关系?”
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 基本散点图,用颜色区分类别
sns.scatterplot(data=tips, x="total_bill", y="tip", hue="time", ax=axes[0])
axes[0].set_title("消费 vs 小费")
# 用大小和颜色同时表示信息
sns.scatterplot(data=tips, x="total_bill", y="tip",
hue="day", size="size", sizes=(20, 200), ax=axes[1])
axes[1].set_title("多维度散点图")
plt.tight_layout()
plt.show()
# 模拟实验数据:每个 x 有多个 y 值
rng = np.random.default_rng(seed=42)
data = pd.DataFrame({
"step": np.tile(np.arange(1, 51), 10),
"accuracy": np.tile(np.linspace(0.5, 0.95, 50), 10) + rng.normal(0, 0.03, 500),
"model": np.repeat(["模型 A", "模型 B"], 250)
})
fig, ax = plt.subplots(figsize=(10, 5))
sns.lineplot(data=data, x="step", y="accuracy", hue="model", ax=ax)
ax.set_title("模型训练准确率变化(阴影 = 95% 置信区间)")
plt.show()
# 鸢尾花数据集的所有变量关系
sns.pairplot(iris, hue="species", diag_kind="kde", corner=True)
plt.suptitle("鸢尾花数据集特征关系", y=1.02)
plt.show()

pairplot 一行代码就能展示所有变量之间的关系,是数据探索阶段的利器


分类图是 Seaborn 的强项,帮你比较不同类别之间的数据分布和统计量。

一个很适合初学者先记的选图表

Section titled “一个很适合初学者先记的选图表”
你最想回答的问题更稳的第一选择
这一列值大概怎么分布?histplot
两个变量有没有关系?scatterplot
两组或多组分布差很多吗?boxplot / violinplot
哪个类别样本更多?countplot
多个数值变量相关吗?heatmap

这张表会让新人少走很多弯路,因为你不用一开始就被函数名压住。

fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 基本箱线图
sns.boxplot(data=tips, x="day", y="total_bill", ax=axes[0])
axes[0].set_title("各日消费分布")
# 用颜色区分子类
sns.boxplot(data=tips, x="day", y="total_bill", hue="sex", ax=axes[1])
axes[1].set_title("各日消费分布(按性别)")
plt.tight_layout()
plt.show()
fig, ax = plt.subplots(figsize=(10, 5))
sns.violinplot(data=tips, x="day", y="total_bill", hue="sex",
split=True, inner="quart", ax=ax)
ax.set_title("各日消费分布(小提琴图,左女右男)")
plt.show()

小提琴图 = 箱线图 + 密度分布,比箱线图能看到更多分布形状。

barplot:均值柱状图(带误差线)

Section titled “barplot:均值柱状图(带误差线)”
fig, ax = plt.subplots(figsize=(8, 5))
sns.barplot(data=tips, x="day", y="total_bill", hue="sex",
ci=95, ax=ax) # ci=95 表示 95% 置信区间
ax.set_title("各日平均消费(误差线 = 95% 置信区间)")
plt.show()
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
# 简单计数
sns.countplot(data=tips, x="day", order=["Thur", "Fri", "Sat", "Sun"], ax=axes[0])
axes[0].set_title("各天就餐人次")
# 分组计数
sns.countplot(data=titanic, x="class", hue="survived", ax=axes[1])
axes[1].set_title("各舱位生存情况")
plt.tight_layout()
plt.show()

热力图用颜色深浅表示数值大小,最常用于相关性矩阵

# 计算数值列的相关系数
# 选取 tips 中的数值列
numeric_cols = tips.select_dtypes(include="number")
corr = numeric_cols.corr()
fig, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(corr, annot=True, fmt=".2f", cmap="RdBu_r",
center=0, vmin=-1, vmax=1,
square=True, linewidths=0.5, ax=ax)
ax.set_title("小费数据集相关性矩阵")
plt.tight_layout()
plt.show()

关键参数:

参数作用常用值
annot显示数值True
fmt数值格式".2f" 两位小数
cmap颜色映射"RdBu_r" 红蓝反转
center颜色中心值0(相关系数)
square正方形格子True
# 交叉表热力图(比如各天各时段的平均消费)
pivot = tips.pivot_table(values="total_bill", index="day", columns="time", aggfunc="mean")
fig, ax = plt.subplots(figsize=(6, 4))
sns.heatmap(pivot, annot=True, fmt=".1f", cmap="YlOrRd",
linewidths=1, ax=ax)
ax.set_title("各天各时段平均消费")
plt.show()

当你想按某个变量把图表拆成多个子图时,用 FacetGrid。

# 按用餐时间分面,展示消费与小费的关系
g = sns.FacetGrid(tips, col="time", row="sex", hue="smoker",
height=4, aspect=1.2)
g.map_dataframe(sns.scatterplot, x="total_bill", y="tip")
g.add_legend()
g.fig.suptitle("按时间和性别分面的消费-小费关系", y=1.02)
plt.show()
# 按星期分面的直方图
g = sns.FacetGrid(tips, col="day", col_wrap=2, height=3)
g.map_dataframe(sns.histplot, x="total_bill", kde=True)
g.set_titles("星期: {col_name}")
g.fig.suptitle("各日消费分布", y=1.02)
plt.show()
参数作用
col按此变量分列
row按此变量分行
hue按此变量分颜色
col_wrap每行最多几列(自动换行)
height每个子图高度
aspect宽高比

因为它能帮你把:

  • “整体看起来还行”

拆成:

  • 在不同类别、不同分组下到底哪里不一样

这对新人很重要,因为很多数据问题并不是整体分布能看出来的,而是:

  • 一旦分组,就会暴露得很明显

root(("Seaborn<br/>图表类型"))
分布图
histplot 直方图
kdeplot 密度曲线
rugplot 地毯图
关系图
scatterplot 散点图
lineplot 折线图
pairplot 变量矩阵
分类图
boxplot 箱线图
violinplot 小提琴图
barplot 均值柱状图
countplot 计数图
矩阵图
heatmap 热力图
多面板
FacetGrid 分面
pairplot 配对

学完这一页,至少保留这张证据卡:

问题
这张图表回答的是比较、分布、趋势,还是关系
图表选择
折线图、柱状图、散点图、直方图、箱线图、热力图或交互式仪表板
工件
保存的图表图片/html 以及所用的数据切片
失败检查
尺度误导、图表过载、聚合错误或缺少标签
期望产出
带有一句说明洞察的图表成果
需求函数说明
查看分布histplot / kdeplot直方图 / 密度曲线
两变量关系scatterplot / lineplot散点图 / 折线图
所有变量关系pairplot一键矩阵图
类别间对比boxplot / violinplot / barplot分布 / 均值
类别计数countplot柱状图
数值矩阵heatmap热力图
分面展示FacetGrid多子图

核心优势: 一行代码就能画出美观且含统计信息的图表,直接传入 DataFrame 即可。

  • Seaborn 最重要的价值,不是更花哨,而是更适合快速做统计探索
  • 第一次做 EDA,先看分布,再看关系,再看分类比较,通常最稳
  • 选图时先问“我想看什么统计现象”,比先背函数更重要

# 加载 tips 数据集
# 1. 用 histplot 画出 tip(小费)的分布,按 time 分颜色
# 2. 用 kdeplot 画出 total_bill 的密度曲线,按 sex 分组
# 加载 titanic 数据集
# 1. 用 boxplot 比较各舱位 (class) 的年龄 (age) 分布
# 2. 用 countplot 展示各舱位的生存人数
# 加载 iris 数据集
# 1. 计算数值列的相关系数矩阵
# 2. 用 heatmap 可视化,添加数值标注
# 3. 用 pairplot 查看所有变量关系
# 使用 tips 数据集
# 用 FacetGrid 按 day 分面,画出 total_bill 和 tip 的散点图
# 用颜色区分 sex
参考实现与讲解
  • 分布图可用 histplotkdeplot,并说明偏态、异常值和大致中心。只有漂亮曲线、没有解释是不完整的。
  • 类别比较中,箱线图和计数图回答的问题不同:一个看分布范围,一个看频数。先选符合问题的图,再做样式调整。
  • 热力图和 pair plot 要解释一两个重要关系,并写一个限制。相关性或视觉聚类只是调查线索,本身不是证明。