Seaborn 统计可视化
问题
Seaborn 相比 Matplotlib 有什么优势?如何用 Seaborn 做统计可视化和 EDA?
答案
Seaborn vs Matplotlib
| 维度 | Matplotlib | Seaborn |
|---|---|---|
| 定位 | 通用绑图库 | 统计可视化库 |
| 默认样式 | 朴素 | 美观 |
| 数据输入 | 数组 | DataFrame 列名 |
| 统计功能 | 无 | 自动计算均值、CI |
| 分面支持 | 需手动 | FacetGrid |
| 学习曲线 | 陡 | 平 |
一句话总结
Seaborn = Matplotlib + 更好的默认样式 + 统计计算 + DataFrame 友好
分布图
分布可视化
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
np.random.seed(42)
df = pd.DataFrame({
'age': np.concatenate([np.random.normal(28, 5, 500),
np.random.normal(35, 8, 500)]),
'group': ['新用户'] * 500 + ['老用户'] * 500,
'spend': np.random.lognormal(4, 1, 1000)
})
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
# 1. 直方图 + KDE
sns.histplot(data=df, x='age', hue='group', kde=True, ax=axes[0])
axes[0].set_title('年龄分布')
# 2. 箱线图
sns.boxplot(data=df, x='group', y='spend', ax=axes[1])
axes[1].set_title('消费分布')
# 3. 小提琴图(箱线图 + 密度图)
sns.violinplot(data=df, x='group', y='age', inner='quartile', ax=axes[2])
axes[2].set_title('年龄分布(小提琴图)')
plt.tight_layout()
plt.show()
关系图
关系可视化
import seaborn as sns
import matplotlib.pyplot as plt
# 使用内置数据集
tips = sns.load_dataset('tips')
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
# 1. 散点图 + 回归线
sns.regplot(data=tips, x='total_bill', y='tip', ax=axes[0],
scatter_kws={'alpha': 0.5})
axes[0].set_title('账单金额 vs 小费')
# 2. 分组散点图
sns.scatterplot(data=tips, x='total_bill', y='tip',
hue='time', style='smoker', ax=axes[1])
axes[1].set_title('按时间和吸烟状态分组')
# 3. 热力图(相关系数矩阵)
corr = tips[['total_bill', 'tip', 'size']].corr()
sns.heatmap(corr, annot=True, cmap='RdBu_r', center=0,
vmin=-1, vmax=1, ax=axes[2])
axes[2].set_title('相关系数矩阵')
plt.tight_layout()
plt.show()
分类对比图
分类数据可视化
import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset('tips')
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
# 1. 柱状图(自动计算均值 + CI)
sns.barplot(data=tips, x='day', y='total_bill', hue='sex',
errorbar='ci', ax=axes[0])
axes[0].set_title('各天平均账单')
# 2. 计数图
sns.countplot(data=tips, x='day', hue='time', ax=axes[1])
axes[1].set_title('各天就餐人数')
# 3. 带状图(看每个数据点)
sns.stripplot(data=tips, x='day', y='total_bill', hue='time',
dodge=True, alpha=0.5, ax=axes[2])
axes[2].set_title('各天账单详情')
plt.tight_layout()
plt.show()
FacetGrid 分面图
分面图——按维度拆分
import seaborn as sns
tips = sns.load_dataset('tips')
# 按 time(行) × smoker(列) 创建分面网格
g = sns.FacetGrid(tips, row='time', col='smoker',
height=4, aspect=1.2)
g.map_dataframe(sns.scatterplot, x='total_bill', y='tip')
g.add_legend()
g.set_titles(row_template='{row_name}', col_template='{col_name}')
plt.show()
# 更简洁的写法:relplot / catplot / displot
sns.relplot(
data=tips,
x='total_bill', y='tip',
col='time', row='smoker',
kind='scatter', height=4
)
plt.show()
主题与调色板
Seaborn 主题设置
import seaborn as sns
# 内置主题:darkgrid, whitegrid, dark, white, ticks
sns.set_theme(style='whitegrid', font_scale=1.2)
# 调色板
# 定性:'Set2', 'Paired', 'tab10'
# 连续:'Blues', 'viridis', 'YlOrRd'
# 发散:'RdBu', 'coolwarm'
sns.set_palette('Set2')
# 自定义调色板
custom = ['#2196F3', '#4CAF50', '#FF9800', '#F44336']
sns.set_palette(custom)
常见面试问题
Q1: EDA 阶段通常画哪些图?
答案(标准 EDA 流程):
- 分布:
histplot/kdeplot查看各数值列分布(是否偏态、有无异常值) - 相关性:
heatmap相关系数矩阵,快速发现变量关系 - 分组对比:
boxplot/barplot按分类维度对比数值 - 缺失值:
heatmap缺失值矩阵(msno库) - 散点图:重要变量对之间的
scatterplot
Q2: 箱线图怎么看?
答案:
- 中位线:中间的横线 = 中位数(Q2)
- 箱体:Q1(25%)到 Q3(75%),箱体宽度 = IQR
- 须线:延伸到 Q1-1.5×IQR 和 Q3+1.5×IQR 范围内
- 离群点:超出须线的点 = 异常值
- 比较多组箱线图时关注:中位数差异、分布宽窄、异常值多少
Q3: 什么时候用小提琴图替代箱线图?
答案:
- 箱线图:简洁,看中位数和四分位数够用
- 小提琴图:能看到完整的分布形状(双峰、偏态等)
- 数据有多峰分布时小提琴图信息更丰富
- 汇报给非技术人员时箱线图更易理解