Matplotlib/Seaborn特征分布图、损失曲线等可视化绘制全攻略

数据可视化是数据分析和机器学习的核心环节,Matplotlib和Seaborn是Python生态中最常用的可视化工具------Matplotlib侧重灵活定制图表,Seaborn专注统计可视化,二者结合能高效绘制特征分布图、损失曲线、相关性热力图等高频图表。

一、环境准备与基础配置

1. 安装与导入

确保安装核心库,建议搭配Pandas处理数据:

bash 复制代码
pip install matplotlib seaborn pandas numpy

导入库并配置全局样式(避免中文乱码、优化图表美观度):

python 复制代码
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np

# 全局配置(关键:解决中文显示问题)
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 适配Windows中文
# plt.rcParams["font.sans-serif"] = ["PingFang SC"]  # 适配Mac中文
plt.rcParams["axes.unicode_minus"] = False  # 解决负号显示异常
sns.set_style("whitegrid")  # 设置Seaborn默认样式(网格清晰,适合数据分析)
sns.set_palette("Set2")  # 设置配色方案(避免默认配色单调)

2. 基础绘图逻辑

Matplotlib采用"画布-子图"层级结构,Seaborn基于Matplotlib封装,核心逻辑一致:

python 复制代码
# 1. 创建画布和子图(1行1列的子图)
fig, ax = plt.subplots(figsize=(10, 6))  # figsize控制图表尺寸(宽, 高)

# 2. 绘制图表(以简单折线图为例)
x = np.linspace(0, 10, 100)
y = np.sin(x)
ax.plot(x, y, label="正弦曲线", color="#2E86AB", linewidth=2)

# 3. 图表美化(标题、标签、图例、网格)
ax.set_title("基础折线图示例", fontsize=14, fontweight="bold")
ax.set_xlabel("X轴", fontsize=12)
ax.set_ylabel("Y轴", fontsize=12)
ax.legend(loc="upper right", fontsize=10)
ax.grid(alpha=0.3)  # 网格透明度0.3,避免遮挡数据

# 4. 保存与显示(保存为高清图片,避免模糊)
plt.tight_layout()  # 自动调整布局,防止标签被截断
plt.savefig("基础折线图.png", dpi=300, bbox_inches="tight")  # dpi=300保证高清
plt.show()

二、特征分布图绘制(数据分析核心)

特征分布是探索性数据分析(EDA)的第一步,用于了解数据的分布形态、异常值、集中趋势,常用图表包括直方图、核密度图、箱线图、小提琴图等。

1. 单特征分布:直方图+核密度图(最常用)

适用于数值型特征(如薪资、年龄、销售额),展示数据分布规律:

python 复制代码
# 构造示例数据(模拟员工月薪数据)
data = pd.DataFrame({
    "月薪": np.random.normal(10000, 2000, 1000)  # 正态分布数据
})

# 方法1:Matplotlib绘制直方图+核密度图
fig, ax = plt.subplots(figsize=(10, 6))
# 绘制直方图(bins=组数,density=True归一化)
ax.hist(data["月薪"], bins=30, density=True, alpha=0.7, color="#A23B72", label="直方图")
# 计算核密度曲线
kernel = data["月薪"].plot.kde(ax=ax, color="#F18F01", linewidth=2, label="核密度曲线")

# 美化配置
ax.set_title("员工月薪分布", fontsize=14, fontweight="bold")
ax.set_xlabel("月薪(元)", fontsize=12)
ax.set_ylabel("密度", fontsize=12)
ax.legend(fontsize=10)
ax.axvline(data["月薪"].mean(), color="red", linestyle="--", label="均值")  # 标注均值线
ax.legend()
plt.tight_layout()
plt.savefig("月薪分布_直方图+核密度.png", dpi=300)
plt.show()

# 方法2:Seaborn一键绘制(更简洁,自带美化)
plt.figure(figsize=(10, 6))
sns.histplot(data["月薪"], bins=30, kde=True, color="#A23B72", alpha=0.7)
plt.title("员工月薪分布(Seaborn版)", fontsize=14, fontweight="bold")
plt.xlabel("月薪(元)", fontsize=12)
plt.ylabel("频数", fontsize=12)
plt.tight_layout()
plt.savefig("月薪分布_Seaborn版.png", dpi=300)
plt.show()

2. 多特征对比:箱线图/小提琴图

适用于对比不同类别下的特征分布(如不同城市、不同部门的薪资分布):

python 复制代码
# 构造多类别数据
data = pd.DataFrame({
    "城市": np.random.choice(["北京", "上海", "广州", "深圳"], 1000),
    "月薪": np.random.normal(10000, 2000, 1000) + np.random.randint(0, 3000, 1000)
})

