🕐 预计用时:3-4 小时 | 🎯 目标:掌握分布图、热力图、分类图、回归图和主题风格
# Seaborn = 基于 Matplotlib 的高级可视化库
# 特点:
# 1. 一行代码画出复杂图表(Matplotlib 可能要 20 行)
# 2. 默认样式美观(配色和谐,字体清晰)
# 3. 原生支持 Pandas DataFrame
# 4. 内置统计计算(均值、置信区间等)
# 安装
# pip install seaborn
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# 中文设置
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False
# Seaborn vs Matplotlib 速览:
# Matplotlib → 底层画笔,完全控制,代码多
# Seaborn → 高层封装,统计图表,代码少,好看sns.histplot() | ||
sns.boxplot() | ||
sns.heatmap() | ||
sns.catplot() |
import seaborn as sns
# Seaborn 自带多个经典数据集,方便练习
tips = sns.load_dataset('tips') # 餐厅小费数据
titanic = sns.load_dataset('titanic') # 泰坦尼克号
iris = sns.load_dataset('iris') # 鸢尾花
flights = sns.load_dataset('flights') # 航班乘客数
# 查看数据
print(tips.head())
# total_bill tip sex smoker day time size
# 0 16.99 1.01 Female No Sun Dinner 2
# 1 10.34 1.66 Male No Sun Dinner 3
# 2 21.01 3.50 Male No Sun Dinner 3
# 3 23.68 3.31 Male No Sun Dinner 2
# 4 24.59 3.61 Female No Sun Dinner 4
print(tips.describe())
print(tips.dtypes)tips | |||
titanic | |||
iris | |||
flights | |||
diamonds | |||
penguins |
分布图回答一个问题:数据长什么样? 集中在哪里?分散还是集中?有没有异常值?
import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset('tips')
# === histplot:直方图 + 密度曲线(最常用)===
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
# 基础直方图
sns.histplot(tips['total_bill'], bins=20, ax=axes[0], color='#07c160')
axes[0].set_title('基础直方图')
# 带 KDE 密度曲线
sns.histplot(tips['total_bill'], kde=True, ax=axes[1], color='#4d96ff')
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()
# === kdeplot:核密度估计(平滑版直方图)===
fig, ax = plt.subplots(figsize=(10, 6))
sns.kdeplot(data=tips, x='total_bill', hue='time', fill=True, ax=ax, alpha=0.5)
ax.set_title('账单金额的密度分布(按用餐时间)')
ax.set_xlabel('账单金额')
ax.set_ylabel('密度')
plt.tight_layout()
plt.show()
# === ecdfplot:累积分布函数(CDF)===
fig, ax = plt.subplots(figsize=(10, 6))
sns.ecdfplot(data=tips, x='total_bill', hue='time', ax=ax)
ax.set_title('账单金额的累积分布')
ax.set_xlabel('账单金额')
ax.set_ylabel('累积比例')
plt.tight_layout()
plt.show()💡 直方图 vs KDE:
• histplot(直方图):把数据分成若干小格,数每个格里有多少个数据点。直观但受 bin 数量影响。
• kdeplot(密度曲线):用数学方法拟合出一条平滑曲线。不受 bin 影响,更优雅。
• 推荐:sns.histplot(kde=True) 两者兼得——直方图看原始分布,曲线看整体趋势。
分类图回答一个问题:不同类别之间的数据有什么区别?
import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset('tips')
# === boxplot:箱线图(最常用)===
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
# 基础箱线图
sns.boxplot(data=tips, x='day', y='total_bill', hue='day', ax=axes[0],
palette='Set2', legend=False)
axes[0].set_title('各天账单金额分布')
# 按性别分组
sns.boxplot(data=tips, x='day', y='total_bill', hue='sex', ax=axes[1], palette='Set2')
axes[1].set_title('各天账单(按性别分组)')
# 水平箱线图
sns.boxplot(data=tips, y='day', x='total_bill', hue='day', ax=axes[2],
palette='Set2', legend=False)
axes[2].set_title('水平箱线图')
plt.tight_layout()
plt.show()
# === violinplot:小提琴图(箱线图 + 密度曲线)===
fig, ax = plt.subplots(figsize=(10, 6))
sns.violinplot(data=tips, x='day', y='total_bill', hue='sex',
split=True, ax=ax, palette='Set2')
ax.set_title('小提琴图:账单金额分布(按性别分半)')
plt.tight_layout()
plt.show()
# === stripplot / swarmplot:散点分布图 ===
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
# stripplot:随机抖动散点(有重叠)
sns.stripplot(data=tips, x='day', y='total_bill', ax=axes[0],
color='#07c160', alpha=0.6, jitter=True)
axes[0].set_title('stripplot:抖动散点')
# swarmplot:无重叠散点(计算最优位置)
sns.swarmplot(data=tips, x='day', y='total_bill', ax=axes[1],
color='#4d96ff', size=4)
axes[1].set_title('swarmplot:蜂群散点')
plt.tight_layout()
plt.show()
# === barplot:带误差线的柱状图(自动计算均值和置信区间)===
fig, ax = plt.subplots(figsize=(10, 6))
sns.barplot(data=tips, x='day', y='total_bill', hue='time',
ax=ax, palette='Set2', errorbar=('ci', 95)) # 95% 置信区间
ax.set_title('各天平均账单(按用餐时间)')
ax.set_ylabel('平均账单金额')
plt.tight_layout()
plt.show()
# === countplot:计数柱状图(统计频次)===
fig, ax = plt.subplots(figsize=(10, 6))
sns.countplot(data=tips, x='day', hue='time', ax=ax, palette='Set2')
ax.set_title('各天用餐次数(按用餐时间)')
ax.set_ylabel('次数')
plt.tight_layout()
plt.show()boxplot | ||
violinplot | ||
swarmplot | ||
stripplot | ||
barplot | ||
countplot |
import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset('tips')
# === scatterplot:散点图 ===
fig, ax = plt.subplots(figsize=(10, 6))
sns.scatterplot(data=tips, x='total_bill', y='tip',
hue='time', size='size', sizes=(50, 300),
alpha=0.7, ax=ax, palette='Set2')
ax.set_title('账单金额 vs 小费(颜色=时间,大小=人数)')
ax.set_xlabel('账单金额')
ax.set_ylabel('小费')
plt.tight_layout()
plt.show()
# === lineplot:折线图(带置信区间)===
flights = sns.load_dataset('flights')
fig, ax = plt.subplots(figsize=(12, 6))
sns.lineplot(data=flights, x='year', y='passengers', ax=ax,
color='#07c160', linewidth=2)
ax.set_title('航班乘客数趋势(1949-1960)')
ax.set_xlabel('年份')
ax.set_ylabel('乘客数(千人)')
plt.tight_layout()
plt.show()
# === relplot:关系图的 FacetGrid 版本(自动分面板)===
# 一行代码生成多面板散点图
g = sns.relplot(data=tips, x='total_bill', y='tip',
col='time', # 按时间分列
hue='sex', # 按性别着色
style='smoker', # 按吸烟状态区分标记
kind='scatter',
height=5, aspect=1.2)
g.fig.suptitle('多面板散点图', y=1.02, fontsize=16)
plt.tight_layout()
plt.show()import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset('tips')
# === regplot:散点 + 回归线 ===
fig, ax = plt.subplots(figsize=(10, 6))
sns.regplot(data=tips, x='total_bill', y='tip',
ax=ax, color='#07c160',
scatter_kws={'alpha': 0.5, 's': 30},
line_kws={'color': 'red', 'linewidth': 2})
ax.set_title('账单与小费的线性回归')
ax.set_xlabel('账单金额')
ax.set_ylabel('小费')
plt.tight_layout()
plt.show()
# === lmplot:多面板回归图 ===
g = sns.lmplot(data=tips, x='total_bill', y='tip',
col='time', # 按时间分列
hue='smoker', # 按吸烟状态分色
height=5, aspect=1.2,
scatter_kws={'alpha': 0.5},
palette='Set2')
g.fig.suptitle('账单与小费的关系(按时间和吸烟状态)', y=1.02, fontsize=14)
plt.tight_layout()
plt.show()
# === residplot:残差图(检查回归假设)===
fig, ax = plt.subplots(figsize=(10, 6))
sns.residplot(data=tips, x='total_bill', y='tip', ax=ax, color='#4d96ff')
ax.set_title('残差图(检查线性假设)')
ax.set_xlabel('账单金额')
ax.set_ylabel('残差')
plt.tight_layout()
plt.show()💡 回归图怎么解读?
• 回归线向上 → 正相关(X 增大,Y 也增大)
• 回归线向下 → 负相关
• 阴影区域 → 置信区间(越窄表示拟合越确定)
• 残差图:点应该随机分布在 0 附近。如果呈现规律(如 U 形),说明线性模型不合适。
热力图是最直观的数据展示方式——颜色深浅表示数值大小。常用于相关矩阵和数据透视。
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# === 相关矩阵热力图(最常用!)===
iris = sns.load_dataset('iris')
# 计算相关系数矩阵
corr = iris.corr(numeric_only=True)
print(corr)
# sepal_length sepal_width petal_length petal_width
# sepal_length 1.000 -0.118 0.872 0.818
# sepal_width -0.118 1.000 -0.428 -0.366
# petal_length 0.872 -0.428 1.000 0.963
# petal_width 0.818 -0.366 0.963 1.000
fig, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(corr,
annot=True, # 显示数值
fmt='.2f', # 保留2位小数
cmap='RdYlGn', # 颜色方案(红黄绿)
center=0, # 0 值对应的颜色
square=True, # 正方形格子
linewidths=1, # 格线宽度
vmin=-1, vmax=1, # 颜色范围
ax=ax)
ax.set_title('鸢尾花特征相关矩阵', fontsize=16)
plt.tight_layout()
plt.show()
# === 数据透视表热力图 ===
flights = sns.load_dataset('flights')
pivot = flights.pivot_table(index='month', columns='year', values='passengers')
fig, ax = plt.subplots(figsize=(14, 6))
sns.heatmap(pivot,
annot=True, # 显示数值
fmt='d', # 整数格式
cmap='YlOrRd', # 黄橙红配色
linewidths=0.5,
ax=ax)
ax.set_title('航班乘客数热力图(月份 × 年份)', fontsize=16)
ax.set_xlabel('年份')
ax.set_ylabel('月份')
plt.tight_layout()
plt.show()
# === 掩码上三角(只显示下三角)===
corr = iris.corr(numeric_only=True)
mask = np.triu(np.ones_like(corr, dtype=bool)) # 上三角为 True
fig, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(corr, mask=mask, annot=True, fmt='.2f',
cmap='coolwarm', center=0, square=True, ax=ax)
ax.set_title('相关矩阵(下三角)')
plt.tight_layout()
plt.show()RdYlGn | ||
coolwarm | ||
YlOrRd | ||
viridis | ||
Blues | ||
mako |
import seaborn as sns
import matplotlib.pyplot as plt
# pairplot:一次性展示所有数值变量两两关系
iris = sns.load_dataset('iris')
g = sns.pairplot(iris,
hue='species', # 按品种着色
diag_kind='kde', # 对角线用密度图(默认 hist)
palette='Set2',
height=2.5,
plot_kws={'alpha': 0.6, 's': 40})
g.fig.suptitle('鸢尾花配对图', y=1.02, fontsize=16)
plt.tight_layout()
plt.show()
# 配对图解读:
# 对角线:每个变量的分布(按品种分色)
# 非对角线:两个变量的散点图(按品种分色)
# 如果某个散点图中不同颜色明显分开 → 这两个变量能区分品种
# 只选择部分变量
g = sns.pairplot(iris,
vars=['sepal_length', 'petal_length', 'petal_width'],
hue='species',
palette='Set2',
height=3)
plt.tight_layout()
plt.show()import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset('tips')
# === FacetGrid:最灵活的多面板工具 ===
# 按 row/column 分面板
g = sns.FacetGrid(tips, col='time', row='sex', height=4, aspect=1.2)
g.map(sns.histplot, 'total_bill', kde=True, color='#07c160')
g.set_axis_labels('账单金额', '频数')
g.fig.suptitle('账单金额分布(按性别×时间)', y=1.02, fontsize=14)
plt.tight_layout()
plt.show()
# === catplot:分类图的 FacetGrid 版本 ===
g = sns.catplot(data=tips, x='day', y='total_bill',
hue='sex', col='time',
kind='box', # 可换成 violin / bar / strip
height=5, aspect=1.0,
palette='Set2')
g.fig.suptitle('各天账单(按性别×时间×图表类型)', y=1.02, fontsize=14)
plt.tight_layout()
plt.show()
# === jointplot:散点 + 边缘分布 ===
g = sns.jointplot(data=tips, x='total_bill', y='tip',
kind='scatter', # 可换成 kde / hex / reg
hue='time',
height=8, ratio=4,
marginal_kws={'fill': True})
g.fig.suptitle('账单 vs 小费(含边缘分布)', y=1.02, fontsize=14)
plt.tight_layout()
plt.show()
# jointplot 的 kind 选项:
# 'scatter' → 散点图(默认)
# 'kde' → 密度等高线
# 'hex' → 六边形分箱
# 'reg' → 散点 + 回归线import seaborn as sns
import matplotlib.pyplot as plt
# === 5 种内置主题 ===
# sns.set_theme(style='darkgrid') # 深色网格(默认)
# sns.set_theme(style='whitegrid') # 浅色网格(适合数据展示)
# sns.set_theme(style='dark') # 纯暗色背景
# sns.set_theme(style='white') # 纯白背景
# sns.set_theme(style='ticks') # 带刻度线
# === 配色方案 ===
# sns.set_palette('Set2') # 柔和色(8色)
# sns.set_palette('husl') # 均匀亮度色(10+色)
# sns.set_palette('pastel') # 柔粉色
# sns.set_palette('muted') # 柔和深色
# sns.set_palette('deep') # 鲜艳深色
# sns.set_palette('colorblind') # 色盲友好
# 临时设置(不影响全局)
with sns.color_palette('Set2'):
fig, ax = plt.subplots()
sns.boxplot(data=tips, x='day', y='total_bill', ax=ax)
plt.show()
# === 完整主题示例 ===
sns.set_theme(
style='whitegrid',
palette='Set2',
font_scale=1.2, # 字体缩放
rc={ # Matplotlib 参数覆盖
'figure.figsize': (10, 6),
'axes.titlesize': 16,
'axes.labelsize': 12,
}
)
fig, ax = plt.subplots()
sns.violinplot(data=tips, x='day', y='total_bill', hue='sex',
split=True, ax=ax)
ax.set_title('Seaborn 白色网格主题', fontsize=16)
plt.tight_layout()
plt.show()
# 恢复默认主题
sns.set_theme() # 不传参数 = 恢复默认# 用 Seaborn 分析泰坦尼克号数据:
# 1. 画舱位等级 vs 生存率的柱状图
# 2. 画年龄分布的直方图(按生存状态分色)
# 3. 画性别 × 舱位 × 生存的分组箱线图
# 4. 画相关矩阵热力图# 用鸢尾花数据:
# 1. 画配对图(pairplot),观察哪些特征能区分品种
# 2. 画花瓣长度 vs 花瓣宽度的散点图(按品种分色 + 回归线)
# 3. 画各品种的特征箱线图对比# 创建一组专业报告图表(2x2 子图布局):
# - 左上:销售趋势折线图
# - 右上:品类占比饼图
# - 左下:价格分布直方图 + KDE
# - 右下:相关性热力图
# 要求:统一配色、统一字体、统一标题风格histplotkdeplot / ecdfplot | ||
boxplotviolinplot / barplot / countplot | ||
scatterplotlineplot / relplot | ||
regplotlmplot / residplot | ||
heatmap | ||
pairplot | ||
FacetGridcatplot / jointplot |
🎉 可视化阶段完结!
Day 76-77 你掌握了 Python 数据可视化的两大利器:
✅ Matplotlib — 底层控制,完全定制
✅ Seaborn — 高级封装,一行代码,统计图表
明天 Day 78 是数据科学综合项目——用 NumPy + Pandas + Matplotlib + Seaborn 完成一份完整的电商销售数据分析报告!