简介:面向具备 Python 基础读者的《Pandas 数据分析实战》是一份 PDF 版实操教程,共 1 个 PDF 文件,压缩后 53.38MB,已有 269 人学习。书中以近百个真实数据集案例为主线,系统讲解 pandas 在科学计算、时间序列分析和数据可视化中的高级应用,重点涉及数据清洗、分组聚合、时间序列重采样,以及与 Matplotlib、Seaborn 的集成绘图。每个案例都配有分步解决方案,并在 iPython Notebook 中给出可复现路径,便于读者从数据选取与子集隔离开始,逐步掌握布尔索引、多重索引、数据拆分重组与分组聚合等核心操作,以及为机器学习任务整理杂乱真实数据的完整流程。内容还涵盖通过 SQL-like 操作合并多来源数据、在金融和科学场景中运用时间序列与统计计算,并以目录化的方式呈现高质量配方,适合按需检索或系统通读。读者学习后可明显提升数据处理效率,形成高效、地道的 pandas 编程习惯,并增强可视化洞察力,在建模与报表制作等场景中更快获得可靠结论。
1. 分析项目怎么落地——动手写码前的思路整理
不管你是刚接触Pandas的新手,还是已经用Python写过几段数据处理脚本的进阶选手,拿到一份真实业务数据的时候,最容易犯的错就是直接打开IDE开始写代码。我见过太多人做了半年数据分析,打开CSV先来一句pd.read_csv(),然后立刻开始drop、fillna,忙活半天发现分析目标根本没想清楚,产出的表格自己都觉得没价值。
1.1 接到分析需求后的第一个动作
先说一个真实场景。我接过一个电商店铺的订单明细数据,十几万行,字段有订单号、下单时间、商品类目、销售数量、单价、成本、客户城市、支付渠道等。老板只丢给我一句话:“看看这个月生意怎么样。”
“看看生意怎么样”不是分析目标。如果我直接开始折腾Pandas,大概率会在数据清洗上耗掉大半天,最后交出一堆流水汇总。正确的第一步是先拆需求,通常我会习惯性问自己三个问题:
- 分析要给谁看?老板看结论,运营看细节,不同受众要的不一样
- 核心问题是什么?是要看整体营收变化,还是要找增长或下滑的原因?
- 数据能支撑到什么程度?字段够不够?周期覆盖是否完整?有没有脏数据风险?
把这三个问题想清楚,分析框架就出来了。比如这次我最终把“看看生意怎么样”拆成了四个具体方向:整体销售趋势、类目结构变化、地区分布情况、支付渠道偏好。每一个方向都能对应到Excel透视表里的一类操作,而用Pandas来做,本质上就是把这些操作脚本化、可复用化。
1.2 Pandas在完整分析流程中的定位
数据分析的标准流程是:数据获取→数据清洗→数据加工→数据可视化→结论输出。Pandas在这条链路里扮演的角色是“加工车间”,它负责把原始数据变成干净、规整、可以喂给下一步分析的结构化数据。
打个比方,数据分析就像做菜。原始数据是刚从菜市场买回来的菜,带泥带虫甚至有些叶子已经烂了;Pandas是你手里的洗菜盆和砧板,负责择菜、清洗、切配;至于最终端上桌的菜品——也就是图表和结论——那是后续用Matplotlib、Seaborn或者直接输出Excel报表完成的。没有洗菜切配这一步,再好的厨艺也白搭。
搞清楚Pandas的定位很重要,因为很多人学Pandas容易陷入“学API”的误区——今天学merge,明天学pivot_table,结果遇到真实数据还是无从下手。实际上Pandas的常用操作就那么几十个,关键是要建立起“拿到数据先摸情况,再逐步加工”的分析习惯。
2. 环境准备与数据读取——从零开始搭好分析环境
环境准备是Pandas实战的第一道坎。很多新手不是学不会Pandas,而是卡在安装这一步就放弃了。我见过有人在网上照着教程装了三次都没成功,最后发现是Python版本和Pandas版本不匹配。
2.1 Pandas安装的两种主流方式
安装Pandas本身并不复杂,核心是选对方式。
第一种:直接pip安装
如果你电脑里已经装好了Python,最简单的办法是在终端或命令行里执行:
pip install pandas如果你用的是国内网络,建议加一个国内镜像源,速度快很多,常规操作是这样:
pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple第二种:通过PyCharm安装
用PyCharm做开发的同学,可以直接在“File → Settings → Project → Python Interpreter”里点击“+”号,搜索pandas之后点Install Package。这个方法的好处是它会自动帮你匹配当前Python版本对应的Pandas版本,不太容易出现兼容性问题。
装完以后验证一下是否成功,在终端里执行:
python -c "import pandas as pd; print(pd.__version__)"能打印出版本号就说明环境已经OK了。
这里说一个我自己踩过的坑。Pandas版本升级到2.x之后,有些旧代码会报AttributeError或者FutureWarning,比如append方法在2.0版本中被移除了,如果你在网上下载的旧教程代码里看到df.append(),跑起来就会报错。建议安装时直接用最新版,遇到旧代码报错就上网搜一下对应API是否已经过期,这个问题在新版本里几乎人人都要碰上一次。
2.2 读取Excel和CSV文件的实用参数
数据分析的场景里,Excel和CSV是最常见的数据源格式,Pandas读取这两个格式的接口分别是:
import pandas as pd # 读取CSV文件 df = pd.read_csv('sales_data.csv') # 读取Excel文件 df = pd.read_excel('sales_data.xlsx', sheet_name='订单明细')但实际业务中远没有这么简单。我拿到过的销售数据,有的表头不在第一行,有的文件编码是GBK而不是UTF-8,有的Excel里有多个Sheet。如果不处理这些细节,读进来的DataFrame简直是灾难现场。
用read_csv读取中文文件时,如果遇到UnicodeDecodeError,通常是因为文件编码是GBK,加上encoding='gbk'或encoding='gb18030'参数就能解决:
df = pd.read_csv('sales_data.csv', encoding='gb18030')读取Excel时,如果发现数据不是从第一行开始的,比如前面有两行标题说明,可以用skiprows跳过:
df = pd.read_excel('sales_data.xlsx', sheet_name='订单明细', skiprows=2)读进来之后,第一步永远是摸数据底细,我常用的“侦查四件套”是:
# 1. 看前5行数据 df.head() # 2. 看行列规模和列名 df.shape df.columns # 3. 看每列的数据类型 df.dtypes # 4. 看描述性统计 df.describe()这四句话能帮你快速判断数据长什么样、有没有明显异常、哪些列需要清洗。做完这一步再去写处理逻辑,心里才真正有底。
2.3 数据类型转换——最容易被忽视的坑
Pandas分析中最常见的一个坑就是数据类型错乱。Excel里看起来是一个数字,读进Pandas却变成了字符串;时间明明是日期格式,读进来却是object。后者导致排序错乱、计算报错,而前者会让所有聚合结果出错。
我处理过一个典型场景:订单明细里的“订单时间”列,读进来之后是object类型,直接排序会出现“2024-1月排到2024-10月后面”的怪事。解决办法是用pd.to_datetime()转换:
df['订单时间'] = pd.to_datetime(df['订单时间'])数值列如果发现有逗号或空格混在数字里,比如“1,200”或“1200 ”,用pd.to_numeric配合errors='coerce'批量转换:
df['销售额'] = pd.to_numeric(df['销售额'].str.replace(',', ''), errors='coerce')str.replace用来去掉千分位逗号,errors='coerce'的作用是转换失败时填入NaN而不是报错中断,方便后续统一清洗。这几个操作看起来简单,但在真实场景里几乎每次都能用上。
3. 数据清洗实战——哪些坑我替你先踩过了
数据清洗在Pandas实战里的比重,比你想象的要大得多。有句老话说“数据分析80%的时间花在数据清洗上”,真的一点都不夸张。我第一次独立做数据分析项目时,花了一整天清洗,真正用来分析的时间反而只有两三个小时。
3.1 缺失值处理的取舍逻辑
拿到带空值的数据,第一反应不要是“把空值删掉”或者“全部填0”。正确的思路是先搞清楚空值为什么存在。
看一个实际的例子。订单数据里有一列“客户ID”,如果某个订单的客户ID为空,那通常说明这个订单可能是线下手工单或者测试单,直接删掉影响不大。但“商品类目”为空就不一样了,如果删掉就会导致该订单无法被归类。这时候要分情况处理。
Pandas里最常用的几个缺失值处理方法是:
# 查看每列的空值数量 df.isnull().sum() # 删除含有空值的行 df.dropna() # 使用指定值填充 df.fillna({'商品类目': '未知', '销售额': 0}) # 使用前后值填充(适用于时间序列) df['销售额'].fillna(method='ffill')我自己的经验法则是:当你对缺失值的业务含义不够确定时,宁可先不处理,也不要盲目fillna或dropna。一个稳妥的做法是把空值单独标记出来,比如加一列“是否缺失”,等分析到具体模块时再决定怎么处理。
比如说分析“各支付渠道销售额”的时候,支付渠道为空的那几单我可以直接跳过;但分析“总销售额”的时候,这几单又是实打实的收入,不能删。这种场景在真实业务里太常见了。
3.2 重复值识别与异常记录处理
重复值比缺失值更容易被忽略。因为表格一多,肉眼根本看不出重复在哪儿。
用Pandas检查重复值:
# 检查所有列都相同的重复行 df.duplicated().sum() # 按指定列判断重复 df.duplicated(subset=['订单号']).sum() # 查看重复的具体行 df[df.duplicated(subset=['订单号'], keep=False)] # 删除重复值,保留第一次出现的记录 df.drop_duplicates(subset=['订单号'], keep='first')这里有个细节需要注意:keep=False的意思是把所有重复的行(包括第一次出现的)都标记为True,方便你查看;而keep='first'则是在去重时保留第一次出现的记录。如果你要检查某列是否有重复,用后者;如果你要查看所有重复的数据做人工判断,用前者。
至于异常值,我见过最离谱的数据是销售数量一列里有个值是“-500”,明显是系统bug或者测试数据。这种数据如果混进聚合计算,会把平均销售量直接拉偏。
处理异常值的思路是先找出来再看业务上是否合理:
# 找出销售数量为负数的记录 df[df['销售数量'] < 0] # 用四分位距(IQR)检测离群值 Q1 = df['销售数量'].quantile(0.25) Q3 = df['销售数量'].quantile(0.75) IQR = Q3 - Q1 outlier = df[(df['销售数量'] < Q1 - 1.5 * IQR) | (df['销售数量'] > Q3 + 1.5 * IQR)]对于确认是脏数据的记录,直接删除或者修正都行;对于疑似合理的离群值(比如大订单),可以保留也可以单独标注,但一定不要静默处理。
3.3 列名标准化与字段拆分的实用技巧
真实拿到的数据,列名往往是中文、英文、大小写混着来,还有带空格和特殊字符的。比如同一份报告里既有“Sales”又有“销售额”还有“sales ”,分析到一半才发现这些其实是同一个字段的不同写法。
我的习惯是拿到数据后先做一次列名统一:
# 去除列名两端的空格,统一转为小写 df.columns = df.columns.str.strip().str.lower() # 批量替换中文列名为英文 df.rename(columns={'订单号': 'order_id', '下单时间': 'order_time'}, inplace=True)统一列名的好处是后续写代码不用反复纠结到底该用哪个名字,而且做数据合并时对列名要求特别严格,多一个空格都可能合并失败。
字段拆分也是高频操作,最典型的是从完整地址里拆出城市,从身份证号里拆出生日期,从支付时间字符串里拆出日期和时刻。用str方法就可以实现:
# 从“北京市朝阳区…”拆出前3位城市信息 df['城市'] = df['地址'].str[:3] # 把“2024-06-01 14:30:00”拆成日期和时刻两列 df['日期'] = pd.to_datetime(df['下单时间']).dt.date df['时刻'] = pd.to_datetime(df['下单时间']).dt.hour4. 数据聚合与业务洞察——把明细数据变成分析结论
数据洗得差不多了,终于轮到Pandas真正发挥威力的环节——聚合计算。这一部分对应的正是Excel透视表的功能,但灵活度和效率碾压Excel,尤其是数据量大到Excel卡死的时候,优势更加明显。
4.1 groupby多维度聚合的核心玩法
groupby是Pandas里最重要的聚合方法,没有之一。它的使用场景覆盖了“按月汇总销售额”“按类目计算平均单价”“按城市和渠道交叉统计订单量”等一切分组统计需求。
以电商订单数据为例,最基础的按月汇总:
# 先提取月份列 df['月份'] = df['下单时间'].dt.to_period('M') # 按月统计销售额、订单数、销量 monthly_summary = df.groupby('月份').agg( 销售额=('销售额', 'sum'), 订单数=('订单号', 'count'), 总销量=('销售数量', 'sum') ).reset_index()这里agg可以同时聚合多个字段,括号里的写法是(列名, 聚合方式),非常直观。除了sum和count,常用的还有mean、max、min、nunique等。
多维度交叉统计同样简单。比如要分析不同城市、不同支付渠道的销售额:
city_channel = df.groupby(['城市', '支付渠道']).agg( 销售额=('销售额', 'sum'), 订单数=('订单号', 'count') ).reset_index()跑完直接得到一个透视后的明细表。这个结果可以保存成Excel,也可以直接用Pandas自带的plot方法可视化。
4.2 派生字段与核心指标计算
分析不只是汇总已有字段,更多时候需要创造新字段。所谓派生字段,就是基于现有的列计算出来的新列,它往往代表了更有业务意义的指标。
比如订单数据里,单独看“销售额”和“成本”意义有限,但看“毛利率”就能说明很多问题:
df['毛利率'] = (df['销售额'] - df['成本']) / df['销售额']再比如分析复购率,需要先按客户分组找每个人下单次数:
customer_stats = df.groupby('客户ID').agg( 订单数=('订单号', 'count'), 消费总额=('销售额', 'sum') ).reset_index() # 标记是否回头客(下单次数大于1) customer_stats['是否回头客'] = customer_stats['订单数'] > 1这些派生字段才是真正能回答业务问题的核心。数据分析的价值不在于把流水账算清楚,而在于从数据中发现模式——哪些类目利润高、哪些客户有复购潜力、哪些时段适合做促销。同样的底层数据,会不会构造派生字段,直接决定分析深度。
4.3 聚合结果的保存与可视化出口
分析结果最终要么落在图表上,要么落到Excel里给业务同事查看。Pandas和可视化库、Excel的衔接都做得很顺手。
导出Excel的时候,我习惯同时输出多个Sheet,把不同维度的分析结果放一起:
with pd.ExcelWriter('销售分析结果.xlsx') as writer: monthly_summary.to_excel(writer, sheet_name='月度汇总', index=False) city_channel.to_excel(writer, sheet_name='城市渠道', index=False) customer_stats.to_excel(writer, sheet_name='客户统计', index=False)可视化直接用matplotlib或seaborn,Pandas的plot方法也够用。比如画月度销售额趋势:
import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] # 解决中文显示问题 plt.rcParams['axes.unicode_minus'] = False monthly_summary.plot(x='月份', y='销售额', kind='line') plt.title('月度销售额趋势') plt.show()有一点需要注意:Matplotlib默认在图表中不支持中文显示。如果图里出现方框,就是缺少中文字体配置。上面代码里设置font.sans-serif为SimHei就是解决这个问题的。这是中文数据分析必踩的坑,提前配置好能省很多事。
5. 常见报错与排查经验速查
Pandas用久了就能发现,报错翻来覆去就是那几种。把高频问题整理出来,遇到直接对照排查,能省下不少搜索时间。
5.1 高频报错速查表
| 报错信息 | 出现原因 | 解决办法 |
|---|---|---|
UnicodeDecodeError | 文件编码不是UTF-8 | 读取时加encoding='gbk'或encoding='gb18030' |
KeyError: 'xxx' | 访问不存在的列名 | 先用df.columns查看实际列名,注意中英文、空格 |
ValueError: cannot reindex | 两个DataFrame的索引或列不一致 | 用pd.merge()前先确认关联键的数据类型一致 |
SettingWithCopyWarning | 在DataFrame切片后试图赋值 | 用.loc或显式.copy()避免链式赋值 |
AttributeError: 'DataFrame' object has no attribute 'append' | Pandas 2.0版本移除了append方法 | 改用pd.concat([df1, df2], ignore_index=True) |
ParserError | CSV文件里有多余分隔符或引号 | 加on_bad_lines='skip'或sep参数指定分隔符 |
SettingWithCopyWarning是新手最常忽略的警告,它不会立刻报错,但会导致赋值不生效,最后分析结果莫名其妙地出错。我之前就吃过这个亏——对df[df['城市']=='北京']切片后的对象赋值,结果原表没变化,排查了半天。记住一个原则:对切片副本要赋值时,要么直接用df.loc[df['城市']=='北京', '新列'] = value,要么先.copy()再操作。
5.2 数据量变大时的提速思路
当数据量从几十万行涨到几百万行甚至上千万行时,同样的Pandas代码执行速度会明显变慢。这时候有几个提速技巧非常实用。
减少不必要的循环。Pandas新手最容易犯的错是用for循环逐行遍历DataFrame。同样的逻辑,用向量化操作写出来通常快几十倍以上。
比如要新增一列“订单级别”,假设订单金额大于500为“高”,否则为“低”。新手写法是:
for i in range(len(df)): if df.loc[i, '销售额'] > 500: df.loc[i, '订单级别'] = '高' else: df.loc[i, '订单级别'] = '低'用np.where向量化一行搞定:
import numpy as np df['订单级别'] = np.where(df['销售额'] > 500, '高', '低')只在需要的列上做计算。如果只需要两三列做聚合,先选出这些列再算,会明显减少内存开销。df[['销售额', '城市']].groupby('城市').sum()比df.groupby('城市')['销售额'].sum()多传了一列进去,计算速度也有差异。
善用category数据类型。如果你的某一列只有少数几个固定取值,比如“支付渠道”只有“微信”“支付宝”“银行卡”,把它转成category类型能大幅节省内存:
df['支付渠道'] = df['支付渠道'].astype('category')这几个技巧加起来,处理千万级数据也基本不会卡到跑不动,足够覆盖绝大多数日常分析场景。
5.3 从单一脚本走向可复用的小工具
当你用一个Pandas脚本成功完成一次分析之后,不要就此结束。我个人的经验是:数据分析这项技能,最大的提升来自于把一次性的脚本总结成可复用的工具。
比如你这次写了“读取销售表→清洗→按月汇总→导出Excel”的过程,完全可以把这个流程封装成一个函数,下次拿到新的数据文件,直接调用一个函数就出结果:
def analyze_sales(file_path, sheet_name): """从Excel读取销售数据,输出月度汇总和城市渠道汇总。""" df = pd.read_excel(file_path, sheet_name=sheet_name) df.columns = df.columns.str.strip() df['下单时间'] = pd.to_datetime(df['下单时间']) df['月份'] = df['下单时间'].dt.to_period('M') monthly = df.groupby('月份').agg( 销售额=('销售额', 'sum'), 订单数=('订单号', 'count') ).reset_index() city_channel = df.groupby(['城市', '支付渠道']).agg( 销售额=('销售额', 'sum') ).reset_index() with pd.ExcelWriter('销售分析结果.xlsx') as writer: monthly.to_excel(writer, sheet_name='月度汇总', index=False) city_channel.to_excel(writer, sheet_name='城市渠道', index=False) return df, monthly, city_channel这样下次不管来什么格式差不多的数据,一行代码就能完成整套分析流程。实际上我在做不同的分析项目时发现,平时花点时间把这些通用逻辑沉淀成自己的函数库,到真正赶项目的时候,效率至少翻一倍。
最后分享一个我在实际操作中的体会:Pandas本身的函数学起来并不困难,真正拉开差距的是你拿到一份毫无头绪的数据时,能不能快速判断出该用什么处理步骤、该按什么顺序推进。多拿真实数据去练手是唯一的捷径。每次分析结束,把走过的弯路、跳过的坑记录下来——这些经验积累起来,比背一百个API都管用。
本文还有配套的精品资源,点击获取