bml.asia · 纯文字 · 写写停停

Pandas 数据分析实战教程:13 步从数据读取到透视表

1. 实验背景

  拿到 Pandas 的那天起,处理数据就从"对着一堆乱七八糟的数字发愁"变成了"像操作一张会思考的 Excel"。它脱胎于 NumPy 的数组运算,但真正和你打交道的是两个数据结构:一维的 Series 像是给一串数字贴上了名字标签,二维的 DataFrame 则直接是一张完整的表。用过之后最大的感受是,它把 Excel 的直观和 SQL 的严谨揉在了一起——既能像点表格一样筛选切片,又能像写查询一样分组聚合。本实验以一份电商订单数据集为主线,通过动手操作掌握 Pandas 的构建、读取、切片、合并、聚合与透视等核心能力。

2. 实验步骤

  本实验按如下顺序推进:先准备并初始化环境,再分别构建 Series 与 DataFrame,随后掌握用 Pandas 加载 Excel 文件,接着学习索引与切片,进一步练习改造与合并,最后完成组合、聚合与透视表的生成。每一步都在 Jupyter Notebook 中边写边运行,看到输出即掌握。

3. 实验指导

  建议不要只读不改:每一段代码都亲手敲进 Notebook,运行后再尝试改一两个参数,观察输出如何变化——这是理解 Pandas 行为最快的方式。每节末尾可以给自己出一个 30 秒的小练习,例如"把聚合结果按金额降序排列",答不上来时回看本节内容即可。

4. 实验环境

  本实验需要 Python 3.10 及以上版本,并安装以下库:

pip install pandas numpy openpyxl jupyter

  pandasnumpy 是数据分析核心,openpyxl 用于读写 Excel 文件,jupyter 提供交互式运行环境。安装后可用一行代码确认版本:

import pandas as pd
print(pd.__version__)   # 2.x 即可

5. 启动 jupyter

  在项目目录打开终端,运行下面任一命令即可启动:

jupyter notebook
# 或更现代的版本
jupyter lab

  启动后浏览器会自动打开 Notebook 界面,点击右上角 “New” 新建一个 Python 3 笔记本,后续实验都在单元格中完成。每写一段代码,按 Shift + Enter 运行并查看输出。

6. 配套文件

  本实验使用一份电商订单数据 orders.xlsx(同时提供 orders.csv 副本),共六列,涵盖区域与类目两个维度:

  • order_id:订单号,唯一标识
  • order_date:下单日期
  • region:区域(华东、华南、华北等)
  • category:商品类目(数码、家居、服饰等)
  • amount:订单金额(元)
  • channel:渠道(线上、门店)

  后续所有操作都围绕这份数据展开。

7. 初始化环境

  每次打开 Notebook 的第一步,是导入 Pandas 并读取数据,让 df 这个 DataFrame 常驻内存:

import pandas as pd

df = pd.read_excel("orders.xlsx", parse_dates=["order_date"])
print(df.shape)          # (行数, 列数)
print(df.head())         # 前 5 行
print(df.info())         # 列类型与非空情况,第一时间暴露隐患
print(df.describe())     # 数值列的统计摘要

  read_excel 的两个参数值得记住:sheet_name 指定工作表(默认第一张),parse_dates 把日期列直接解析为时间类型。info() 常能发现"金额被读成字符串"这类问题。

8. 构建和初始化 Series

  Series 是带标签的一维数组,可以理解为"带行号的单列 Excel"。几种常见构造方式:

# 从列表构造,自动生成 0..n-1 索引
s1 = pd.Series([10, 20, 30], name="amount")

# 从字典构造,键即索引
s2 = pd.Series({"华东": 120, "华南": 90, "华北": 75})

# 标量广播:一个值铺满多个索引
s3 = pd.Series(0, index=["a", "b", "c"])

print(s1.values)   # 底层数组
print(s2.index)    # 索引标签
print(s3)

  name 属性给 Series 起名字,indexvalues 分别取出标签和值。Series 可以直接做算术运算,例如 s2 * 1.1 得到每个区域金额上浮 10% 的结果。

9. 构建和初始化 DataFrame

  DataFrame 是二维表格,是最常用的结构。三种主流构造方式:

# 方式一:字典(键为列名,值为列数据)
df1 = pd.DataFrame({
    "region": ["华东", "华南", "华北"],
    "amount": [120, 90, 75],
})

# 方式二:列表套字典(每行一个字典,列自动推断)
df2 = pd.DataFrame([
    {"region": "华东", "amount": 120},
    {"region": "华南", "amount": 90},
])

