Python数据分析与可视化入门:Pandas清洗数据结合Matplotlib绘图

云舒
云舒
发布时间:2026-11-09| 17人浏览过
原创

本文系统讲解Python数据分析与可视化入门流程,演示如何使用Pandas检测缺失值、剔除重复项、转换类型与规整数据,并结合Matplotlib面向对象接口绘制专业趋势图与对比图。

在实际业务场景中,直接拿到的原始数据往往夹杂着缺失值、类型错误、格式混乱和重复记录,未经处理直接调用绘图函数往往会导致程序报错或生成具有严重偏差的图表。完成一次可靠的数据分析,标准解决路径是先用 Pandas 对数据进行全面探查、清洗转换与维度聚合,理顺数据类型和度量指标,再通过 Matplotlib 的面向对象接口进行精准的视觉映射。本文以一份常见的商户线上交易数据为例,分步演示从读取脏数据、清洗治理到绘制时间趋势线与类别对比条形图的完整流程。
Python数据分析与可视化入门:Pandas清洗数据结合Matplotlib绘图
图 0:数据分析与可视化协同处理总览(脏数据输入 ➔ Pandas清洗引擎 ➔ Matplotlib视觉输出)

一、环境准备与业务脏数据样本构建

进行本篇操作需要安装两个 Python 核心库:数据分析库 pandas 与基础可视化库 matplotlib。在终端或命令行中执行以下命令即可完成安装:

pip install pandas matplotlib

为了让演示具有真实参考价值,我们构造一份包含典型“脏数据特征”的电商销售记录。这份样本包含了初学者最常遇到的几类缺陷:单价带有货币符号导致被识别为文本、下单时间格式不统一、关键销售额存在缺失(NaN)、包含完全重复的记录,以及商品类别字段存在尾部空格。

以下是生成并加载该模拟数据的完整代码:

import pandas as pd
import numpy as np

# 模拟构建包含常见脏数据问题的初始交易数据集
raw_data = {
    'order_id': ['A101', 'A102', 'A103', 'A104', 'A105', 'A101', 'A106'],
    'order_date': ['2023-10-01', '2023/10/02', '2023-10-02', '2023-10-03', '2023-10-03', '2023-10-01', '2023-10-04'],
    'category': ['电子数码 ', '办公文具', '家居生活', '电子数码', '办公文具 ', '电子数码 ', '家居生活'],
    'unit_price': ['¥199.0', '¥25.5', '¥88.0', '¥299.0', '¥45.0', '¥199.0', '¥120.0'],
    'quantity': [2, 4, 1, 1, np.nan, 2, 3],
    'total_amount': [398.0, 102.0, np.nan, 299.0, 45.0, 398.0, 360.0]
}

df = pd.DataFrame(raw_data)
print("【原始数据预览】:\n", df)

拿到数据后的第一件事不是直接上手绘图,而是调用 df.info() 与 df.isnull().sum() 进行全貌诊断。

print("\n【字段信息与数据类型诊断】:\n")
df.info()
print("\n【各列缺失值统计】:\n", df.isnull().sum())

