
本教程面向零基础用户,手把手教你如何使用 Python(Pandas、Matplotlib、Seaborn)从 Excel 数据导入、清洗到多维度分析与可视化,覆盖环境搭建、数据预处理、分组统计、折线图、柱状图、饼图、散点图、箱线图等常见图表绘制技巧,并演示结果导出与报告生成全流程。无论你是刚接触 Python 数据分析,还是想提升 Excel 报表处理效率,都能通过本指南快速上手,实现“Excel → Python 代码操作 →可视化图表”一站式学习,掌握现代化数据分析与可视化方法。

在日常工作或学习中,经常会面对成百上千行的表格数据:销售报表、财务明细、学生成绩等。传统上,我们会用 Excel 做简单的筛选、排序、求和、制图等操作,但一旦数据量增大、指标复杂、必须批量处理或自动化分析时,就会显得力不从心。
Python 作为一门强大的编程语言,拥有丰富且成熟的数据分析与可视化生态(如 Pandas、NumPy、Matplotlib、Seaborn、Plotly 等),可以轻松完成从读取、清洗、转换到统计、可视化的一系列工作。而且,Python 代码易于复用、可扩展,适合重复性工作流的自动化、报告生成、数据监控等场景。
本教程将从零开始,带领完全没有编程基础的朋友一步步学会:
通过本教程,你可以掌握完整的“Excel → Python 代码操作 → 可视化图表”流程,为今后在各类数据分析任务中打下坚实基础。
为了让初学者快速上手,推荐通过 Anaconda(集成了 Python、Jupyter Notebook、常用科学计算库)来安装。Anaconda 会帮你预装好绝大多数常用的包,无需逐个安装。以下步骤以 Windows 系统为例,Mac/Linux 基本类似。
下载 Anaconda
安装 Anaconda
C:\Users\<用户名>\anaconda3)测试是否安装成功
打开 “Anaconda Prompt” (Windows)或终端(macOS/Linux),输入:
python --version如果返回类似 Python 3.x.x,说明安装成功。
输入:
conda list可以看到一系列已安装的包,比如 pandas, numpy, matplotlib, seaborn 等。
提示:如果你习惯手动安装 Python,也可以去 python.org 下载安装包,但之后需要自行用
pip install安装各类库。本教程以 Anaconda 为例进行演示。
本教程后续示例会以 Jupyter Notebook 为主。若你使用 VS Code,概念是一致的,只是新建 .ipynb 文件或 .py 文件并运行的方式不同。
大多数常用库 Anaconda 已预装,如果偶尔缺少某个包,请在终端(或 Anaconda Prompt)里执行:
# 如果还没有安装 pandas、matplotlib、seaborn,可以手动安装:
conda install pandas matplotlib seaborn openpyxl -y.xlsx 格式 Excel 文件。(pandas 底层调用它)在开始编写代码前,我们先准备一个简单的 Excel 文件,方便示例演示与练习。 假设我们有一份 “公司月度销售数据.xlsx”,内容如下(以下截图仅做示意,可以手动在 Excel 中创建或用现有数据替换):
月份 | 地区 | 产品类别 | 销售数量 | 单价(元) | 销售额(元) |
|---|---|---|---|---|---|
2024-01 | 华东 | A | 120 | 50 | 6000 |
2024-01 | 华北 | B | 85 | 70 | 5950 |
2024-01 | 华南 | A | 95 | 50 | 4750 |
2024-02 | 华东 | B | 110 | 70 | 7700 |
2024-02 | 华北 | A | 100 | 50 | 5000 |
2024-02 | 华南 | B | 90 | 70 | 6300 |
2024-03 | 华东 | A | 130 | 50 | 6500 |
2024-03 | 华北 | B | 95 | 70 | 6650 |
2024-03 | 华南 | A | 105 | 50 | 5250 |
… | … | … | … | … | … |
你可以将上述表格保存为 company_sales.xlsx,并放置在本地某个文件夹中,比如 C:\Users\<用户名>\Documents\data\company_sales.xlsx。
建议:创建一个专门的项目文件夹,例如
C:\Users\<用户名>\Documents\py_data_analysis\。将 Excel 文件及后续所有.ipynb文件都放在此文件夹下,路径清晰易管理。
py_data_analysis),点击 “New” → 选择 “Python 3” 新建一个 Notebook,命名为 sales_analysis.ipynb。或者在命令行中进入目录后运行:
jupyter notebook即可自动打开默认浏览器,进入项目文件夹后新建 Notebook。
在第一个单元格中,输入以下代码并运行(Shift + Enter):
import pandas as pd # 数据处理
import numpy as np # 数值计算(可选)
import matplotlib.pyplot as plt # 基础可视化
import seaborn as sns # 进一步美化可视化(可选)
# 让绘图结果直接在 Notebook 中显示
%matplotlib inline
# 设置更美观的 Seaborn 样式(可选)
sns.set_style("whitegrid")pd 是 Pandas 的常见别名。%matplotlib inline:让 Matplotlib 绘图结果嵌入到 Notebook 中。sns.set_style("whitegrid"):让 Seaborn 为后续图表设置白色网格背景,增强可读性。如果你不想使用 Seaborn,也可以不导入,后续全部用 Matplotlib 即可。
pd.read_excel 读取数据假设我们已经将 company_sales.xlsx 放在项目根目录下,路径就是 ./company_sales.xlsx。在第二个单元格输入:
# 读取 Excel 中第一个 sheet(默认是第一个)到 DataFrame
file_path = "company_sales.xlsx" # 如果 Notebook 与 Excel 文件在同一目录
df = pd.read_excel(file_path)
# 如果你的文件有多个 sheet,可以通过 sheet_name 参数指定
# df = pd.read_excel(file_path, sheet_name="Sheet1")运行后,Pandas 会自动根据 Excel 中的列名与数据类型创建 DataFrame,存储在 df 变量中。
在新的单元格中,依次执行以下操作,了解数据概况:
# 查看前 5 行数据
df.head()head() 默认显示前 5 行,用于快速检查数据列名和部分值。# 查看数据维度(行数、列数)
df.shape(n_rows, n_columns),告诉我们数据有多少行、多少列。# 查看各列的数据类型与是否存在缺失值
df.info()info() 会显示每一列的名称、非空值数量、数据类型,方便判断是否有空值或类型混乱。# 查看数值型列的描述性统计
df.describe()describe() 会对数值列计算计数、均值、标准差、最小值、四分位数、最大值等指标,帮助快速了解数据分布情况。# 查看是否有缺失值统计
df.isnull().sum()isnull().sum() 会输出每一列缺失值的数量,用于判断是否需要做后续的缺失值处理。如果前几行已经能看懂原始 Excel 数据的结构与内容,就可以继续:列名(“月份”、“地区”、“产品类别”、“销售数量”、“单价(元)”、“销售额(元)”)、行数、是否存在空值等。
注意:若 read_excel 遇到无法解析的列名或日期类型有误,可以通过参数 dtype 或 parse_dates 强制指定列类型。例如:
df = pd.read_excel(file_path, dtype={"销售数量": int, "单价(元)": float})
df = pd.read_excel(file_path, parse_dates=["月份"])真实项目中,Excel 数据往往存在:空值、错误值、列名不规范、数据类型不一致等问题。下面演示常见清洗步骤。
# 先统计各列缺失值数量(已在上文执行过)
df.isnull().sum()假设出现少量缺失值,根据业务需求决定处理方式:
删除含缺失值的行:当缺失值行很少且对整体影响不大时,可直接删除。
df_dropna = df.dropna(axis=0, how="any") # 删除任意列有缺失值的行用特定值填充:如数值类列用 0、均值、中位数填充,类别型列用“未知”或众数填充。
# 示例:用平均值填充“销售数量”中的缺失值
mean_qty = df["销售数量"].mean()
df["销售数量"].fillna(mean_qty, inplace=True)
# 用“未知”填充“地区”缺失值
df["地区"].fillna("未知", inplace=True)按组填充:对分组后的缺失值,用同组的均值/中位数填充。
# 例如:按“产品类别”分组,用每类的平均“单价(元)”填充该类的缺失值
df["单价(元)"] = df.groupby("产品类别")["单价(元)"].apply(lambda x: x.fillna(x.mean()))Tip:对于时间序列数据,也常用 “前向填充” 或 “后向填充”:
df.sort_values("月份", inplace=True)
df["销售额(元)"].fillna(method="ffill", inplace=True) # 前向填充
df["销售额(元)"].fillna(method="bfill", inplace=True) # 后向填充有时 Excel 中的列名过长、包含空格或奇怪字符,不利于后续编码,可重命名为易操作的英文或简短中文。
# 假设目前列名是 ["月份", "地区", "产品类别", "销售数量", "单价(元)", "销售额(元)"]
# 我们将其重命名为: Month, Region, Category, Quantity, UnitPrice, SalesAmount
df.rename(columns={
"月份": "Month",
"地区": "Region",
"产品类别": "Category",
"销售数量": "Quantity",
"单价(元)": "UnitPrice",
"销售额(元)": "SalesAmount"
}, inplace=True)
# 再次查看:
df.head()筛选数据:比如只保留 2024 年的数据,或只看华东地区。
# 假设 Month 列类型为字符串 "2024-01", "2024-02"。先将其转换为 datetime 类型:
df["Month"] = pd.to_datetime(df["Month"], format="%Y-%m")
# 筛选出 2024 年的数据
df_2024 = df[df["Month"].dt.year == 2024]
# 筛选出“华东”地区的所有记录
df_huadong = df[df["Region"] == "华东"]datetime 类型,方便后续按年月、季度等分析。# 举例:如果“UnitPrice” 列是字符串,如 "¥50.00" 或 "1,200":
df["UnitPrice"] = df["UnitPrice"].astype(str).str.replace("¥", "").str.replace(",", "").astype(float)category 类型,节省内存并加快运算。df["Region"] = df["Region"].astype("category")
df["Category"] = df["Category"].astype("category")Quantity * UnitPrice 生成:df["SalesAmount"] = df["Quantity"] * df["UnitPrice"]df["Year"] = df["Month"].dt.year
df["MonthNum"] = df["Month"].dt.month
df["Quarter"] = df["Month"].dt.to_period("Q")# 按 Region 分组,计算月度销售额的累计和
df["CumulativeSales"] = df.groupby("Region")["SalesAmount"].cumsum()
# 计算销售额的 3 个月移动平均值
df["Rolling3Months_Sales"] = df.groupby("Region")["SalesAmount"].transform(lambda x: x.rolling(window=3, min_periods=1).mean())这些新列在后续可视化与分析时非常有用,比如趋势图、环比分析等。
下面给出几个常见的统计与分组示例,帮助你快速掌握 Pandas 的 聚合(Aggregation) 与 分组(GroupBy) 操作。
# 全局统计:查看所有数值列的均值、总和、最小值、最大值等
df.describe()
# 单列统计:计算“SalesAmount”总和、均值、中位数、最大/最小
total_sales = df["SalesAmount"].sum()
mean_sales = df["SalesAmount"].mean()
median_sales = df["SalesAmount"].median()
max_sales = df["SalesAmount"].max()
min_sales = df["SalesAmount"].min()
print(f"总销售额:{total_sales:.2f} 元")
print(f"平均销售额:{mean_sales:.2f} 元")
print(f"中位数销售额:{median_sales:.2f} 元")
print(f"最高单条记录销售额:{max_sales:.2f} 元")
print(f"最低单条记录销售额:{min_sales:.2f} 元")groupby假设我们想了解各 地区(Region) 的总销售额与平均销售额:
# 按 Region 分组,聚合计算
sales_by_region = df.groupby("Region")["SalesAmount"].agg(["sum", "mean", "count"]).reset_index()
# 重命名列,方便阅读
sales_by_region.rename(columns={
"sum": "TotalSales",
"mean": "AvgSales",
"count": "RecordCount"
}, inplace=True)
sales_by_region输出示例:
Region | TotalSales | AvgSales | RecordCount |
|---|---|---|---|
华北 | 14600.00 | 7300.00 | 2 |
华东 | 20200.00 | 6733.33 | 3 |
华南 | 16300.00 | 5433.33 | 3 |
groupby("Region")["SalesAmount"]:按 “Region” 分组,只对 “SalesAmount” 一列进行统计。.agg(["sum", "mean", "count"]):一次性计算总和、均值、计数等指标。.reset_index():把“Region”从索引变成普通列,方便后续处理。如果想一次性对多列、多函数执行分组聚合,也可以传字典。例如:对 “Quantity” 和 “SalesAmount” 都计算总和与均值:
agg_dict = {
"Quantity": ["sum", "mean"],
"SalesAmount": ["sum", "mean"]
}
grouped = df.groupby("Region").agg(agg_dict)
# 默认结果会出现多层列索引(MultiIndex),可手动平铺列名:
grouped.columns = ["_".join(col) for col in grouped.columns]
grouped = grouped.reset_index()
grouped输出示例:
Region | Quantity_sum | Quantity_mean | SalesAmount_sum | SalesAmount_mean |
|---|---|---|---|---|
华北 | 180 | 90.00 | 14600.00 | 7300.00 |
华东 | 360 | 120.00 | 20200.00 | 6733.33 |
华南 | 290 | 96.67 | 16300.00 | 5433.33 |
pivot_table如果想同时按 “Region” 和 “Category” 查看销售额情况,可使用 pivot_table:
pivot = pd.pivot_table(
df,
values="SalesAmount",
index="Region",
columns="Category",
aggfunc="sum",
fill_value=0 # 如果某个“Region+Category”组合缺失,用 0 填充
).reset_index()
pivot输出示例:
Region | A_sales | B_sales |
|---|---|---|
华北 | 5000 | 9600 |
华东 | 12500 | 7700 |
华南 | 10000 | 6300 |
你也可以在 pivot_table 中同时聚合多个值:
pivot2 = pd.pivot_table(
df,
values=["Quantity", "SalesAmount"],
index="Region",
columns="Category",
aggfunc={"Quantity": "sum", "SalesAmount": "mean"},
fill_value=0
)结果同样会出现多层列索引,需要注意查看与重命名。
在完成数据清洗与统计聚合后,我们通常要把结果通过图表展示出来,让结论一目了然。本节主要介绍 Matplotlib、Pandas 内置绘图接口 以及 Seaborn 的常见用法,帮助你绘制以下几种常见图表:
在示例中,我们假设 DataFrame 命名为 df,并且已经完成必要的列重命名与类型转换。
Matplotlib 是 Python 最基础的绘图库,后续很多高级库都基于它封装。一般导入时会写成:
import matplotlib.pyplot as plt然后,绘制一个简单的折线图示例:
# 1. 生成示例数据
months = ["2024-01", "2024-02", "2024-03", "2024-04", "2024-05", "2024-06"]
sales = [6000, 7700, 6500, 7200, 8100, 9000]
# 2. 创建图形对象和坐标轴
plt.figure(figsize=(10, 6)) # figsize: 宽为10英寸、高为6英寸
# 3. 绘制折线图
plt.plot(months, sales, marker="o", linestyle="-", label="销售额 (元)")
# 4. 添加标题与坐标轴标签
plt.title("2024年上半年月度销售趋势")
plt.xlabel("月份")
plt.ylabel("销售额 (元)")
# 5. 添加图例
plt.legend()
# 6. 添加网格(可选)
plt.grid(True)
# 7. 设置 x 轴刻度旋转角度,避免文字拥挤
plt.xticks(rotation=45)
# 8. 展示图表
plt.tight_layout() # 调整布局,防止标签超出边界
plt.show()plt.figure(figsize=(10, 6)):创建一个宽 10 英寸、高 6 英寸的画布;plt.plot(x, y, marker="o", linestyle="-", label="..."):绘制折线图,并在数据点处加圆点,label 用于在图例中显示;plt.title(), plt.xlabel(), plt.ylabel():设置标题与坐标轴说明文字;plt.legend():显示图例;plt.grid(True):开启网格线;plt.xticks(rotation=45):将 x 轴刻度标签旋转 45°,方便阅读;plt.tight_layout():自动调整子图参数,使之填充整个图像区域;plt.show():展示图表。假设我们有一个 DataFrame sales_by_region,含两列:Region (地区) 和 TotalSales (总销售额)。示例数据如下:
Region | TotalSales |
|---|---|
华北 | 14600.00 |
华东 | 20200.00 |
华南 | 16300.00 |
绘制柱状图:
# 示例数据
regions = sales_by_region["Region"]
totals = sales_by_region["TotalSales"]
plt.figure(figsize=(8, 5))
plt.bar(regions, totals, width=0.5) # width 控制柱子宽度
# 添加标题与标签
plt.title("各地区总销售额对比")
plt.xlabel("地区")
plt.ylabel("总销售额 (元)")
# 在柱子上方显示具体数值
for i, v in enumerate(totals):
plt.text(i, v + 500, f"{v:.0f}", ha="center") # ha: horizontalalignment
plt.tight_layout()
plt.show()plt.bar(x, height):其中 x 是分类标签列表,height 是对应数值;plt.text(i, v + 偏移量, 文本, ha="center"):在第 i 个柱子的顶部稍微偏上一点处,显示具体数字;width=0.5:柱子宽度,范围一般在 (0,1]。适合展示两个连续型变量之间的关系。假设我们有一份包含 UnitPrice (单价) 和 Quantity (销量) 的数据,想看两者是否存在相关性:
# 简化示例:使用原始 df
prices = df["UnitPrice"]
quantities = df["Quantity"]
plt.figure(figsize=(8, 6))
plt.scatter(prices, quantities, alpha=0.7) # alpha: 透明度([0,1])
plt.title("价格 vs 销量 散点图")
plt.xlabel("单价 (元)")
plt.ylabel("销售数量")
plt.grid(True)
# 可选:在图中添加一条线性拟合线
m, b = np.polyfit(prices, quantities, 1) # 线性拟合:quantity = m*price + b
plt.plot(prices, m * prices + b, color="red", linestyle="--", label="线性拟合")
plt.legend()
plt.tight_layout()
plt.show()plt.scatter(x, y, alpha=0.7):绘制散点,alpha 设置点的透明度;np.polyfit(x, y, 1):利用 NumPy 进行一次线性拟合,返回斜率 m 和截距 b;plt.plot(x, y_fit):在同一图上添加拟合直线。用于展示各部分占整体的比例。以 Category(产品类别) 为例,绘制不同类别销售额占比。
# 先做分组聚合
sales_by_category = df.groupby("Category")["SalesAmount"].sum().reset_index()
labels = sales_by_category["Category"]
sizes = sales_by_category["SalesAmount"]
plt.figure(figsize=(6, 6))
plt.pie(
sizes,
labels=labels,
autopct="%1.1f%%", # 百分比格式,保留一位小数
startangle=140, # 起始角度
explode=[0.05] * len(labels) # 将所有扇区稍微“炸开”一点
)
plt.title("产品类别销售额占比")
plt.axis("equal") # 使饼图为正圆形
plt.show()箱线图可以展示数据分布的中位数、四分位数及异常值。假设想看各地区单价分布情况:
plt.figure(figsize=(8, 6))
# 使用 DataFrame 的列名及列名对应的数据
plt.boxplot(
[df[df["Region"] == region]["UnitPrice"] for region in df["Region"].unique()],
labels=df["Region"].unique()
)
plt.title("各地区单价分布(箱线图)")
plt.xlabel("地区")
plt.ylabel("单价 (元)")
plt.grid(True, axis="y") # 只对 y 轴显示网格
plt.show()plt.boxplot([...], labels=[...]):第一个参数是一个列表,其中每个子列表都是要绘制箱线图的数据;labels 为对应的每个箱体名称。
也可以调用 Pandas 自带的 DataFrame.boxplot():
df.boxplot(column="UnitPrice", by="Region", figsize=(8,6))
plt.title("各地区单价分布(箱线图)")
plt.suptitle("") # 去掉默认的副标题
plt.xlabel("地区")
plt.ylabel("单价 (元)")
plt.show()Pandas DataFrame 与 Series 本身封装了绘图接口,底层调用 Matplotlib。优点是在分组后快速作图,不需要提取 x、y 列到 numpy 数组。示例:
# DataFrame 直接按 Region 分组,画总销售额柱状图
sales_by_region.set_index("Region")["TotalSales"].plot(
kind="bar",
figsize=(8, 5),
title="各地区总销售额对比",
legend=False
)
plt.ylabel("总销售额 (元)")
plt.tight_layout()
plt.show()df.plot(kind="bar"):kind 参数可以是 "line", "bar", "barh", "hist", "box", "pie", "scatter" 等。
优势:语法简洁,适用于快速探索性绘图。例如:
# 折线图:按照月份排序后,绘制销售额趋势
df.sort_values("Month").set_index("Month")["SalesAmount"].plot(
kind="line",
figsize=(10, 6),
marker="o",
title="2024 年销售额趋势"
)
plt.ylabel("销售额 (元)")
plt.tight_layout()
plt.show()Seaborn 是在 Matplotlib 之上封装的一款高级绘图库,默认配色和风格更美观,并且在统计图形上提供了更丰富的接口。常用导入:
import seaborn as sns
sns.set_style("whitegrid")条形图(Barplot):与柱状图类似,但可以额外显示置信区间。
plt.figure(figsize=(8, 6))
sns.barplot(
data=sales_by_region, # DataFrame
x="Region",
y="TotalSales",
palette="Blues_d" # 选择一个配色方案(可选)
)
plt.title("各地区总销售额对比(Seaborn)")
plt.ylabel("总销售额 (元)")
plt.xlabel("地区")
plt.tight_layout()
plt.show()折线图(Lineplot):
# 假设有一个 DataFrame df_monthly,包含 Month、Region、SalesAmount
plt.figure(figsize=(10, 6))
sns.lineplot(
data=df, # 原始 df 中包含 Month、Region、SalesAmount
x="Month",
y="SalesAmount",
hue="Region", # 按地区绘制多条折线
marker="o"
)
plt.title("各地区月度销售趋势(Seaborn)")
plt.ylabel("销售额 (元)")
plt.xlabel("月份")
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()散点图(Scatterplot):
plt.figure(figsize=(8, 6))
sns.scatterplot(
data=df,
x="UnitPrice",
y="Quantity",
hue="Region",
size="SalesAmount", # 点大小与销售额成正比
alpha=0.7
)
plt.title("价格 vs 销量 散点图(Seaborn)")
plt.ylabel("销售数量")
plt.xlabel("单价 (元)")
plt.tight_layout()
plt.show()箱线图(Boxplot):
plt.figure(figsize=(8, 6))
sns.boxplot(
data=df,
x="Region",
y="UnitPrice",
palette="Pastel2"
)
plt.title("各地区单价分布(箱线图,Seaborn)")
plt.ylabel("单价 (元)")
plt.xlabel("地区")
plt.tight_layout()
plt.show()热力图(Heatmap):适用于展示相关矩阵或透视表结果。示例:先生成相关矩阵,再可视化:
# 计算数值型列的相关系数矩阵
corr = df[["Quantity", "UnitPrice", "SalesAmount"]].corr()
plt.figure(figsize=(6, 5))
sns.heatmap(
corr,
annot=True, # 在格子中显示相关系数数值
fmt=".2f", # 数字格式
cmap="coolwarm" # 配色
)
plt.title("数值列相关系数矩阵_heatmap")
plt.tight_layout()
plt.show()总结:Matplotlib、Pandas 内置绘图与 Seaborn 各有优劣:
下面以 “某公司 2024 年月度销售数据” 为例,从头到尾演示一次完整流程。包括:读取、清洗、分析、可视化、保存结果。
假设你接到了一个任务:
**“请根据 2024 年 1-6 月各地区各产品类别的销售数据,完成以下任务:
为了演示,此处我们用 2024 年 1-3 月的手动示例,添加 4-6 月假设数据,表格示例结构如第 4 节所示。你只需将示例 Excel 扩充到 6 个月的数据即可。下面演示步骤。
首先,确认我们已经将 company_sales_2024_1-6.xlsx 文件放在工作目录下。假设文件名为 company_sales_2024.xlsx。
# 导入库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.set_style("whitegrid")
# 读取数据
file_path = "company_sales_2024.xlsx"
df = pd.read_excel(file_path)
# 快速查看前几行
df.head()如果输出与预期一致(包含 月份、地区、产品类别、销售数量、单价(元)、销售额(元) 等列),继续下一步。
# 重命名列为英文,方便后续操作
df.rename(columns={
"月份": "Month",
"地区": "Region",
"产品类别": "Category",
"销售数量": "Quantity",
"单价(元)": "UnitPrice",
"销售额(元)": "SalesAmount"
}, inplace=True)
# 将 Month 列由字符串转换为 datetime
df["Month"] = pd.to_datetime(df["Month"], format="%Y-%m")
# 将 Region 与 Category 转为 category 类型
df["Region"] = df["Region"].astype("category")
df["Category"] = df["Category"].astype("category")
# 检查是否有缺失值
df.isnull().sum()isnull().sum() 中有非零值),根据数据情况进行填充或删除。例如:# 假设缺失较少,直接删除含缺失行
df.dropna(axis=0, how="any", inplace=True)# 如果原始文件 “SalesAmount” 列存在,但是你想验证或重新生成
df["CalcSales"] = df["Quantity"] * df["UnitPrice"]
# 查看两列是否一致(可能存在浮点误差)
(df["SalesAmount"] - df["CalcSales"]).abs().sum()# 删除临时列
df.drop(columns="CalcSales", inplace=True)# 提取年份和月份数字
df["Year"] = df["Month"].dt.year
df["MonthNum"] = df["Month"].dt.month
# 如果需要季度
df["Quarter"] = df["Month"].dt.to_period("Q")df_2024 = df[df["Year"] == 2024].copy()# 先过滤出 2024 年 1-6 月的数据
df_first_half = df_2024[df_2024["MonthNum"].between(1, 6)]
# 按 Region 分组,求总销售额
sales_by_region_2024H1 = df_first_half.groupby("Region")["SalesAmount"].sum().reset_index()
sales_by_region_2024H1.rename(columns={"SalesAmount": "TotalSales_2024H1"}, inplace=True)
sales_by_region_2024H1假设输出如下:
Region | TotalSales_2024H1 |
|---|---|
华北 | 45000.00 |
华东 | 52000.00 |
华南 | 48000.00 |
假如你也有 company_sales_2023.xlsx 中 2023 年 1-6 月数据,可同样读取并聚合,然后合并对比:
# 读取去年数据
df_2023 = pd.read_excel("company_sales_2023.xlsx")
df_2023.rename(columns={/* 重命名同上 */}, inplace=True)
df_2023["Month"] = pd.to_datetime(df_2023["Month"], format="%Y-%m")
df_2023["Year"] = df_2023["Month"].dt.year
df_2023["MonthNum"] = df_2023["Month"].dt.month
df_2023H1 = df_2023[(df_2023["Year"] == 2023) & (df_2023["MonthNum"].between(1, 6))]
# 统计 2023 H1 各地区总销售额
sales_by_region_2023H1 = df_2023H1.groupby("Region")["SalesAmount"].sum().reset_index()
sales_by_region_2023H1.rename(columns={"SalesAmount": "TotalSales_2023H1"}, inplace=True)
# 合并
compare = pd.merge(
sales_by_region_2023H1,
sales_by_region_2024H1,
on="Region",
how="outer"
)
# 计算同比增长率
compare["YoY_Growth_Rate"] = (compare["TotalSales_2024H1"] - compare["TotalSales_2023H1"]) / compare["TotalSales_2023H1"] * 100
compare输出示例:
Region | TotalSales_2023H1 | TotalSales_2024H1 | YoY_Growth_Rate |
|---|---|---|---|
华北 | 42000.00 | 45000.00 | 7.14% |
华东 | 48000.00 | 52000.00 | 8.33% |
华南 | 46000.00 | 48000.00 | 4.35% |
如果没有去年数据,这一步可跳过,仅保留本年度分析。
下面将分别绘制:折线图、柱状图、散点图、饼图、箱线图,并讲解关键参数。
plt.figure(figsize=(10, 6))
sns.lineplot(
data=df_first_half,
x="Month",
y="SalesAmount",
hue="Region", # 按地区分线
marker="o",
palette="tab10" # 配色可选
)
plt.title("2024 年各地区月度销售趋势 (1-6 月)")
plt.xlabel("月份")
plt.ylabel("销售额 (元)")
plt.xticks(rotation=45)
plt.legend(title="地区")
plt.tight_layout()
plt.show()说明:
hue="Region" 会根据 “Region” 列的不同取值绘制多条折线,并自动生成图例;marker="o":在每个数据点画圆圈;palette="tab10":Seaborn 提供的一种配色方案,可根据需求替换;plt.xticks(rotation=45):旋转 x 轴刻度标签,避免重叠;plt.figure(figsize=(8, 5))
sns.barplot(
data=sales_by_region_2024H1,
x="Region",
y="TotalSales_2024H1",
palette="viridis"
)
# 在柱子上方显示数值
for idx, row in sales_by_region_2024H1.iterrows():
plt.text(
x=idx,
y=row["TotalSales_2024H1"] + 500, # 在柱顶上方 500 单位处
s=f"{row['TotalSales_2024H1']:.0f}",
ha="center"
)
plt.title("2024 年上半年(1-6 月)各地区总销售额")
plt.xlabel("地区")
plt.ylabel("总销售额 (元)")
plt.tight_layout()
plt.show()sns.barplot 默认会绘制均值并显示置信区间,如果你传入聚合后的 DataFrame(已经是总值),就不会显示误差线;plt.text 用于给每个柱子上方添加对应数值。用原始 df_first_half 数据绘制不同地区单价与销售数量的散点图,观察两者关系是否一致。
plt.figure(figsize=(8, 6))
sns.scatterplot(
data=df_first_half,
x="UnitPrice",
y="Quantity",
hue="Region",
size="SalesAmount",
alpha=0.7,
palette="Set2"
)
plt.title("单价 vs 销量 散点图 (按地区及销售额大小区分)")
plt.xlabel("单价 (元)")
plt.ylabel("销售数量")
plt.legend(title="地区", bbox_to_anchor=(1.05, 1), loc="upper left") # 将图例放置到右侧
plt.tight_layout()
plt.show()size="SalesAmount":点的大小随销售额变化,实际观察时可以明显看出高销售额点的分布;alpha=0.7:点的透明度,使得重叠区域更易观察;bbox_to_anchor 与 loc:用于调整图例位置,防止遮挡图表内容。若想看每个地区内部不同产品类别销售额占比,可针对各地区分别做饼图,或一次性用子图展示。这里我们演示以华东地区为例:
# 筛选华东地区,并做分组聚合
df_huadong = df_first_half[df_first_half["Region"] == "华东"]
sales_by_cat_huadong = df_huadong.groupby("Category")["SalesAmount"].sum().reset_index()
labels = sales_by_cat_huadong["Category"]
sizes = sales_by_cat_huadong["SalesAmount"]
plt.figure(figsize=(6, 6))
plt.pie(
sizes,
labels=labels,
autopct="%1.1f%%",
startangle=90,
explode=[0.05] * len(labels)
)
plt.title("华东地区产品类别销售额占比 (2024 H1)")
plt.axis("equal")
plt.show()startangle=90:让第一个扇区从 90° (正上方)开始绘制,可以调整视觉效果;
如果要同时展示多个地区的饼图,可以使用 Matplotlib 的子图功能:
regions = df_first_half["Region"].unique()
fig, axes = plt.subplots(1, len(regions), figsize=(len(regions)*5, 5))
for ax, reg in zip(axes, regions):
data_reg = df_first_half[df_first_half["Region"] == reg].groupby("Category")["SalesAmount"].sum()
ax.pie(
data_reg,
labels=data_reg.index,
autopct="%1.1f%%",
startangle=90,
explode=[0.05]*len(data_reg)
)
ax.set_title(f"{reg}地区 产品类别占比")
ax.axis("equal")
plt.tight_layout()
plt.show()plt.figure(figsize=(8, 6))
sns.boxplot(
data=df_first_half,
x="Region",
y="UnitPrice",
palette="pastel"
)
plt.title("各地区单价分布 (箱线图)")
plt.xlabel("地区")
plt.ylabel("单价 (元)")
plt.tight_layout()
plt.show()在实际工作中,我们常需要将图表保存为图片,插入到 PPT 或报告中。Matplotlib 提供 plt.savefig() 方法,推荐在 plt.show() 之前调用,以确保图片保存的是完整图形。
# 举例:保存折线图
plt.figure(figsize=(10, 6))
sns.lineplot(
data=df_first_half,
x="Month",
y="SalesAmount",
hue="Region",
marker="o",
palette="tab10"
)
plt.title("2024 年各地区月度销售趋势 (1-6 月)")
plt.xlabel("月份")
plt.ylabel("销售额 (元)")
plt.xticks(rotation=45)
plt.legend(title="地区")
plt.tight_layout()
# 保存图表
plt.savefig("monthly_sales_trend_2024H1.png", dpi=300) # dpi=300 提升分辨率
plt.show()plt.savefig("文件名.png", dpi=300):常用格式包括 .png, .jpg, .pdf, .svg 等,dpi(dots per inch)越高,图片分辨率越好;
若想保存到指定文件夹,例如 output/ 文件夹,需要先确保此文件夹已存在:
import os
os.makedirs("output", exist_ok=True)
plt.savefig("output/monthly_sales_trend_2024H1.png", dpi=300)将清洗后的原始数据、分组聚合结果等导出到 Excel 文件,方便他人查看或进一步加工。Pandas 提供 to_excel 方法。示例:
# 创建一个 ExcelWriter 对象,可写入多个 sheet
output_path = "sales_analysis_results.xlsx"
with pd.ExcelWriter(output_path, engine="openpyxl") as writer:
# 1. 将清洗后的原始数据写入 sheet1
df_first_half.to_excel(writer, sheet_name="Cleaned_Data", index=False)
# 2. 将各地区总销售额写入 sheet2
sales_by_region_2024H1.to_excel(writer, sheet_name="Region_Summary", index=False)
# 3. (可选)将同比对比结果写入 sheet3
# compare.to_excel(writer, sheet_name="YoY_Comparison", index=False)
# 提示:执行完毕后,会在当前目录生成 sales_analysis_results.xlsxExcelWriter 可以指定不同 sheet 名称,将多张表写入同一文件;index=False 表示不写入行索引;问:我在 pd.read_excel 时碰到 “ValueError: Excel file format cannot be determined” 错误,怎么办?
核心原因:Pandas 依赖 xlrd 或 openpyxl 解析 Excel。如果文件是 .xlsx,需安装 openpyxl;如果是 .xls,需安装 xlrd。
解决方法:
conda install openpyxl xlrd -y然后在代码中显式指定 engine:
df = pd.read_excel("data.xlsx", engine="openpyxl")问:为什么导入的列名前后有空格,导致 df["Month"] 访问不到?
原因:Excel 表头中可能存在隐藏空格、换行符等不可见字符。
解决:可以在读取后,对列名进行去空格处理:
df.columns = df.columns.str.strip() # 去除首尾空格
df.columns = df.columns.str.replace("\n", "") # 去除换行问:绘图时中文乱码如何解决?
默认 Matplotlib 不支持中文,需要设置字体。例如在 Windows 上使用 SimHei 字体:
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题如果你使用 Jupyter Notebook,一旦设置上述 rcParams,即可在所有后续图表中正确显示中文。
问:保存图片后打开模糊怎么改进?
提高 dpi 值,例如 plt.savefig("chart.png", dpi=300),或者更高。
保存为矢量图格式 .svg 或 .pdf,在放大时不会失真:
plt.savefig("chart.svg")问:如何只读取 Excel 的部分列或部分行?
读取部分列:使用 usecols 参数,例如只读取 A、C、E 列,或具体列名:
df = pd.read_excel("data.xlsx", usecols=["月份", "地区", "销售额(元)"])
# 或 usecols="A,C,E"跳过前几行:如果表头前面有无用行,可用 skiprows:
df = pd.read_excel("data.xlsx", skiprows=2) # 跳过前两行问:如何导出筛选后的数据?
在代码中筛选后直接使用 to_excel 写出:
filtered = df[df["SalesAmount"] > 5000]
filtered.to_excel("filtered_data.xlsx", index=False)问:Seaborn 的配色方案怎么查看?
"deep", "muted", "pastel", "bright", "dark", "colorblind" 等;palette="pastel" 等即可。功能 | 函数/方法 | 说明 |
|---|---|---|
读取 Excel | pd.read_excel("file.xlsx", sheet_name=...) | 读取 .xlsx 或 .xls 文件 |
写入 Excel | df.to_excel("out.xlsx", index=False) | 保存 DataFrame 到 Excel 文件 |
查看前几行 | df.head(n=5) | 查看前 n 行 |
查看后几行 | df.tail(n=5) | 查看后 n 行 |
查看列名 | df.columns | 返回 Index 对象 |
查看维度 | df.shape | 返回 (行数, 列数) |
查看数据类型 | df.info() | 显示每列数据类型与非空行数 |
查看缺失值 | df.isnull().sum() | 返回各列缺失值数量 |
筛选行 | df[df["col"] > 0] | 布尔索引 |
筛选列 | df[["col1", "col2"]] | 选择子集列 |
删除列 | df.drop(columns="col") | 删除一列 |
删除行 | df.drop(index=[0,1]) | 删除指定行 |
重命名 | df.rename(columns={"old":"new"}) | 重命名列 |
分组聚合(GroupBy) | df.groupby("col")["val"].agg(["sum","mean"]) | 按某列分组后对指定列进行聚合 |
透视表 | pd.pivot_table(df, index, columns, values) | 创建交叉表 |
排序 | df.sort_values("col", ascending=False) | 按某列排序,降序示例:ascending=False |
重置索引 | df.reset_index(drop=True) | 重置索引并丢弃原索引 |
类型转换 | df["col"].astype(int) | 转为整数类型 |
转换为 datetime | pd.to_datetime(df["col"], format="%Y-%m") | 将字符串列转为 datetime |
添加新列 | df["new"] = df["a"] + df["b"] | 常用于计算 |
缺失值删除 | df.dropna(axis=0, how="any") | 删除含任意缺失值的行 |
缺失值填充 | df["col"].fillna(value, inplace=True) | 用指定 value 填充缺失值 |
绘制折线图 | plt.plot(x, y, marker="o", label="...") | Matplotlib 折线图基础用法 |
绘制柱状图 | plt.bar(x, height) | Matplotlib 柱状图 |
绘制散点图 | plt.scatter(x, y, alpha=0.7) | Matplotlib 散点图 |
绘制饼图 | plt.pie(sizes, labels=labels, autopct="%.1f%%") | Matplotlib 饼图 |
绘制箱线图 | plt.boxplot(data, labels=labels) | Matplotlib 箱线图 |
Pandas 快速绘图 | df.plot(kind="bar/line/box", ...) | 调用 Pandas 封装的绘图方法 |
Seaborn 条形图 | sns.barplot(data=df, x="col1", y="col2") | Seaborn 条形图 |
Seaborn 折线图 | sns.lineplot(data=df, x="col1", y="col2", hue="col3") | Seaborn 折线图 |
Seaborn 散点图 | sns.scatterplot(data=df, x="col1", y="col2", hue="col3") | Seaborn 散点图 |
Seaborn 箱线图 | sns.boxplot(data=df, x="col1", y="col2") | Seaborn 箱线图 |
Seaborn 热力图 | sns.heatmap(corr, annot=True, cmap="coolwarm") | Seaborn 热力图 |
本文从环境搭建开始,详细讲解了如何使用 Python(以 Pandas、Matplotlib、Seaborn 为主)完成从读取 Excel 到数据清洗、统计分析,再到绘制各种可视化图表,并将结果导出报告的完整流程。希望你结合示例代码,动手实践一遍后,能够掌握基本思路与常见用法。在此基础上,若有更多需求(如交互式图表、网页仪表盘、机器学习模型等),可以继续深入学习相关库与框架。
祝学习顺利,早日成为 Python 数据分析与可视化的高手!