维护中学习资料公开

pandas 数据分析实战:从读表到出结论

用一条完整的分析链路串起 pandas 核心能力——数据读取与类型修整、缺失值与异常值处理、分组聚合、表连接、时间序列重采样,最后用透视表回答真实业务问题。

更新于 2026年9月20日发布于 2026年9月20日AI资源库进阶
下载渠道
暂无
文件信息
— · MD + 示例代码
资料数量
1 项
访问方式
公开查看
pandas 数据分析实战:从读表到出结论 封面
编程开发 · Python
收藏

学习信息

pandas 数据分析实战

适合谁

  • 有一份销售明细 / 投放明细 / 库存流水,想回答「哪个品类最赚钱」「哪天掉量了」的人
  • 会用 Excel 透视表,但数据量一大就卡死的人
  • 会 Python 语法,想把分析过程固化成可复用脚本的人

先建立心智模型

pandas 的两大件:Series(一列)和 DataFrame(一张表)。所有操作基本围绕三件事展开:

1. 选:我要哪几行、哪几列 2. 算:按什么维度聚合、算什么指标 3. 拼:多张表怎么关联起来

把这三件事想清楚,剩下的全是查文档。

第一步:把数据读对

import pandas as pd

df = pd.read_excel("sales.xlsx", dtype={"订单号": str})
print(df.shape)          # (行数, 列数)
print(df.dtypes)         # 每列类型,这里最常出问题
print(df.isna().sum())   # 每列缺失值数量

看 dtypes 这一步不能省。日期被读成字符串,后面所有时间分析都会失效;金额被读成 object,聚合时会直接报错或静默出错。

修正常见类型问题:

df["日期"] = pd.to_datetime(df["日期"], errors="coerce")
df["金额"] = pd.to_numeric(df["金额"], errors="coerce")
df["数量"] = pd.to_numeric(df["数量"], errors="coerce").fillna(0).astype("int64")

第二步:缺失值与异常值

缺失值没有万能解法,看业务含义决策:

# 关键字段缺失 → 直接删(金额都不知道,这条没法分析)
df = df.dropna(subset=["金额", "日期"])

# 数值型缺失 → 用中位数填充,比均值更抗极端值
df["折扣"] = df["折扣"].fillna(df["折扣"].median())

# 类别型缺失 → 单独成一类,保留「未填写」这个信息本身
df["渠道"] = df["渠道"].fillna("未标注")

异常值用分位数而不是拍脑袋:

q1, q3 = df["金额"].quantile([0.25, 0.75])
iqr = q3 - q1
upper = q3 + 1.5 * iqr
outliers = df[df["金额"] > upper]
print(f"疑似异常 {len(outliers)} 条,阈值 {upper:.2f}")

先打印出来人工看一眼再决定删还是留。大额订单可能是真实批发单,删掉反而丢掉重要客户。

第三步:分组聚合(最常用)

# 单维度:各品类销售额
by_cat = (
    df.groupby("品类", as_index=False)
      .agg(销售额=("金额", "sum"), 订单数=("订单号", "nunique"))
      .sort_values("销售额", ascending=False)
)

# 双维度:品类 × 渠道
by_cat_chn = df.groupby(["品类", "渠道"], as_index=False)["金额"].sum()

# 顺便算占比
by_cat["占比"] = (by_cat["销售额"] / by_cat["销售额"].sum() * 100).round(2)

注意 nunique() 和 count() 的区别:前者数去重后的订单数,后者数行数(含同一订单的多行明细)。算订单量几乎都是前者。

第四步:多表连接

订单表和商品表分开时,用 merge:

products = pd.read_excel("products.xlsx")
merged = df.merge(products, on="商品ID", how="left", validate="many_to_one")

# 检查有没有匹配不上的
print("未匹配行数:", merged["商品名称"].isna().sum())

validate="many_to_one" 是个好习惯:如果右表主键有重复,会直接报错提醒你,而不是悄悄把行数翻几倍。

三种 how 的选择:

| 需求 | 参数 | | --- | --- | | 保留左表全部,右表没有就填 NaN | how="left"(最常用) | | 只保留两边都匹配上的 | how="inner" | | 想找「左表有右表没有」的差异 | how="left" + indicator=True |

第五步:时间序列分析

df = df.set_index("日期")

# 按周汇总
weekly = df["金额"].resample("W").sum()

# 7 日移动平均,看趋势而不是看噪声
weekly_ma = weekly.rolling(7).mean()

# 同比环比(对比上一周期)
weekly_mom = weekly.pct_change() * 100

W 是周、M 是月、D 是日。做趋势判断时一定要叠加移动平均,单日数据的涨跌大多是噪声。

综合:一张透视表回答业务问题

pv = pd.pivot_table(
    df.reset_index(),
    index="品类",
    columns=df.reset_index()["日期"].dt.to_period("M").astype(str),
    values="金额",
    aggfunc="sum",
    fill_value=0,
    margins=True,          # 加合计行/列
    margins_name="合计",
)
print(pv.round(0))

这一张表就能回答:每个品类每月卖了多少、哪个月是高峰、整体合计是多少。直接用 to_excel 输出就是能发给老板的报表。

性能:什么时候会卡

数据量级决定写法:

  • 十万行以内:随便写,pandas 秒回
  • 百万行以上:读表时加 usecols= 只读需要的列、dtype 指定类型;必要时分块 chunksize
  • 千万行以上:考虑 polars 或先落库用 SQL 聚合

一个立刻见效的优化:把重复用到的字符串列转成 category 类型,内存能省一大截。

df["品类"] = df["品类"].astype("category")

常见问题

SettingWithCopyWarning 警告看不懂? 这是链式赋值导致的。想改子表就显式 .copy(),比如 sub = df[df["金额"] > 100].copy()。

groupby 后索引很乱? 用 as_index=False 或末尾接 .reset_index()。

merge 后行数暴涨? 右表主键重复了,先 products.drop_duplicates(subset=["商品ID"]) 再去连。

下一步

  • 可视化:df.plot() 快速看,正式图表用 matplotlib 或 pyecharts
  • 固定流程:把清洗逻辑封装成函数,每次新数据直接调用
  • 交互式看板:Streamlit 几十行就能把分析结果做成网页

评论建议

欢迎反馈资料质量、链接状态或希望补充的内容,管理员会持续维护。

常见问题

下载链接失效怎么办?
请优先切换其他网盘渠道,并反馈失效链接。

会员能下载所有资料吗?
页面标注为会员专享的资料支持会员下载,具体以当前页面显示为准。

相关资源