Seaborn 数据可视化
Seaborn 是基于 Matplotlib 的统计数据可视化库,提供了更高级的接口和更美观的默认样式。它专门针对 Pandas 数据结构进行了优化,能够轻松创建各种统计图表。本章将详细介绍 Seaborn 的使用方法。
Seaborn 简介
为什么选择 Seaborn?
相比 Matplotlib,Seaborn 有以下优势:
- 更简洁的 API:一行代码即可创建复杂图表
- 美观的默认样式:内置多种专业配色方案
- 统计数据可视化:自动计算统计量并绑定置信区间
- Pandas 集成:直接使用 DataFrame 列名
安装和导入
# 安装
# pip install seaborn
import seaborn as sns
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 设置样式
sns.set_theme(style="whitegrid") # 可选: white, dark, whitegrid, darkgrid, ticks
# 设置中文字体(避免中文乱码)
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
图表类型概览
Seaborn 的函数按功能分为几类:
| 模块 | 函数 | 用途 |
|---|---|---|
| 关系图 | relplot, scatterplot, lineplot | 展示变量关系 |
| 分布图 | displot, histplot, kdeplot | 展示数据分布 |
| 分类图 | catplot, boxplot, violinplot | 展示分类数据 |
| 回归图 | lmplot, regplot | 展示回归关系 |
| 矩阵图 | heatmap, clustermap | 展示矩阵数据 |
图表级别 vs 轴级别函数
- 轴级别函数:在单个坐标轴上绘图,返回 Axes 对象
- 图表级别函数:管理整个图形,返回 FacetGrid 对象
# 轴级别函数
ax = sns.scatterplot(data=df, x='x', y='y')
# 图表级别函数(可以创建多子图)
g = sns.relplot(data=df, x='x', y='y', col='category')
关系图
关系图用于展示两个或多个数值变量之间的关系。
散点图
import seaborn as sns
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 创建示例数据
np.random.seed(42)
tips = pd.DataFrame({
'total_bill': np.random.uniform(10, 50, 100),
'tip': np.random.uniform(1, 10, 100),
'sex': np.random.choice(['Male', 'Female'], 100),
'smoker': np.random.choice(['Yes', 'No'], 100),
'time': np.random.choice(['Lunch', 'Dinner'], 100)
})
tips['tip'] = tips['tip'] + tips['total_bill'] * 0.15 # 使tip与total_bill相关
# 基本散点图
plt.figure(figsize=(10, 6))
sns.scatterplot(data=tips, x='total_bill', y='tip')
plt.title('消费金额与小费关系')
plt.show()
# 添加分类颜色
plt.figure(figsize=(10, 6))
sns.scatterplot(data=tips, x='total_bill', y='tip', hue='sex')
plt.title('不同性别的小费分布')
plt.show()
# 添加大小和样式
plt.figure(figsize=(10, 6))
sns.scatterplot(data=tips, x='total_bill', y='tip',
hue='sex', # 颜色区分性别
style='time', # 样式区分用餐时间
size='smoker', # 大小区分是否吸烟
sizes=(50, 150))
plt.title('多维数据散点图')
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()
线图
# 创建时间序列数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=30)
fmri = pd.DataFrame({
'timepoint': np.tile(np.arange(30), 4),
'signal': np.random.randn(120).cumsum() + 10,
'region': np.repeat(['frontal', 'parietal'], 60),
'event': np.tile(np.repeat(['stim', 'cue'], 30), 2)
})
# 基本线图
plt.figure(figsize=(12, 6))
sns.lineplot(data=fmri, x='timepoint', y='signal')
plt.title('信号随时间变化')
plt.show()
# 分组线图
plt.figure(figsize=(12, 6))
sns.lineplot(data=fmri, x='timepoint', y='signal',
hue='region', # 颜色区分区域
style='event', # 样式区分事件
markers=True, # 显示标记点
dashes=False) # 不使用虚线
plt.title('不同区域和事件的信号变化')
plt.show()
# 添加置信区间
plt.figure(figsize=(12, 6))
sns.lineplot(data=fmri, x='timepoint', y='signal',
hue='region',
errorbar='sd') # 显示标准差区间
plt.title('带置信区间的线图')
plt.show()
relplot 多面板图
# 使用 relplot 创建多面板图
g = sns.relplot(data=tips, x='total_bill', y='tip',
col='time', # 列分面
row='sex', # 行分面
hue='smoker',
style='smoker',
height=3, aspect=1.2)
g.fig.suptitle('不同时段和性别的小费分布', y=1.02)
plt.show()
分布图
分布图用于展示单个变量的分布情况。
直方图
# 创建示例数据
np.random.seed(42)
penguins = pd.DataFrame({
'flipper_length_mm': np.random.normal(200, 15, 300),
'species': np.random.choice(['Adelie', 'Chinstrap', 'Gentoo'], 300),
'island': np.random.choice(['Torgersen', 'Biscoe', 'Dream'], 300)
})
# 基本直方图
plt.figure(figsize=(10, 6))
sns.histplot(data=penguins, x='flipper_length_mm')
plt.title('鳍长分布直方图')
plt.show()
# 添加核密度估计
plt.figure(figsize=(10, 6))
sns.histplot(data=penguins, x='flipper_length_mm', kde=True)
plt.title('带KDE的直方图')
plt.show()
# 分组直方图
plt.figure(figsize=(10, 6))
sns.histplot(data=penguins, x='flipper_length_mm', hue='species')
plt.title('不同物种的鳍长分布')
plt.show()
# 堆叠直方图
plt.figure(figsize=(10, 6))
sns.histplot(data=penguins, x='flipper_length_mm',
hue='species', multiple='stack')
plt.title('堆叠直方图')
plt.show()
# 按比例显示
plt.figure(figsize=(10, 6))
sns.histplot(data=penguins, x='flipper_length_mm',
hue='species', multiple='fill')
plt.title('比例直方图')
plt.show()
核密度估计图
# 基本KDE图
plt.figure(figsize=(10, 6))
sns.kdeplot(data=penguins, x='flipper_length_mm')
plt.title('核密度估计图')
plt.show()
# 填充KDE
plt.figure(figsize=(10, 6))
sns.kdeplot(data=penguins, x='flipper_length_mm', fill=True)
plt.title('填充KDE图')
plt.show()
# 分组KDE
plt.figure(figsize=(10, 6))
sns.kdeplot(data=penguins, x='flipper_length_mm',
hue='species', fill=True, alpha=0.5)
plt.title('不同物种的KDE分布')
plt.show()
# 二维KDE
plt.figure(figsize=(10, 8))
sns.kdeplot(data=tips, x='total_bill', y='tip', fill=True)
plt.title('二维核密度估计')
plt.show()
displot 综合分布图
# 使用 displot 创建多面板分布图
g = sns.displot(data=penguins, x='flipper_length_mm',
col='species', # 按物种分面
kde=True, # 添加KDE
height=4, aspect=1)
g.fig.suptitle('各物种鳍长分布', y=1.02)
plt.show()
分类图
分类图用于展示分类变量与数值变量之间的关系。
箱线图
# 基本箱线图
plt.figure(figsize=(10, 6))
sns.boxplot(data=tips, x='time', y='total_bill')
plt.title('不同时段的消费金额分布')
plt.show()
# 分组箱线图
plt.figure(figsize=(10, 6))
sns.boxplot(data=tips, x='time', y='total_bill', hue='sex')
plt.title('不同时段和性别的消费分布')
plt.legend(title='性别')
plt.show()
# 横向箱线图
plt.figure(figsize=(10, 6))
sns.boxplot(data=tips, y='time', x='total_bill', orient='h')
plt.title('横向箱线图')
plt.show()
小提琴图
小提琴图结合了箱线图和核密度估计:
# 基本小提琴图
plt.figure(figsize=(10, 6))
sns.violinplot(data=tips, x='time', y='total_bill')
plt.title('小提琴图')
plt.show()
# 分组小提琴图
plt.figure(figsize=(10, 6))
sns.violinplot(data=tips, x='time', y='total_bill',
hue='sex', split=True) # split=True 将两组显示在同一侧
plt.title('分组小提琴图')
plt.legend(title='性别')
plt.show()
# 显示内部箱线图
plt.figure(figsize=(10, 6))
sns.violinplot(data=tips, x='time', y='total_bill',
inner='box') # 可选: box, quartile, point, stick, None
plt.title('带内部箱线图的小提琴图')
plt.show()
条形图和点图
# 条形图(显示均值和置信区间)
plt.figure(figsize=(10, 6))
sns.barplot(data=tips, x='time', y='total_bill', hue='sex')
plt.title('平均消费金额(带置信区间)')
plt.legend(title='性别')
plt.show()
# 计数图(显示各类别的计数)
plt.figure(figsize=(10, 6))
sns.countplot(data=tips, x='time', hue='sex')
plt.title('各时段用餐人数')
plt.legend(title='性别')
plt.show()
# 点图(便于比较不同组别)
plt.figure(figsize=(10, 6))
sns.pointplot(data=tips, x='time', y='total_bill', hue='sex',
markers=['o', 's'], linestyles=['-', '--'])
plt.title('点图比较')
plt.legend(title='性别')
plt.show()
catplot 多面板分类图
# 使用 catplot 创建多面板图
g = sns.catplot(data=tips, x='sex', y='total_bill',
col='time', # 列分面
row='smoker', # 行分面
kind='box', # 图表类型
height=4, aspect=1)
g.fig.suptitle('多维度消费分布', y=1.02)
plt.show()
回归图
回归图用于展示变量之间的线性关系。
基本回归图
# 散点图+回归线
plt.figure(figsize=(10, 6))
sns.regplot(data=tips, x='total_bill', y='tip')
plt.title('消费金额与小费的回归关系')
plt.show()
# 多项式回归
plt.figure(figsize=(10, 6))
sns.regplot(data=tips, x='total_bill', y='tip',
order=2) # 二次多项式
plt.title('二次多项式回归')
plt.show()
# 不显示散点
plt.figure(figsize=(10, 6))
sns.regplot(data=tips, x='total_bill', y='tip',
scatter=False, ci=95) # 不显示散点,95%置信区间
plt.title('仅显示回归线')
plt.show()
lmplot 分组回归
# 分组回归
g = sns.lmplot(data=tips, x='total_bill', y='tip',
hue='smoker', # 按吸烟状态分组
height=6, aspect=1.2)
g.fig.suptitle('不同吸烟习惯的回归分析', y=1.02)
plt.show()
# 多面板回归
g = sns.lmplot(data=tips, x='total_bill', y='tip',
col='time', # 列分面
row='sex', # 行分面
height=4, aspect=1)
g.fig.suptitle('多维度回归分析', y=1.02)
plt.show()
矩阵图
热力图
# 创建相关系数矩阵
np.random.seed(42)
data = pd.DataFrame({
'A': np.random.randn(100),
'B': np.random.randn(100),
'C': np.random.randn(100),
'D': np.random.randn(100)
})
data['B'] = data['A'] * 0.8 + np.random.randn(100) * 0.3 # 使A和B相关
data['D'] = data['C'] * 0.7 + np.random.randn(100) * 0.4 # 使C和D相关
corr = data.corr()
# 基本热力图
plt.figure(figsize=(8, 6))
sns.heatmap(corr)
plt.title('相关系数热力图')
plt.show()
# 添加数值标注
plt.figure(figsize=(8, 6))
sns.heatmap(corr, annot=True, cmap='coolwarm', center=0,
fmt='.2f', square=True)
plt.title('带数值标注的热力图')
plt.show()
# 自定义配色
plt.figure(figsize=(8, 6))
sns.heatmap(corr, annot=True, cmap='RdYlGn', center=0,
linewidths=0.5, linecolor='white')
plt.title('自定义配色热力图')
plt.show()
聚类图
# 创建用于聚类的数据
np.random.seed(42)
cluster_data = pd.DataFrame(
np.random.randn(10, 8),
columns=[f'Gene_{i}' for i in range(8)],
index=[f'Sample_{i}' for i in range(10)]
)
# 聚类热力图
g = sns.clustermap(cluster_data,
cmap='coolwarm',
center=0,
figsize=(10, 8),
dendrogram_ratio=0.2)
plt.suptitle('聚类热力图', y=1.02)
plt.show()
多图组合
jointplot 联合分布图
# 基本联合分布图
g = sns.jointplot(data=tips, x='total_bill', y='tip',
height=8)
g.fig.suptitle('联合分布图', y=1.02)
plt.show()
# 添加回归线
g = sns.jointplot(data=tips, x='total_bill', y='tip',
kind='reg', height=8)
g.fig.suptitle('带回归线的联合分布图', y=1.02)
plt.show()
# 使用KDE
g = sns.jointplot(data=tips, x='total_bill', y='tip',
kind='kde', fill=True, height=8)
g.fig.suptitle('KDE联合分布图', y=1.02)
plt.show()
# 六边形图(适合大数据集)
g = sns.jointplot(data=tips, x='total_bill', y='tip',
kind='hex', height=8)
g.fig.suptitle('六边形图', y=1.02)
plt.show()
pairplot 成对关系图
# 选择数值列
numeric_cols = ['total_bill', 'tip']
tips_numeric = tips[numeric_cols + ['sex']]
# 基本pairplot
g = sns.pairplot(tips_numeric, height=3)
g.fig.suptitle('成对关系图', y=1.02)
plt.show()
# 分组pairplot
g = sns.pairplot(tips_numeric, hue='sex', height=3)
g.fig.suptitle('分组成对关系图', y=1.02)
plt.show()
# 自定义对角线和非对角线图表类型
g = sns.pairplot(tips_numeric, hue='sex',
diag_kind='kde', # 对角线使用KDE
kind='scatter', # 非对角线使用散点图
height=3)
g.fig.suptitle('自定义pairplot', y=1.02)
plt.show()
样式和美化
设置主题
# 设置主题样式
# 可选: white, dark, whitegrid, darkgrid, ticks
sns.set_theme(style='whitegrid')
# 设置调色板
# 内置调色板: deep, muted, pastel, bright, dark, colorblind
# 其他: husl, Set1, Set2, Set3, tab10, coolwarm, RdYlGn
sns.set_palette('husl')
# 设置字体大小
sns.set_context('notebook') # paper, notebook, talk, poster
# 创建图表
plt.figure(figsize=(10, 6))
sns.scatterplot(data=tips, x='total_bill', y='tip', hue='sex')
plt.title('应用样式后的图表')
plt.show()
自定义颜色
# 使用调色板
plt.figure(figsize=(10, 6))
sns.scatterplot(data=tips, x='total_bill', y='tip',
hue='sex', palette='Set1')
plt.title('使用Set1调色板')
plt.show()
# 自定义颜色
custom_palette = {'Male': '#3498db', 'Female': '#e74c3c'}
plt.figure(figsize=(10, 6))
sns.scatterplot(data=tips, x='total_bill', y='tip',
hue='sex', palette=custom_palette)
plt.title('自定义颜色')
plt.show()
# 使用渐变色
plt.figure(figsize=(10, 6))
sns.scatterplot(data=tips, x='total_bill', y='tip',
hue='total_bill', palette='coolwarm')
plt.title('渐变色映射')
plt.show()
使用 FacetGrid 自定义
# 创建 FacetGrid
g = sns.FacetGrid(tips, col='time', row='sex', height=4)
# 映射绘图函数
g.map_dataframe(sns.scatterplot, x='total_bill', y='tip')
# 添加标题和标签
g.set_titles(col_template='{col_name}', row_template='{row_name}')
g.set_axis_labels('消费金额', '小费')
g.add_legend()
plt.suptitle('自定义 FacetGrid', y=1.02)
plt.show()
# 使用不同的绘图类型
g = sns.FacetGrid(tips, col='time', height=5)
g.map_dataframe(sns.histplot, x='total_bill', kde=True)
g.set_axis_labels('消费金额', '计数')
plt.suptitle('分面直方图', y=1.02)
plt.show()
实战示例
示例:鸢尾花数据集分析
# 使用 Seaborn 内置数据集
iris = sns.load_dataset('iris')
# 查看数据
print(iris.head())
# 成对关系图
g = sns.pairplot(iris, hue='species', height=2.5)
g.fig.suptitle('鸢尾花特征关系', y=1.02)
plt.show()
# 箱线图比较各特征
iris_melt = iris.melt(id_vars='species', var_name='feature', value_name='value')
plt.figure(figsize=(12, 6))
sns.boxplot(data=iris_melt, x='feature', y='value', hue='species')
plt.title('各特征在不同物种间的分布')
plt.xticks(rotation=15)
plt.legend(title='物种')
plt.show()
# 小提琴图
plt.figure(figsize=(12, 6))
sns.violinplot(data=iris_melt, x='feature', y='value', hue='species',
split=False, inner='quartile')
plt.title('各特征的小提琴图')
plt.xticks(rotation=15)
plt.show()
示例:多维度数据分析
# 创建模拟数据
np.random.seed(42)
n = 200
analysis_data = pd.DataFrame({
'age': np.random.randint(20, 60, n),
'income': np.random.normal(50000, 15000, n),
'education': np.random.choice(['High School', 'Bachelor', 'Master', 'PhD'], n),
'department': np.random.choice(['Sales', 'Engineering', 'Marketing', 'HR'], n),
'satisfaction': np.random.randint(1, 6, n)
})
# 调整数据使有关联
analysis_data['income'] = analysis_data['income'] + \
(analysis_data['education'].map({'High School': 0, 'Bachelor': 10000,
'Master': 20000, 'PhD': 35000}))
analysis_data['income'] = analysis_data['income'] + \
(analysis_data['age'] - 30) * 500
# 教育程度与收入
plt.figure(figsize=(12, 6))
sns.boxplot(data=analysis_data, x='education', y='income',
order=['High School', 'Bachelor', 'Master', 'PhD'])
plt.title('不同教育程度的收入分布')
plt.xlabel('教育程度')
plt.ylabel('收入')
plt.show()
# 年龄与收入的关系
plt.figure(figsize=(12, 6))
sns.regplot(data=analysis_data, x='age', y='income',
scatter_kws={'alpha': 0.5}, line_kws={'color': 'red'})
plt.title('年龄与收入的关系')
plt.show()
# 多维度分析
g = sns.lmplot(data=analysis_data, x='age', y='income',
col='department', hue='education',
col_wrap=2, height=4, aspect=1.2,
scatter_kws={'alpha': 0.5})
g.fig.suptitle('各部门年龄与收入关系(按教育程度分组)', y=1.02)
plt.show()
# 满意度热力图
satisfaction_pivot = analysis_data.pivot_table(
values='satisfaction',
index='education',
columns='department',
aggfunc='mean'
)
plt.figure(figsize=(10, 6))
sns.heatmap(satisfaction_pivot, annot=True, cmap='RdYlGn',
center=3, fmt='.2f')
plt.title('各部门各教育程度的平均满意度')
plt.show()
小结
本章我们学习了:
- 关系图:
scatterplot,lineplot,relplot展示变量关系 - 分布图:
histplot,kdeplot,displot展示数据分布 - 分类图:
boxplot,violinplot,barplot,catplot展示分类数据 - 回归图:
regplot,lmplot展示回归关系 - 矩阵图:
heatmap,clustermap展示矩阵数据 - 多图组合:
jointplot,pairplot综合展示 - 样式设置:主题、调色板、自定义样式
选择合适的图表类型:
| 分析目标 | 推荐图表 |
|---|---|
| 两个数值变量的关系 | scatterplot, lineplot |
| 单个变量分布 | histplot, kdeplot |
| 分类与数值变量关系 | boxplot, violinplot |
| 多变量关系 | pairplot, heatmap |
| 趋势分析 | lineplot, regplot |
练习
- 使用
iris数据集创建各特征的箱线图和小提琴图 - 创建一个散点图,展示两个变量的关系,并按第三个变量着色
- 使用
heatmap展示一个相关系数矩阵