# 技巧1:箱线图(展示四分位数、异常值)
plt.figure(figsize=(12, 7))
sns.boxplot(x="城市", y="月薪", data=data, palette="Set2")
plt.title("各城市员工月薪分布(箱线图)", fontsize=14, fontweight="bold")
plt.xlabel("城市", fontsize=12)
plt.ylabel("月薪(元)", fontsize=12)
# 标注异常值数量
for i, city in enumerate(data["城市"].unique()):
    city_data = data[data["城市"] == city]["月薪"]
    q1 = city_data.quantile(0.25)
    q3 = city_data.quantile(0.75)
    iqr = q3 - q1
    outliers = city_data[(city_data < q1-1.5*iqr) | (city_data > q3+1.5*iqr)]
    plt.text(i, city_data.min(), f&#34;异常值:{len(outliers)}&#34;, ha=&#34;center&#34;, fontsize=9)
plt.tight_layout()
plt.savefig(&#34;各城市月薪_箱线图.png&#34;, dpi=300)
plt.show()

# 技巧2:小提琴图(结合箱线图+核密度,展示分布形态)
plt.figure(figsize=(12, 7))
sns.violinplot(x=&#34;城市&#34;, y=&#34;月薪&#34;, data=data, palette=&#34;Set2&#34;, inner=&#34;quartile&#34;)  # inner显示四分位数
plt.title(&#34;各城市员工月薪分布(小提琴图)&#34;, fontsize=14, fontweight=&#34;bold&#34;)
plt.xlabel(&#34;城市&#34;, fontsize=12)
plt.ylabel(&#34;月薪(元)&#34;, fontsize=12)
plt.tight_layout()
plt.savefig(&#34;各城市月薪_小提琴图.png&#34;, dpi=300)
plt.show()

3. 分类特征分布:计数图/饼图

适用于离散型特征(如城市、性别、部门),展示类别占比:

python 复制代码
# 计数图(Seaborn)
plt.figure(figsize=(10, 6))
sns.countplot(x=&#34;城市&#34;, data=data, palette=&#34;Set2&#34;, order=data[&#34;城市&#34;].value_counts().index)
plt.title(&#34;各城市员工数量分布&#34;, fontsize=14, fontweight=&#34;bold&#34;)
plt.xlabel(&#34;城市&#34;, fontsize=12)
plt.ylabel(&#34;人数&#34;, fontsize=12)
# 标注数值
for i, v in enumerate(data[&#34;城市&#34;].value_counts().values):
    plt.text(i, v + 5, str(v), ha=&#34;center&#34;, fontsize=10)
plt.tight_layout()
plt.savefig(&#34;各城市人数_计数图.png&#34;, dpi=300)
plt.show()

# 饼图(Matplotlib,适合展示占比)
city_counts = data[&#34;城市&#34;].value_counts()
plt.figure(figsize=(8, 8))
plt.pie(
    city_counts.values,
    labels=city_counts.index,
    autopct=&#34;%1.1f%%&#34;,  # 显示百分比
    colors=sns.color_palette(&#34;Set2&#34;),
    explode=[0.05, 0, 0, 0],  # 突出第一个类别
    shadow=True,  # 阴影效果
    startangle=90  # 起始角度
)
plt.title(&#34;各城市员工占比&#34;, fontsize=14, fontweight=&#34;bold&#34;)
plt.axis(&#34;equal&#34;)  # 保证饼图为正圆形
plt.tight_layout()
plt.savefig(&#34;各城市人数_饼图.png&#34;, dpi=300)
plt.show()

三、损失曲线绘制(机器学习核心)

损失曲线用于监控模型训练过程,判断模型是否过拟合、欠拟合,是调参的重要依据,核心是绘制训练集/验证集的损失随迭代次数的变化。

1. 基础损失曲线(单模型)

python 复制代码
# 模拟训练数据(迭代次数、训练损失、验证损失)
epochs = range(1, 51)
train_loss = np.random.randn(50).cumsum() + 10  # 训练损失(逐渐下降)
train_loss = np.sort(train_loss)[::-1]  # 反转,模拟损失下降
val_loss = train_loss + np.random.randn(50) * 0.5  # 验证损失(略高于训练损失)

# 绘制损失曲线
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(epochs, train_loss, label=&#34;训练损失&#34;, color=&#34;#E94B3C&#34;, linewidth=2, marker=&#34;.&#34;)
ax.plot(epochs, val_loss, label=&#34;验证损失&#34;, color=&#34;#2E86AB&#34;, linewidth=2, marker=&#34;.&#34;)

# 关键标注:验证损失最小值点
min_val_loss_idx = np.argmin(val_loss)
min_val_loss = val_loss[min_val_loss_idx]
ax.scatter(epochs[min_val_loss_idx], min_val_loss, color=&#34;red&#34;, s=100, zorder=5)  # 标注最小值
ax.annotate(
    f&#34;最小值:{min_val_loss:.2f}\n迭代次数:{epochs[min_val_loss_idx]}&#34;,
    xy=(epochs[min_val_loss_idx], min_val_loss),
    xytext=(epochs[min_val_loss_idx]+5, min_val_loss+1),
    arrowprops=dict(arrowstyle=&#34;->&#34;, color=&#34;black&#34;)
)

# 美化配置
ax.set_title(&#34;模型训练损失曲线&#34;, fontsize=14, fontweight=&#34;bold&#34;)
ax.set_xlabel(&#34;迭代次数(Epoch)&#34;, fontsize=12)
ax.set_ylabel(&#34;损失值(Loss)&#34;, fontsize=12)
ax.legend(fontsize=10)
ax.grid(alpha=0.3)
plt.tight_layout()
plt.savefig(&#34;单模型损失曲线.png&#34;, dpi=300)
plt.show()

2. 多模型损失对比(调参/对比实验)

适用于对比不同超参数、不同模型的训练效果:

python 复制代码
# 模拟3个模型的损失数据
model1_train = np.sort(np.random.randn(50).cumsum() + 10)[::-1]
model1_val = model1_train + np.random.randn(50) * 0.5
model2_train = np.sort(np.random.randn(50).cumsum() + 9)[::-1]
model2_val = model2_train + np.random.randn(50) * 0.4
model3_train = np.sort(np.random.randn(50).cumsum() + 11)[::-1]
model3_val = model3_train + np.random.randn(50) * 0.6

# 绘制多模型对比曲线
fig, ax = plt.subplots(figsize=(12, 7))
ax.plot(epochs, model1_train, label=&#34;模型1-训练&#34;, color=&#34;#E94B3C&#34;, linewidth=2, linestyle=&#34;-&#34;)
ax.plot(epochs, model1_val, label=&#34;模型1-验证&#34;, color=&#34;#E94B3C&#34;, linewidth=2, linestyle=&#34;--&#34;)
ax.plot(epochs, model2_train, label=&#34;模型2-训练&#34;, color=&#34;#2E86AB&#34;, linewidth=2, linestyle=&#34;-&#34;)
ax.plot(epochs, model2_val, label=&#34;模型2-验证&#34;, color=&#34;#2E86AB&#34;, linewidth=2, linestyle=&#34;--&#34;)
ax.plot(epochs, model3_train, label=&#34;模型3-训练&#34;, color=&#34;#F18F01&#34;, linewidth=2, linestyle=&#34;-&#34;)
ax.plot(epochs, model3_val, label=&#34;模型3-验证&#34;, color=&#34;#F18F01&#34;, linewidth=2, linestyle=&#34;--&#34;)

# 美化配置
ax.set_title(&#34;多模型损失曲线对比&#34;, fontsize=14, fontweight=&#34;bold&#34;)
ax.set_xlabel(&#34;迭代次数(Epoch)&#34;, fontsize=12)
ax.set_ylabel(&#34;损失值(Loss)&#34;, fontsize=12)
ax.legend(fontsize=9, ncol=2)  # 图例分2列,避免遮挡
ax.grid(alpha=0.3)
plt.tight_layout()
plt.savefig(&#34;多模型损失曲线对比.png&#34;, dpi=300)
plt.show()

四、高频拓展可视化(业务实战)

1. 相关性热力图(特征关系分析)

适用于分析数值型特征间的线性关系,是特征选择的重要工具:

python 复制代码
# 构造多特征数据
data = pd.DataFrame({
    &#34;年龄&#34;: np.random.randint(20, 50, 1000),
    &#34;月薪&#34;: np.random.normal(10000, 2000, 1000) + np.random.randint(0, 3000, 1000),
    &#34;工作年限&#34;: np.random.randint(1, 30, 1000),
    &#34;绩效得分&#34;: np.random.normal(80, 10, 1000)
})

# 计算相关性矩阵
corr_matrix = data.corr()

# 绘制热力图
plt.figure(figsize=(9, 7))
sns.heatmap(
    corr_matrix,
    annot=True,  # 显示相关系数数值
    cmap=&#34;coolwarm&#34;,  # 配色(红=正相关,蓝=负相关)
    fmt=&#34;.2f&#34;,  # 数值保留2位小数
    linewidths=0.5,  # 格子边框宽度
    vmin=-1, vmax=1  # 数值范围(-1到1)
)
plt.title(&#34;特征相关性热力图&#34;, fontsize=14, fontweight=&#34;bold&#34;)
plt.tight_layout()
plt.savefig(&#34;特征相关性热力图.png&#34;, dpi=300)
plt.show()

2. 时间序列图(趋势分析)

适用于销售数据、用户增长、指标监控等时序场景:

python 复制代码
# 构造时序数据
dates = pd.date_range(start=&#34;2024-01-01&#34;, end=&#34;2024-12-31&#34;, freq=&#34;D&#34;)
sales = np.random.randn(366).cumsum() + 1000  # 模拟销售额趋势
sales_data = pd.DataFrame({&#34;日期&#34;: dates, &#34;销售额&#34;: sales})

# 绘制时序图
plt.figure(figsize=(15, 7))
sns.lineplot(x=&#34;日期&#34;, y=&#34;销售额&#34;, data=sales_data, color=&#34;#A23B72&#34;, linewidth=2)
plt.title(&#34;2024年每日销售额趋势&#34;, fontsize=14, fontweight=&#34;bold&#34;)
plt.xlabel(&#34;日期&#34;, fontsize=12)
plt.ylabel(&#34;销售额(元)&#34;, fontsize=12)
# 按月标注(避免x轴标签拥挤)
plt.xticks(pd.date_range(start=&#34;2024-01-01&#34;, end=&#34;2024-12-31&#34;, freq=&#34;MS&#34;), rotation=45)
plt.grid(alpha=0.3)
plt.tight_layout()
plt.savefig(&#34;销售额时序图.png&#34;, dpi=300)
plt.show()

五、可视化优化技巧(避坑指南)

1. 避免常见问题

  • 中文乱码 :必须配置plt.rcParams[&#34;font.sans-serif&#34;]plt.rcParams[&#34;axes.unicode_minus&#34;]
  • 图表模糊 :保存时设置dpi=300,避免默认dpi=100;
  • 标签截断 :使用plt.tight_layout()bbox_inches=&#34;tight&#34;
  • 配色混乱:优先使用Seaborn预设配色(如Set2、coolwarm),避免高对比度配色。

2. 批量绘制子图

适用于一次性展示多个特征分布:

python 复制代码
# 批量绘制4个子图(2行2列)
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
axes = axes.flatten()  # 展平轴数组,方便遍历

# 子图1:月薪直方图
axes[0].hist(data[&#34;月薪&#34;], bins=30, alpha=0.7, color=&#34;#A23B72&#34;)
axes[0].set_title(&#34;月薪分布&#34;, fontsize=12, fontweight=&#34;bold&#34;)

# 子图2:年龄箱线图
sns.boxplot(y=&#34;年龄&#34;, data=data, ax=axes[1], color=&#34;#F18F01&#34;)
axes[1].set_title(&#34;年龄分布&#34;, fontsize=12, fontweight=&#34;bold&#34;)

# 子图3:工作年限计数图
sns.countplot(x=&#34;工作年限&#34;, data=data, ax=axes[2], palette=&#34;Set2&#34;)
axes[2].set_title(&#34;工作年限分布&#34;, fontsize=12, fontweight=&#34;bold&#34;)
axes[2].tick_params(axis=&#34;x&#34;, rotation=45)  # x轴标签旋转

# 子图4:绩效得分核密度图
sns.kdeplot(data[&#34;绩效得分&#34;], ax=axes[3], color=&#34;#2E86AB&#34;)
axes[3].set_title(&#34;绩效得分分布&#34;, fontsize=12, fontweight=&#34;bold&#34;)

# 全局标题
fig.suptitle(&#34;员工数据多特征分布&#34;, fontsize=16, fontweight=&#34;bold&#34;, y=0.98)
plt.tight_layout()
plt.savefig(&#34;多特征分布子图.png&#34;, dpi=300)
plt.show()
相关推荐
路边草随风2 小时前
python获取飞书文档内容
python·aigc·飞书
Q_Q5110082852 小时前
python+django/flask+vue基于spark的西南天气数据的分析与应用系统
spring boot·python·spark·django·flask·node.js
深圳佛手2 小时前
LangChain 提供的搜素工具SerpAPIWrapper介绍
开发语言·人工智能·python
坐吃山猪2 小时前
BrowserUse06-源码-DOM模块
python·llm·browser-use
路边草随风2 小时前
llama_index简单使用
人工智能·python·llama
Q_Q5110082852 小时前
python+springboot+django/flask基于深度学习的旅游推荐系统
spring boot·python·django·flask·node.js·php
梨落秋霜2 小时前
Python入门篇【if判断语句】
android·java·python
宝贝儿好2 小时前
【强化学习】第二章:老虎机问题、ε-greedy算法、指数移动平均
人工智能·python·算法
闲人编程2 小时前
Flask-SQLAlchemy高级用法:关系建模与复杂查询
后端·python·flask·一对多·多对多·一对一·自引用