控制台将输出以下关键特征(此为示例输出):

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 7 entries, 0 to 6
Data columns (total 6 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   order_id      7 non-null      object 
 1   order_date    7 non-null      object 
 2   category      7 non-null      object 
 3   unit_price    7 non-null      object 
 4   quantity      6 non-null      float64
 5   total_amount  6 non-null      float64
dtypes: float64(2), object(4)

从探测结果中可以明确发现三处阻碍绘图的硬伤:

  1. order_date 是 object(文本)类型且混有斜杠与短横线,无法按真实时间周期排序和按天对齐;
  2. unit_price 含有货币符号字符 ¥,导致本应为数字的列被判定为 object,无法进行算术求和;
  3. total_amount 与 quantity 存在 NaN 缺失,直接计算平均值或绘图会导致数据脱节。

二、Pandas 核心数据清洗五步法

针对探查发现的问题,我们按照“文本规整 ➔ 类型转换 ➔ 缺失填补 ➔ 重复剔除 ➔ 异常过滤”的标准流水线进行处理。

Python数据分析与可视化入门:Pandas清洗数据结合Matplotlib绘图
图 1:Pandas 业务数据清洗标准化五步工序流程图

步骤一:文本空格清除与非法字符剥离

在类别列中,'电子数码 ' 带有尾随空格,这会导致后续 groupby 将其视作两个完全不同的独立分类。同时,单价列含有字符 ¥。我们使用 Pandas 的向量化字符串访问器 .str 分别进行清理:

# 1. 清理分类文本的首尾多余空格
df['category'] = df['category'].str.strip()

# 2. 去除单价中的人民币符号 '¥'
df['unit_price'] = df['unit_price'].str.replace('¥', '', regex=False)

步骤二:数据类型显式转换

将剥离符号后的 unit_price 转换为高精度浮点数 float,并将混杂格式的 order_date 通过 pd.to_datetime() 统一解析为标准时间戳:

# 转换为数值型浮点数
df['unit_price'] = df['unit_price'].astype(float)

# 转换为标准 DatetimeIndex 兼容的时间戳
df['order_date'] = pd.to_datetime(df['order_date'])

步骤三:缺失值诊断与业务逻辑填补

在样本数据中,第 2 行的 total_amount 为 NaN,而该行的单价与数量均已知;第 4 行的 quantity 为 NaN。在实际业务中,应优先利用已知字段的勾稽关系(总金额 = 单价 × 数量)进行精准推导填补,而非简单地盲目删除:

# 根据业务逻辑:若 total_amount 缺失但单价与数量齐全,则自动计算填补
mask_amount_nan = df['total_amount'].isna() & df['quantity'].notna()
df.loc[mask_amount_nan, 'total_amount'] = df['unit_price'] * df['quantity']

# 反向逻辑:若数量缺失但总金额与单价齐全,推导数量
mask_qty_nan = df['quantity'].isna() & df['total_amount'].notna()
df.loc[mask_qty_nan, 'quantity'] = df['total_amount'] / df['unit_price']
注意:如果某些记录的核心关键字段(例如同时缺少单价和总额)无法通过逻辑推导且空值占比较低,建议使用 df.dropna(subset=['total_amount']) 直接剔除,以防引入虚假均值污染分析结果。

步骤四:剔除重复记录与边界逻辑校验

检查是否存在重复上报的订单记录。使用 drop_duplicates 保证每条交易在分析库中唯一存在:

# 查看重复条数
duplicate_count = df.duplicated(subset=['order_id']).sum()
print(f"发现重复订单记录数:{duplicate_count}")

# 仅保留第一条记录,剔除后续冗余重复项
df = df.drop_duplicates(subset=['order_id'], keep='first').copy()

# 过滤金额小于等于0的异常脏数据
df = df[df['total_amount'] > 0].reset_index(drop=True)

print("\n【清洗完成后的合规数据集】:\n", df)

三、数据聚合与准备:从明细到绘图输入

清洗后的 DataFrame 属于明细宽表。直接绘制折线图或条形图时,往往需要先按“分析维度”聚合出清晰的度量指标。

Python数据分析与可视化入门:Pandas清洗数据结合Matplotlib绘图
图 2:Pandas 数据模型与 Matplotlib 画布对象的传递映射机制

为了支撑后续的可视化任务,我们从清洗后的数据中提炼出两个维度的聚合数据:

  1. 时间维度聚合(趋势线):按 order_date 统计每日销售总额;
  2. 品类维度聚合(对比图):按 category 统计各品类的销售总额并按从大到小排序。
# 1. 时间维度:按天汇总结算
daily_sales = df.groupby('order_date')['total_amount'].sum().reset_index()

# 2. 品类维度:按类别汇总并排序(便于条形图展现阶梯感)
category_sales = df.groupby('category')['total_amount'].sum().sort_values(ascending=True)

print("\n【每日销售总额】:\n", daily_sales)
print("\n【各品类销售总额】:\n", category_sales)

四、Matplotlib 绘图实战:面向对象 API 核心范式

很多初学者习惯直接使用 plt.plot() 这类快捷接口,但在多子图控制、坐标格式精细调节和批量导出时极易产生样式串扰。在生产环境中,推荐始终采用面向对象 API(Object-Oriented API),即通过 fig, ax = plt.subplots() 显式获得画布容器(Figure)与坐标系(Axes)。

Python数据分析与可视化入门:Pandas清洗数据结合Matplotlib绘图
图 3:Matplotlib 面向对象调用流水线与坐标系组件剖析图

中文字体与负号显示避坑配置

Matplotlib 默认缺少对中文无衬线字体的指向,如果不做配置,图表中的所有中文字符都会显示为乱码方块(Tofu box),并且负号容易被误渲染为缺失字符。绘图前务必加入以下两行配置:

import matplotlib.pyplot as plt

# 设置中文字体回退列表与正常显示负号
plt.rcParams['font.sans-serif'] = ['PingFang SC', 'Microsoft YaHei', 'SimHei', 'sans-serif']
plt.rcParams['axes.unicode_minus'] = False

案例 1:绘制每日销售额走势折线图

使用面向对象方式将 daily_sales 绘制为时间序列折线图,包含网格线、数据标记点与日期倾斜排版:

# 1. 创建画布与独立坐标系
fig, ax = plt.subplots(figsize=(8, 4.2), dpi=100)

# 2. 绘制折线图,设置线宽、主色与节点圆圈
ax.plot(
    daily_sales['order_date'],
    daily_sales['total_amount'],
    marker='o',
    markersize=6,
    color='#17324D',      # 深海蓝主色
    linewidth=2,
    label='每日营收'
)

# 3. 装饰标题、轴标签与参考网格
ax.set_title('2023年10月每日销售额变化趋势', fontsize=13, fontweight='bold', pad=12, color='#17324D')
ax.set_xlabel('下单日期', fontsize=11, color='#475569')
ax.set_ylabel('销售金额 (元)', fontsize=11, color='#475569')
ax.grid(True, linestyle='--', alpha=0.4, color='#94A3B8')
ax.legend(frameon=True, facecolor='#FFFFFF', edgecolor='#E2E8F0')

# 4. 自动旋转日期标签避免重叠粘连
fig.autofmt_xdate(rotation=30)
fig.tight_layout()

# 5. 导出并及时关闭图表对象
fig.savefig('daily_trend.png', dpi=300)
plt.close(fig)

案例 2:绘制品类销售对比水平条形图

当类别名称较长或分类较多时,水平条形图(ax.barh)比普通纵向柱状图(ax.bar)更易阅读,因为水平文字无须倾斜即可完整展现。我们利用 ax.bar_label 直接在条形顶端打上具体数值标签:

# 创建画布
fig, ax = plt.subplots(figsize=(8, 4.2), dpi=100)

categories = category_sales.index
amounts = category_sales.values

# 绘制水平条形图,采用灰青强调色
bars = ax.barh(categories, amounts, color='#659B9B', height=0.55)

# 在柱子右侧标注精准数值
ax.bar_label(bars, fmt='¥%.1f', padding=5, color='#17324D', fontweight='bold')

# 优化边框与坐标范围
ax.set_title('各商品品类总销售额对比', fontsize=13, fontweight='bold', pad=12, color='#17324D')
ax.set_xlabel('总金额 (元)', fontsize=11, color='#475569')
ax.set_xlim(0, max(amounts) * 1.18)  # 留出右侧空间容纳文本标签
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.grid(axis='x', linestyle=':', alpha=0.5)

fig.tight_layout()
fig.savefig('category_comparison.png', dpi=300)
plt.close(fig)

五、常见问题排查与避坑要点

初学者将 Pandas 与 Matplotlib 结合使用时,往往会在以下四个环节遭遇非预期的报错或图表异样:

  • SettingWithCopyWarning 警告:对过滤后的切片 DataFrame 直接赋值时,Pandas 会发出警告。根本原因在于系统无法确定操作的是视图(View)还是副本(Copy)。解决方法是在切片或过滤后显式附加 .copy(),例如 df = df[df['amount'] > 0].copy()。
  • 日期刻度挤压重叠:当时间跨度较长、日期点密集时,X 轴文本极易连成一片黑块。除了使用 fig.autofmt_xdate() 旋转外,还可以引入 matplotlib.dates.DayLocator(interval=N) 强制按固定步长稀疏显示刻度。
  • 连续数值被误作离散分类绘图:如果在清洗阶段漏掉了 .astype(float),原本为数值的列依然是 object。Matplotlib 会将每个数字字符串当作一个互不相关的独立分类标签绘制,导致坐标轴刻度失去连续数值比例尺。
  • 循环绘图引发显存与内存泄漏:在批量处理数百份报告或轮询绘图时,仅调用 plt.savefig() 并不会销毁底层对象。务必在图表保存后显式调用 plt.close(fig) 彻底释放图形句柄。
Python数据分析与可视化入门:Pandas清洗数据结合Matplotlib绘图
图 4:常见数据分析任务、Pandas 聚合手段与 Matplotlib 选型总结矩阵

六、端到端完整复现脚本

将前述所有清洗步骤与双子图面板(Dashboard)整合为单个可独立执行的 Python 脚本。读者可直接复制并在本地环境中运行验证:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 1. 字体环境初始化
plt.rcParams['font.sans-serif'] = ['PingFang SC', 'Microsoft YaHei', 'SimHei', 'sans-serif']
plt.rcParams['axes.unicode_minus'] = False

# 2. 模拟真实脏数据
raw_data = {
    'order_id': ['A101', 'A102', 'A103', 'A104', 'A105', 'A101', 'A106'],
    'order_date': ['2023-10-01', '2023/10/02', '2023-10-02', '2023-10-03', '2023-10-03', '2023-10-01', '2023-10-04'],
    'category': ['电子数码 ', '办公文具', '家居生活', '电子数码', '办公文具 ', '电子数码 ', '家居生活'],
    'unit_price': ['¥199.0', '¥25.5', '¥88.0', '¥299.0', '¥45.0', '¥199.0', '¥120.0'],
    'quantity': [2, 4, 1, 1, np.nan, 2, 3],
    'total_amount': [398.0, 102.0, np.nan, 299.0, 45.0, 398.0, 360.0]
}
df = pd.DataFrame(raw_data)

# 3. 标准化清洗处理
df['category'] = df['category'].str.strip()
df['unit_price'] = df['unit_price'].str.replace('¥', '', regex=False).astype(float)
df['order_date'] = pd.to_datetime(df['order_date'])

# 逻辑补齐缺失值
mask_amount = df['total_amount'].isna() & df['quantity'].notna()
df.loc[mask_amount, 'total_amount'] = df['unit_price'] * df['quantity']

mask_qty = df['quantity'].isna() & df['total_amount'].notna()
df.loc[mask_qty, 'quantity'] = df['total_amount'] / df['unit_price']

# 去重与边界过滤
df = df.drop_duplicates(subset=['order_id'], keep='first')
df = df[df['total_amount'] > 0].copy()

# 4. 聚合计算
daily_sales = df.groupby('order_date')['total_amount'].sum().reset_index()
category_sales = df.groupby('category')['total_amount'].sum().sort_values(ascending=True)

# 5. 组合画布面向对象绘制 (1行2列看板)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13, 5), dpi=100)

# 子图 1:销售趋势折线
ax1.plot(daily_sales['order_date'], daily_sales['total_amount'], marker='o', color='#17324D', lw=2.2)
ax1.set_title('每日销售走势', fontsize=12, fontweight='bold', color='#17324D')
ax1.set_ylabel('销售额 (元)')
ax1.grid(True, linestyle='--', alpha=0.4)
fig.autofmt_xdate(rotation=25)

# 子图 2:品类对比条形
bars = ax2.barh(category_sales.index, category_sales.values, color='#659B9B', height=0.55)
ax2.bar_label(bars, fmt='¥%.1f', padding=4, color='#17324D', fontweight='bold')
ax2.set_title('品类总营收对比', fontsize=12, fontweight='bold', color='#17324D')
ax2.set_xlim(0, max(category_sales.values) * 1.2)
ax2.spines['top'].set_visible(False)
ax2.spines['right'].set_visible(False)

fig.tight_layout()
fig.savefig('sales_analysis_dashboard.png', dpi=300)
plt.close(fig)
print("\n数据分析与图表生成执行完成,图像已保存为 sales_analysis_dashboard.png")

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。