很多人在第一次打开 Pandas 官方文档时,面对几百个方法,很容易觉得“入门”是一件很难的事。尤其是用过 Excel 的人,会产生一个更直观的困惑:Excel 里点几下就完成的筛选、求和、排序,为什么到了 Pandas 里,还要写一行行代码?
这是 Pandas 入门时最大的认知门槛,也是本文想重点解决的问题。Pandas 不是让你把简单的操作变复杂,而是帮你把重复、耗时、无法回溯的表格处理流程,转化为可复用、可自动化、可验证的数据分析脚本。它的学习重点不是“记住每个 API”,而是先建立“一张表在代码里是什么样的”这个基本认知。
这篇文章给你规划的 2 小时,目标非常具体:读完一遍,你能独立把一份 CSV 格式的订单表读进程序,完成缺失值清理、重复值处理、类型转换,再基于分组聚合得出“不同分类的销售额、订单量、客单价”这类结论,最后把分析结果导出成一张新表。这就是日常工作中最常见、也最刚需的数据分析流程。如果你能跑通这条通路,就已经超过了大多数停留在“了解概念”阶段的初学者。
整篇文章的实践路径是:先理解 Series 和 DataFrame 两个核心对象,再准备好环境,然后用一个小型订单数据走一遍“读取数据 → 清洗数据 → 筛选数据 → 分组聚合 → 导出结果”的完整流程。每部分都会配合直接可运行的代码示例,并在最后给出常见问题和工程建议。
1. 这篇文章真正要解决的问题
先说说新手学 Pandas 最常见的三个困境。
第一个困境是“文档看不进去”。Pandas 文档确实很全,但全到让新手不知道该从哪里开始。你知道merge、pivot_table、rolling这些方法听说过,但不知道日常工作里它们到底对应哪个场景。文档本身是“字典”式的,不是“入门教程”式的,直接翻开它,很容易被庞大的 API 数量劝退。
第二个困境是“教程太散”。网上很多 Pandas 教程是逐个讲函数,今天讲read_csv,明天讲groupby,后天讲apply。每个函数看懂了,但遇到真实数据时还是不知道第一步该干什么,第二步该干什么。真正的数据分析是有固定流程的,这个流程就是“读取、查看、清洗、筛选、聚合、导出”。如果你没有一个完整的流程感,知识就永远是碎片。
第三个困境是“动手太少”。数据分析是实践学科,只看代码不敲代码,相当于学游泳不下水。很多人卡住的不是概念难,而是电脑上没有合适的运行环境,或者照着代码敲到一半因为一个小语法错误就放弃了,然后误以为自己不适合学编程。
这篇文章要解决的就是这三点。它不追求把 Pandas 所有知识点全部覆盖,而是把“用 Pandas 完成一次基础数据分析”的最小知识集提炼出来,再教你按流程组织这些知识。
给一个明确判断:Pandas 入门最核心的不是记忆函数,而是形成“数据思维”。所谓数据思维,就是拿到一份数据后,能立刻知道要先看结构、再查异常、再做分析、最后出结果。2 小时完全足够建立这种思维和对应的操作能力。
2. Pandas 核心概念:Series 和 DataFrame
2.1 从“表格”出发理解 Pandas
先不要急着记概念。你先回忆一下 Excel 里的表格长什么样:有行号,有列名,每一列可能是数值、文本或日期。Pandas 里的 DataFrame 本质就是这样一个对象,只不过它是在内存中用 Python 对象表示的二维表。
DataFrame 的“列”在 Pandas 中叫做 Series。Series 可以理解为“带标签的一维数组”,它有索引,也有值。一个 DataFrame 可以看作“多个 Series 纵向拼在一起”,每个 Series 对应一列。
用表来表示两者的区别:
| 对象 | 维度 | 类比物 | 核心成员 |
|---|---|---|---|
| Series | 一维 | Excel 中的一列 | index(索引)、values(值) |
| DataFrame | 二维 | 一张 Excel 工作表 | columns(列名)、index(行索引)、values(数据块) |
这里最适合用一个真实场景来理解。假设你拿到一份销售订单数据:
| 订单编号 | 城市 | 销售额 | 订单日期 |
|---|---|---|---|
| 1001 | 上海 | 998 | 2025-01-01 |
| 1002 | 北京 | 320 | 2025-01-02 |
在 Pandas 中可以这样创建这个 DataFrame:
import pandas as pd data = { "订单编号": [1001, 1002], "城市": ["上海", "北京"], "销售额": [998, 320], "订单日期": ["2025-01-01", "2025-01-02"] } df = pd.DataFrame(data) print(df)输出如下:
订单编号 城市 销售额 订单日期 0 1001 上海 998 2025-01-01 1 1002 北京 320 2025-01-02这个示例虽简单,但它说明了一件事:我们平时用 Excel 看到的“表”,在 Pandas 中就是一个 DataFrame。之后的全部操作,本质上都是对这个二维对象做“取行、取列、过滤、计算、分组、汇总”。
2.2 新手最容易出现的误区
新手最容易犯的误区,是把 DataFrame 当成 Python 里的二维 list 来用。二维 list 只能通过[行下标][列下标]的方式访问,而 DataFrame 有更丰富的访问方式。
例如,你想取出“销售额”这一列,正确的做法是:
# 推荐:按列名取列 print(df["销售额"])如果你用二维 list 的思维,写成df[0],就会得到完全不同的结果,甚至报错。Pandas 中df[0]表示“按行索引取行”的语义,而不是取第一列。
这个阶段的小结论是:学习 Pandas 时,要把每一行代码思考成“对一张表做了什么”,比如“取出某一列”“筛选某些行”“按某一列排序”。当你把每次操作都映射到表结构上,而不是停留在记忆语法层面,学习速度会快很多。
3. 环境准备:安装 Pandas 的最稳妥方式
3.1 环境说明
Pandas 是基于 Python 的数据分析库,因此前提是先有一个可用的 Python 环境。官方目前对 Python 版本有明确的支持范围,具体以官网说明为准。对于新手,我的建议是使用 Python 3.9 及以上版本,这样在安装 Pandas 时兼容性问题最少。
如果你使用的是 PyCharm,可以通过项目解释器直接安装,也可以使用命令行安装。两者效果一样,核心命令就一条:
pip install pandas这条命令会自动安装 Pandas 本身,同时会拉取它依赖的 numpy、python-dateutil 等基础库,不需要你手动逐个安装。
有些读者用的是 Anaconda 环境,对应的命令是:
conda install pandas3.2 在 PyCharm 中安装 Pandas
如果你的电脑里已经装了 PyCharm,最简单的操作路径是:
- 打开 PyCharm,创建一个新项目。
- 点击左下角的
Python Packages窗口。 - 在搜索框中输入
pandas。 - 点击右侧的
Install按钮。
这种方式的好处是,PyCharm 会自动识别当前项目用的 Python 解释器,把包安装到正确的虚拟环境中,不容易出现“命令装好了,但项目里用不了”的情况。
如果你更习惯命令行方式,也可以先用python -m venv venv创建虚拟环境,激活后再执行pip install pandas。不过对于 2 小时入门这个目标来说,跳过虚拟环境、直接使用全局环境也完全可以,关键是把流程跑通。
3.3 验证安装是否成功
安装完成后,验证方式很简单:
import pandas as pd print(pd.__version__)如果能正常输出版本号,比如2.2.3,说明环境已经准备好了。
这里要提醒一个常见问题:如果安装后运行import pandas提示找不到模块,一般不是安装失败,而是 PyCharm 当前选中的 Python 解释器,和安装 pandas 时用的解释器不是同一个。解决方法是在 PyCharm 的Settings -> Project -> Python Interpreter中确认当前解释器路径,再重新安装一次。
4. 数据读取:先把数据拿进来,再谈分析
4.1 读取 CSV 文件
Pandas 最常用的数据读取操作就是读 CSV 文件。假设本地有一个orders.csv文件,包含订单数据,读取代码只有一行:
import pandas as pd df = pd.read_csv("orders.csv")这件事看起来简单,但真实项目中经常会出现三类问题:文件路径不对、中文乱码、列名不匹配。对于新手,建议先给文件一个绝对路径,减少路径问题:
df = pd.read_csv("C:/Users/你的用户名/Desktop/orders.csv")如果 CSV 中包含中文,推荐显式指定编码:
df = pd.read_csv("orders.csv", encoding="utf-8")有些老文件是gbk编码,则改成:
df = pd.read_csv("orders.csv", encoding="gbk")4.2 快速认识数据
读进来之后,不要急着做分析,先用三个方法快速了解这张表。
# 查看前5行 print(df.head()) # 查看表的行列数 print(df.shape) # 查看每一列的数据类型和非空情况 print(df.info())head()默认显示前 5 行,你可以传入数字查看前 N 行。shape返回(行数, 列数)元组,比如(1000, 6)表示 1000 行、6 列。info()会列出每一列的名称、数据类型、非空值数量,这是判断数据是否需要清洗的第一个依据。
4.3 关于 Parquet、Feather 等格式
对于日常练习和中小型数据集,CSV 足够了。如果是大数据集,压缩的格式,在实践中也经常用 parquet、feather 等方式,这在 pandas 中也有对应接口:
# 读取 parquet 格式 df2 = pd.read_parquet("orders.parquet") # 读取 feather 格式 df3 = pd.read_feather("orders.feather")Parquet 和 Feather 的优势在于读取速度快、文件体积小,适合离线分析、数据仓库场景。对于第一次接触 Pandas 的读者,知道“Pandas 不仅能读 CSV,还能读各种列式格式”这个信息就够了,2 小时内不需要深入。
这个小节的结论是:读取数据只是热身,真正重要的工作是“认识这张表”。如果你连数据有多少行、哪些列、哪些列有缺失都不知道,分析就是盲人摸象。
5. 数据清洗三件套:缺失值、重复值、类型转换
5.1 为什么清洗是数据分析中最耗时的一步
真实世界给到的数据很少是干净的。你可能会拿到空值、重复记录、字符串格式的金额、错误日期。这就是为什么数据分析流程中,数据清洗经常占据一半以上时间。
清洗工作有三类最基础的任务:处理缺失值、删除重复值、转换数据类型。把这三件事做对,后面的分析质量才有保障。
5.2 缺失值处理
先看哪些列有缺失值:
print(df.isnull().sum())如果某些列缺失数据很少,最直接的办法是删除有缺失的行:
df.dropna(inplace=True)inplace=True表示原地修改 df。对于新手,建议尽量少用inplace,而是使用赋值方式:
df = df.dropna()两者的区别在于,后者更符合函数式写法,可读性更好,也不容易因为原地修改造成连锁问题。如果缺失值很关键,比如“销售额”为空,删除整行可能会损失信息,此时可以考虑填充:
df["销售额"] = df["销售额"].fillna(0)5.3 重复值处理
重复值处理对应的场景,正好是热搜词里出现过的“如果指定两列的值均相同,则取第一条数据即可”。
先查看重复情况:
duplicate_mask = df.duplicated() print(duplicate_mask.sum())删除所有列完全相同的重复行:
df = df.drop_duplicates()如果只根据“订单编号”和“城市”两列判断是否重复,保留第一条:
df = df.drop_duplicates(subset=["订单编号", "城市"], keep="first")keep="first"表示保留第一次出现的记录,keep="last"表示保留最后一次,keep=False表示删除所有重复记录。这个参数在不同业务场景下含义不同,订单流水一般保留第一条即可。
5.4 数据类型转换
Pandas 中常见的坑是把“数值”存成了“字符串”。比如 Excel 导出 CSV 后,金额列可能出现"1,234"这种带逗号的文本,直接计算就会报错或得到错误结果。
查看类型:
print(df.dtypes)使用astype转换:
df["销售额"] = df["销售额"].astype(float)如果列中带有逗号或千分符,需要先清洗再转换:
df["销售额"] = df["销售额"].str.replace(",", "").astype(float)日期列也需要转换,方便后续按时间做聚合:
df["订单日期"] = pd.to_datetime(df["订单日期"])这个阶段的小结论是:清洗的本质是让 Pandas 对数据的“默认理解”与业务实际一致。缺失值影响的是统计口径,重复值影响的是计数,错误类型影响的是运算。每次拿到新数据,先在这三项上检查一遍,是最稳妥的做法。
6. 数据筛选与排序:组合条件不迷路
6.1 布尔索引:筛选的核心
筛选是数据分析最常用的操作。“找出销售额大于 1000 的记录”“找出上海和北京的订单”,这些需求的实现方式都依赖布尔索引。
布尔索引的逻辑是:先构造一个由 True/False 组成的条件序列,再把它放到df的方括号中,True 对应的行会被保留。
最简单的方式:
condition = df["销售额"] > 1000 result = df[condition]6.2 多条件组合
多条件时,新手最常踩的坑是写and/or。Pandas 中必须使用&(且)和|(或),并且每个条件最好用括号包起来:
# 找出销售额大于1000,且城市为上海 condition1 = df["销售额"] > 1000 condition2 = df["城市"] == "上海" result = df[condition1 & condition2]注意,==是比较运算,不能写成单个=。如果使用~表示取反,比如“不是上海”:
result = df[~condition2]6.3 排序
排序用sort_values:
# 按销售额从大到小排序 df_sorted = df.sort_values("销售额", ascending=False)如果想按多列排序,可以传入列表:
df_sorted = df.sort_values(["城市", "销售额"], ascending=[True, False])这里需要注意,sort_values默认不会原地排序,返回的是一个新的 DataFrame。如果你想让当前变量改变,要重新赋值:
df = df.sort_values("销售额", ascending=False)6.4 一个容易混淆的点
新手容易混淆“按列筛选”和“按行筛选”。df["销售额"]是取列,df[df["销售额"] > 0]是取行。如果一时反应不过来,就记一个原则:括号里面放一个布尔条件序列的时候,一定是在筛行。
这个小节的结论是:筛选是数据分析的语言。它让你从全量数据中把需要的子集拿出来,而不是用眼睛在 Excel 里一行行找。
7. 分组聚合:数据分析真正“出结论”的地方
7.1 为什么必须学 groupby
前面几步只是“整理数据”,到分组聚合这一步,才真正开始“得出指标”。面试中高频出现的 Pandas 问题,几乎同时也是业务中最常用的操作:按某个维度分组,计算总和、平均值、计数。
比如“每个城市的销售额”“每个月的订单数”“每个品类的客单价”,这些全部来自groupby。
7.2 基础分组聚合
继续用订单数据举例,按城市分组,统计销售额总和:
result = df.groupby("城市")["销售额"].sum() print(result)这个操作可以用中文描述为:按“城市”列分组,取出每组中“销售额”列,求和。结果是一个 Series,索引是城市名。
如果想一次得到多个统计量,使用agg:
result = df.groupby("城市")["销售额"].agg(["sum", "mean", "count", "max"]) print(result)输出类似:
sum mean count max 城市 上海 1996 998.0000 2 1998 北京 320 320.0000 1 3207.3 groupby 结果转为 DataFrame
groupby结果默认的索引是分组字段。如果你希望分组字段也作为普通列存在,注意reset_index:
result = df.groupby("城市")["销售额"].sum().reset_index()或者在groupby时指定as_index=False:
result = df.groupby("城市", as_index=False)["销售额"].sum()这两种方式得到的都是常见的二维表结构,方便后续导出或继续处理。
7.4 多列分组
业务中经常有“每个城市、每个产品分类的订单量”这类需求,分组列可以传入多个字段:
result = df.groupby(["城市", "商品分类"]).agg( 订单量=("订单编号", "count"), 销售额合计=("销售额", "sum") ).reset_index()这段代码中,agg接收一个字典或关键字参数,("订单编号", "count")的含义是“对订单编号列执行计数”,("销售额", "sum")是“对销售额列执行求和”。
这个小节的结论是:groupby 让数据从明细形态进入汇总形态,是你从数据里提取信息的分水岭。学习时先会用sum、mean、count三个基础统计量,再逐步接触agg的组合用法,就足够应对 80% 的日常工作。
8. 综合实战:用一份订单数据跑通 2 小时练习
8.1 练习目标
下面我们用一个完整案例,把前面所有知识点串起来。目标如下:
- 创建一份模拟订单数据。
- 清洗缺失值和重复值。
- 转换日期与金额类型。
- 筛选出“已支付”订单。
- 按城市和商品分类统计销售额与订单量。
- 导出结果到 CSV 文件。
8.2 完整代码
这段代码可以直接复制运行。为了让读者不受外部文件限制,这里用随机方式构造数据,模拟一份名为orders.csv的销售订单表。
import pandas as pd import numpy as np # 1. 构造一份模拟订单数据 rng = np.random.default_rng(42) n = 200 df = pd.DataFrame({ "订单编号": [f"ORD{i:04d}" for i in range(1, n + 1)], "城市": rng.choice(["上海", "北京", "广州", "深圳"], n), "商品分类": rng.choice(["数码", "服装", "食品", "家居"], n), "销售额": rng.choice([None, 100, 300, 500, 800, 1200], n, p=[0.1, 0.2, 0.2, 0.2, 0.2, 0.1]), "订单状态": rng.choice(["已支付", "待支付", "已取消"], n, p=[0.7, 0.2, 0.1]), "订单日期": pd.date_range("2025-01-01", periods=n, freq="D") }) # 制造一些重复行 df = pd.concat([df, df.iloc[:5]], ignore_index=True) # 2. 查看初始结构 print("数据形状:", df.shape) print(df.head()) # 3. 清洗:删除缺失值、重复值,转换类型 df = df.dropna(subset=["销售额"]) df = df.drop_duplicates(subset=["订单编号", "城市"], keep="first") df["销售额"] = df["销售额"].astype(float) df["订单日期"] = pd.to_datetime(df["订单日期"]) # 4. 筛选:只保留已支付订单 df_paid = df[df["订单状态"] == "已支付"] # 5. 分组聚合:统计每个城市、每个分类的销售额和订单量 result = df_paid.groupby(["城市", "商品分类"], as_index=False).agg( 销售额合计=("销售额", "sum"), 订单量=("订单编号", "count"), 平均客单价=("销售额", "mean") ) # 6. 排序并导出 result = result.sort_values(["城市", "销售额合计"], ascending=[True, False]) result.to_csv("result_summary.csv", index=False, encoding="utf-8-sig") print("\n分组统计结果:") print(result.head(10))8.3 代码关键逻辑解释
第一,模拟数据部分用np.random.default_rng生成了 200 条订单。这里特意包含了空值,用于演示缺失值处理。实际工作中,数据通常来自数据库导出、Excel 文件或接口,但清洗逻辑是一样的。
第二,df = pd.concat([df, df.iloc[:5]], ignore_index=True)故意制造了 5 条重复记录,方便验证drop_duplicates是否生效。
第三,导出 CSV 时使用encoding="utf-8-sig"而不是utf-8,这是为了兼容 Excel 打开中文不乱码。很多新手在这里忽略编码,导致导出结果在 Excel 中乱码,其实不是 Pandas 的问题,而是编码选错。
8.4 运行结果与预期输出
运行代码后,控制台会先输出:
数据形状: (205, 6)说明原始数据有 205 行,后面清洗后行数会减少。输出分组统计结果时,会看到类似下面这样的一张表:
城市 商品分类 销售额合计 订单量 平均客单价 0 上海 家居 29500 34 867.65 1 上海 数码 41200 40 1030.00 2 北京 服装 18200 21 866.67 ...如果你看到result_summary.csv文件成功生成,并且分组字段、统计字段都正确,说明整个流程已经跑通。
8.5 怎么判断分析结果是否合理
一个简单的方法是对比原始数据的汇总。比如先直接算所有“已支付”订单的销售额总和,再对分组结果按销售额合计求和,两个数字应该一样:
total1 = df_paid["销售额"].sum() total2 = result["销售额合计"].sum() print(total1, total2)如果两者一致,说明分组汇总没有漏数据,也没有重复计算。如果不一致,优先检查筛选条件和重复值清洗步骤。
9. 常见问题与排查思路
数据分析过程中,新手最容易碰到的问题其实高度集中。整理成一张表格,方便你遇到问题时快速定位:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
import pandas报 ModuleNotFoundError | pandas 未安装,或解释器不对 | 检查当前 Python 解释器路径 | 在正确解释器中执行pip install pandas |
| CSV 中文乱码 | 编码格式不一致 | 查看文件原始编码 | 读取时指定encoding="utf-8"或encoding="gbk" |
| pandas 报警告 SettingWithCopyWarning | 对切片后的数据做原地修改 | 检查代码中是否用了链式赋值 | 使用.copy()复制子集,或改用布尔索引直接筛选 |
astype转换数字失败 | 列中有逗号、百分号等非数值字符 | 先打印该列的唯一值,观察脏数据 | 用str.replace去除特殊字符后再转换 |
| groupby 结果看起来像是“一串数字” | 结果是 Series,没有把分组字段变成普通列 | 查看结果类型 | 使用reset_index()或as_index=False |
| 导出 Excel 中文乱码 | 编码不是 utf-8-sig | 用文本编辑器打开 CSV 看原始内容 | 导出时指定encoding="utf-8-sig" |
| 数据量大的时候运行很慢 | 使用了大量循环 | 检查是否对 DataFrame 进行迭代 | 尽量使用向量化操作,避免 for 循环 |
每类问题都有一个核心原则:先看数据结构,再看代码逻辑。拿astype转换失败来说,不要直接猜原因,而是先运行df["销售额"].unique(),把列里的所有值打印出来,看到脏数据再说解决方案。排查的本质是获取更多信息,而不是盲改。
10. 新手最容易忽略的 5 个工程细节
第 1 个细节是变量命名。学习阶段用df没问题,但进入真实项目后,建议把变量名写成有业务含义的名称,比如orders_df、paid_df、city_sales_summary。这能让代码变得可读、可维护。
第 2 个细节是避免用 for 循环遍历 DataFrame。Pandas 的核心优势是向量化计算。如果发现自己写了很多for i in range(len(df)),大概率是思路错了。正确的方向是“用列操作代替行循环”,比如df["新列"] = df["销售额"] * 0.9这样的一整列计算。
第 3 个细节是inplace=True的使用争议。虽然它可以让代码看起来简洁,但会让代码不容易追踪。建议统一采用df = df.dropna()这种显式赋值的写法,目的更明确。
第 4 个细节是数据备份。洗数据之前,建议先保留一份原始数据的副本:
raw_df = df.copy()如果清洗过程出现问题,还可以从原始版本重来,不用重新读取文件。copy()这个调用在新建变量时有效避免切片视图带来的连锁修改问题。
第 5 个细节是抽样时固定随机种子。当你需要用随机抽样快速验证代码时,一定要加random_state,否则每次运行结果不一样,排查时非常痛苦:
sample_df = df.sample(n=100, random_state=42)这些细节不直接影响入门,但能帮你从“能跑”走向“跑得明白”。
11. 小结与后续学习方向
现在回头看,Pandas 入门的核心其实就是一个流程:读取数据、了解数据、清洗数据、筛选数据、分组聚合、导出结果。你不必记住 Pandas 的所有方法,只要能按这个流程走一遍,遇到不会的再去查,就已经具备了用 Python 做基础数据分析的能力。
如果你按照本文的代码练习了一遍,下一步可以有四个方向继续深入。第一个是数据可视化,用 Matplotlib 或 Seaborn 把分组结果画成柱状图、折线图,让分析结果更直观;第二个是学习 SQL,把 Pandas 的 table 思维和 SQL 的表操作对比理解,会加深对数据结构的认识;第三个是接触更多真实数据,比如公开的电商数据、招聘数据,自己设定分析问题并动手实践;第四个是掌握更进阶的 Pandas 操作,比如merge做表连接、pivot_table做透视表、apply做自定义函数处理,这些会在处理复杂数据时派上用场。
最后想给所有新手一个提醒:不要把 2 小时的目标定成“学会所有 Pandas 函数”,那是学习几个月甚至更久的结果。2 小时最合理的产出,是形成 DataFrame 的基本认知,并且亲手完成一次从原始数据到分析结果的小闭环。有了这个闭环,之后每学一个新函数,都是在往这个流程里加工具;而如果连闭环都没有,学再多的函数也很难用起来。
这篇教程里的代码,建议复制到你的本地环境跟着敲一遍。第一次跑通可能有点卡壳,但每解决一个报错,你对 Pandas 的理解都会上一个台阶。后面如果再碰到“数据分析”相关的面试题或真实项目,你会发现,最核心的考察点仍然落在这套读、察、洗、析、出的流程上。把这些基础打牢,远比追求高深复杂的技巧更重要。