# 方式三:NumPy 数组 + 显式指定列名
import numpy as np
arr = np.array([[1, "华东"], [2, "华南"]])
df3 = pd.DataFrame(arr, columns=["id", "region"])

print(df1)

  构造完成后,head()info()describe() 是最常用的"体检三件套",任何 DataFrame 拿到手先跑这三行。

10. 用 Pandas 加载 Excel 格式的文件

  加载 Excel 是 read_excel 的主场,它依赖 openpyxl 引擎。除了直接读整张表,还支持按需读取:

df = pd.read_excel("orders.xlsx")                    # 默认第一张工作表
df = pd.read_excel("orders.xlsx", sheet_name="2026")  # 指定工作表
df = pd.read_excel("orders.xlsx", sheet_name=0)       # 按位置索引取表
df = pd.read_excel("orders.xlsx", header=1)           # 数据从第 2 行开始

# 一次读多张表,返回 {工作表名: DataFrame} 的字典
sheets = pd.read_excel("orders.xlsx", sheet_name=None)
print(sheets.keys())

  sheet_name=None 是最实用的技巧之一:它把整个工作簿的所有表一次读进来,省去反复打开文件的麻烦。

11. DataFrame 的索引与切片

  索引与切片是使用频率最高的操作,核心是记住两套定位器:loc 按标签、iloc 按位置。

# 列的选择
df["amount"]                    # 单列 -> Series
df[["region", "amount"]]        # 多列 -> DataFrame

# 行的切片
df[:5]                          # 前 5 行(位置切片)

# loc:按标签/条件
df.loc[0]                       # 第 0 行(索引标签)
df.loc[0:5, ["region", "amount"]]  # 行 + 列同时切

# iloc:按位置
df.iloc[0]                      # 第 0 行
df.iloc[1:6, 1:3]               # 第 1~5 行、第 1~2 列

# 布尔索引:条件筛选,数据分析的灵魂
east = df[df["region"] == "华东"]
big = df[(df["amount"] > 500) & (df["channel"] == "线上")]

  一个常见困惑是 df[0:5]df.loc[0:5] 的区别:前者是纯位置切片(不含第 5 行),后者按标签切片(含标签为 5 的行)。当索引是整数时特别容易混,动手各跑一次就清楚了。

12. DataFrame 的改造与合并

  改造指改名、增列、改类型;合并指把多个表拼在一起,分横向(merge)与纵向(concat)两种。

# 改造:重命名、新增列、类型转换、删除列
df = df.rename(columns={"amount": "sales"})
df["year"] = df["order_date"].dt.year       # 从日期提取年份
df["is_big"] = df["sales"] > 500            # 新增布尔列
df["sales"] = df["sales"].astype(float)     # 类型转换
df = df.drop(columns=["channel"])           # 删列

# 纵向合并:两个结构相同的 DataFrame 拼成更长的表
df_2026 = pd.read_excel("orders.xlsx", sheet_name="2026")
df_all = pd.concat([df, df_2026], ignore_index=True)

# 横向合并:像 SQL 的 JOIN,按 key 关联
orders = pd.DataFrame({"order_id": [1, 2, 3], "amount": [100, 200, 300]})
users  = pd.DataFrame({"order_id": [1, 2], "buyer": ["张三", "李四"]})
joined = orders.merge(users, on="order_id", how="left")
print(joined)

  how="left" 保留左侧全部订单,右侧没有匹配的用户就留空——这是业务上最常用的左连接。

13. DataFrame 的组合与聚合以及透视表生成

  最后一步是"把数据变成结论":分组聚合回答"每组怎么样",透视表回答"两个维度叠加怎么样"。

# 分组聚合:按类目统计订单数、总金额、平均金额
stat = df.groupby("category").agg(
    orders=("order_id", "count"),
    total=("sales", "sum"),
    avg=("sales", "mean"),
).sort_values("total", ascending=False)
print(stat)

# 时间聚合:按自然月统计销售额
monthly = df.set_index("order_date").resample("M")["sales"].sum()

# 透视表:类目 × 区域的销售额矩阵
pivot = pd.pivot_table(
    df, index="category", columns="region",
    values="sales", aggfunc="sum", fill_value=0,
)
print(pivot)

# 结果落盘,方便汇报或下一步分析
stat.to_csv("category_stats.csv", encoding="utf-8-sig")

  至此,一份订单数据就从原始的 Excel 变成了"哪个类目赚钱、哪个区域最强、月度趋势如何"的业务洞察。回顾整个实验,主线其实只有一句:先读进来、再弄干净、然后分组聚合、最后透视呈现——把这条主线练熟,Pandas 也就真正上手了。