简介:《Pandas入门与实践》是一份面向Python初学者的数据分析入门课件,内容聚焦Pandas在数据清洗、转换与聚合中的实用操作。课件以完整章节系统讲解Series、Index、DataFrame三大核心结构,包括Series的多种创建方式、Index的不可变特性与集合操作、Series数据访问中loc与iloc的区别,并在数据处理部分演示了dropna、fillna处理缺失值,groupby实现分组聚合,concat、merge完成数据合并等常用方法,每一部分都配有可运行的代码示例,便于边学边练。资料仅包含1个PPTX演示文稿,压缩包大小3.59MB,文件精简、内容精炼,结构按知识模块递进,适合高校教学、自学入门或快速回顾使用,也可延伸到用Pandas操作Excel表格数据的场景。目前已有1200余人学习浏览,这份课件既能帮助读者建立Pandas整体框架,也能作为日常数据处理时的速查参考。
1. 为什么数据分析第一站要选Pandas
这两年Python数据分析方向的热度一直没降过,搜索"Pandas"的人越来越多,热搜榜上出现了大量"pycharm怎么安装pandas包""pandas drop""pandas读取excel文件"这类问题,说明大家不是不想学,而是卡在了最基础的进门环节。很多人在安装、导入、读取数据这些第一步上就消耗了大量热情,还没碰到数据分析的真正核心就被劝退了。
Pandas在Python数据分析生态里的位置,打个比方就是家常菜里的炒锅。NumPy提供了数组和数学运算的底层能力,Matplotlib负责把结果画出来,而Pandas负责中间所有和表格数据打交道的活儿——读取、清洗、筛选、分组、聚合、合并、透视、导出。做数据分析的人每天至少70%的时间是在跟DataFrame打交道,而这恰恰是Pandas的主场。
我见过不少初学者绕开Pandas直接去学机器学习算法,结果处理数据时被搞到崩溃,又要回头补Pandas的课。所以我的建议很直接:不管你是做数据清洗、报表自动化还是机器学习特征工程,Pandas都是必须趟过去的第一条河。这篇课件性质的实战笔记,就是按照一条完整的数据处理链路来组织的——从环境搭建、核心数据结构,到高频操作、分组聚合,再到时间序列和性能优化,覆盖了入门到进阶的核心知识点,同时把实际使用中踩过的坑一并写出来。
适合谁来读?刚接触Python数据分析、看到Excel上百万行数据无从下手的同学,以及已经会用Pandas做简单操作但想系统化梳理知识体系的新手。老手可以直接跳到第5章看性能优化和第6章的实战避坑,应该也会有收获。
2. 安装配置:Pandas依赖栈与PyCharm集成细节
2.1 安装Pandas的正确姿势:pip与conda两条路线
安装Pandas看起来是小事,但很多人第一次就栽在这里。热搜词里"pycharm怎么安装pandas包""pandas安装""pip install pandas openpyxl"高频出现,说明大家确实需要一条清楚可靠的安装路径。
最常用的命令是:
pip install pandas以pandas 2.0以上版本为例,安装时会在后台自动拉取NumPy、python-dateutil、pytz、tzdata这几个核心依赖。不过在实际安装时,我强烈建议直接一步到位,把常用的配套库一起装上:
pip install pandas openpyxl xlrd matplotlib这里解释一下原因:openpyxl是Pandas读写.xlsx格式Excel文件的底层引擎,xlrd负责旧版.xls格式的读取,matplotlib则是后续做数据可视化时必用的库。分开装不是不行,只是经常会出现"Pandas装好了,read_excel一跑就报错,提示缺少openpyxl"这种尴尬情况。
如果你用的是Anaconda发行版,直接用conda就完了:
conda install pandasAnaconda的默认源已经包含了pandas及其全部依赖,conda会自动解决依赖版本冲突问题。这里多说一句:如果你不是对包管理特别熟悉,用Anaconda确实能省去很多依赖地狱的麻烦,尤其Windows环境下,用pip装某些科学计算包遇到编译错误的机会更大。
2.2 PyCharm里安装Pandas的两种方式
在PyCharm里装Pandas,新手最容易困惑的是"我明明在命令行pip install成功了,为什么PyCharm里import pandas还是报错"。核心原因只有一个:PyCharm默认给每个项目创建了独立的虚拟环境(venv),你在命令行装的包进入的是系统全局Python解释器,而PyCharm项目用的是虚拟环境里的Python,两套环境互不相通,自然找不到包。
解决办法就两条:
- 在PyCharm底部Terminal终端里先执行
python -m pip install pandas openpyxl,这会安装到当前项目使用的解释器环境中。 - 或者通过File -> Settings -> Project -> Python Interpreter,点右侧"+"号,搜索pandas,然后Install Package。
个人推荐第一种,因为第二种方式在搜索包时网络超时的情况比较频繁,而在终端里用python -m pip能确保安装目标解释器和当前项目一致。
Windows用户如果遇到安装过程非常慢,优先考虑切换国内镜像源,阿里云源和清华源都比较稳定:
pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple2.3 安装验证:用一行代码测试环境
安装完成后,不要急着写业务代码,先在解释器里跑一行:
import pandas as pd print(pd.__version__)如果能正常输出版本号(比如2.1.4),说明安装成功。如果这里就报错了,基本可以确定是环境配置问题,按上面说的检查虚拟环境路径即可。我见过太多人拿着"ModuleNotFoundError: No module named 'pandas'"这个报错去搜索引擎翻半天,其实只是装错了环境而已。
3. 深入理解Pandas两大核心数据结构
3.1 Series:带标签的一维数组
Series是Pandas中最基础的数据结构,可以理解为一个带索引的NumPy数组。它有两个核心组成部分:values(数据值)和index(标签索引)。
import pandas as pd s = pd.Series([85, 92, 78, 96], index=['语文', '数学', '英语', '物理']) print(s)输出结果:
语文 85 数学 92 英语 78 物理 96 dtype: int64这里的index就是标签索引,它给每个数据值起了一个"名字"。
理解Series的关键在于:它的索引机制比Python自带的列表灵活得多。列表只能通过位置下标(0、1、2...)访问,而Series既可以通过位置访问,也可以通过标签访问:
# 通过标签访问 print(s['数学']) # 92 # 通过位置访问 print(s.iloc[1]) # 92初学者经常搞混s['数学']和s.iloc[1]这两种访问方式的区别,本质上要记住一个原则:loc按标签取,iloc按位置取。前者的标签是"数学",后者的位置是第1个。等到后面DataFrame的数据筛选,这里的基础一定要打牢。
3.2 DataFrame:二维表格数据的操作中心
DataFrame是Pandas的核心中的核心,几乎所有真实场景的数据分析都建立在DataFrame之上。它是一个二维的、带行索引和列索引的表格结构,可以想象成一个增强版的Excel表格。
从字典创建DataFrame是最常见的入门方式:
import pandas as pd data = { '姓名': ['张伟', '李娜', '王强', '刘洋'], '部门': ['技术部', '市场部', '技术部', '财务部'], '薪资': [15000, 12000, 18000, 10000], '入职年份': [2019, 2021, 2018, 2022] } df = pd.DataFrame(data) print(df)输出:
姓名 部门 薪资 入职年份 0 张伟 技术部 15000 2019 1 李娜 市场部 12000 2021 2 王强 技术部 18000 2018 3 刘洋 财务部 10000 2022注意观察两个细节。一是行索引默认从0开始的整数序列,这是Pandas自动生成的。二是每一列的数据类型是统一的,而列与列之间可以是不同类型——这正是DataFrame比NumPy二维数组更适合处理真实业务数据的原因,NumPy数组要求所有元素同类型,但现实中的数据表天然就是混合类型的。
3.3 关键属性与基础信息查看
拿到一个陌生DataFrame,第一步永远是"摸清底细"。我习惯性地会先跑下面几个方法:
# 查看前5行数据 df.head() # 查看数据形状(行数, 列数) print(df.shape) # 查看列名 print(df.columns) # 查看每列数据类型 print(df.dtypes) # 查看统计摘要(数值列) print(df.describe())df.head()能快速显示数据长什么样,df.shape告诉你数据规模,df.dtypes则非常重要——很多后续操作报错,源头就是数据类型不对。比如某列看起来是数字,实际上是字符串类型,做求和时就会得到一连串的"1500012000"而不是27000。所以我拿到数据的第一步,永远是先看dtypes,心里有个数。
3.4 为什么说索引是Pandas的"银弹"
Pandas的索引机制是它区别于Excel和原生Python的一个重要设计。默认情况下,DataFrame的行索引是0到n-1的整数,但你可以把任何有业务意义的列设为索引:
# 将“姓名”列设为行索引 df.set_index('姓名', inplace=True) print(df)输出:
部门 薪资 入职年份 姓名 张伟 技术部 15000 2019 李娜 市场部 12000 2021 王强 技术部 18000 2018 刘洋 财务部 10000 2022设置了有意义的行索引之后,按标签取数就变得非常直观:
# 获取张伟的所有信息 print(df.loc['张伟'])Pandas的索引还有一个厉害之处是自动对齐。两个DataFrame做运算时,Pandas会按照索引对齐数据,而不是像NumPy那样机械地按位置对齐。这个特性在实际合并多个数据源时特别有用,后面会展开讲。
4. 高频操作实战:数据读取、选择与清洗
4.1 读写Excel文件的完整流程
Pandas最吸引人的功能之一就是读写Excel,这也是热搜词里"pandas读取excel文件""pandas读写excel文件"常年霸榜的原因。一个真实的场景:每天从业务系统导出一份Excel报表,上百列、几十万行,手工处理效率极低,用Pandas几秒钟完成全部清洗和统计。
读取Excel:
import pandas as pd # 读取第一个sheet df = pd.read_excel('销售数据.xlsx') # 读取指定sheet df = pd.read_excel('销售数据.xlsx', sheet_name='华东区') # 读取多个sheet dfs = pd.read_excel('销售数据.xlsx', sheet_name=['华东区', '华北区']) df_east = dfs['华东区']这里有几个参数值得留意。sheet_name不写默认读第一个sheet,建议明确指定,避免sheet顺序变动导致程序出错。header参数控制表头所在行,如果Excel里前几行是标题文字而不是列名,需要设置header=1或者header=2来跳过。dtype参数可以强制指定某列的数据类型,比如订单号这种看起来像数字但实际上是字符串的列,如果不强制指定,读取后前导零会丢失。
写入Excel同样方便:
# 将多个DataFrame写入同一个Excel文件的不同sheet with pd.ExcelWriter('输出结果.xlsx') as writer: df_east.to_excel(writer, sheet_name='华东区', index=False) df_north.to_excel(writer, sheet_name='华北区', index=False)注意index=False这个参数。如果不设置,Pandas会把行索引也写进Excel,生成一列没有意义的"0、1、2、3...",这在导出给业务方时是比较低级的小失误。
4.2 数据类型转换的常见坑
热搜词里出现了"pandas 数据类型转换"和"pandas drop",这两类问题本质上是同一个根源:数据类型不对,导致筛选和删除操作结果不符合预期。
最典型的一个例子是字符串型数字参与计算。假设某列"销售额"看起来是数字,实际上读进来是字符串(object类型),此时对整列做求和会报错,或者得到拼接结果。解决办法是用pd.to_numeric()做转换:
# 强制将某列转换为数值类型,errors='coerce'把无法转换的值变为NaN df['销售额'] = pd.to_numeric(df['销售额'], errors='coerce')errors='coerce'这个参数值得展开讲。它表示"如果某个值无法转成数字,就置为NaN(缺失值)"。这在处理脏数据时非常有用——不干净的脏值不会让程序崩溃,而是变成缺失值,留给后续清洗步骤。同样的逻辑也适用于pd.to_datetime(),把字符串日期转成标准时间格式时,遇到格式不规范的日期值,用errors='coerce'处理掉,避免整个程序中断。
4.3 数据筛选:loc/iloc/布尔索引
数据筛选是Pandas使用频率最高的操作之一。很多初学者习惯用链式赋值df[df['列名'] > 数值]['另一列'],这种写法在读取时没问题,但一旦涉及修改数据就极易触发SettingWithCopyWarning警告。正确做法是用.loc和.iloc:
# 布尔索引筛选:选出薪资大于12000的记录 df_filtered = df.loc[df['薪资'] > 12000] # 同时筛选行和列 df_result = df.loc[df['薪资'] > 12000, ['姓名', '部门']] # 按位置切片,取前3行,第1到第2列 df_slice = df.iloc[:3, 1:3]强调一下布尔索引的原理:df['薪资'] > 12000这个表达式会生成一个由True和False组成的布尔Series,.loc拿到这个布尔Series后,会保留对应位置为True的行。这个机制是整个Pandas筛选逻辑的基石,也是后面链式操作的基础。
4.4 缺失值处理与去重删除
数据清洗量大头是处理缺失值和重复值。过关的操作是下面这三板斧:
# 检查缺失值 print(df.isnull().sum()) # 删除含有缺失值的行 df_cleaned = df.dropna() # 填充缺失值 df_filled = df.fillna({'薪资': df['薪资'].median(), '部门': '未知'})一个大原则是:不要一上来就dropna()把所有含缺失值的行删掉。真实数据里,缺失值可能只集中在某一列,如果这列缺失比例达到20%,直接删行会损失大量有用信息。正确的思路是先isnull().sum()看每列的缺失情况,再决定是删行、删列还是填充。薪资这类数值列用中位数或均值填充比较稳妥,部门这种类别列用"未知"或众数填充更合理。
删除列的操作用drop:
# 删除指定列(axis=1表示按列删除) df = df.drop(['备注', '临时字段'], axis=1)另外,drop默认返回新对象,不会修改原DataFrame,需要加inplace=True才会原地修改,或者像上面一样重新赋值给原变量。这个细节经常被忽略,导致代码运行了但数据没变。
4.5 链式操作提升清洗效率
真实项目的数据清洗往往是多个步骤串联,可以用链式调用来写,代码更紧凑:
df_clean = (df .drop_duplicates() # 删除重复行 .dropna(subset=['订单号']) # 只查看订单号列缺失值对应行删除 .assign(销售额=lambda x: pd.to_numeric(x['销售额'], errors='coerce')) # 类型转换 .query('销售额 > 0')) # 过滤异常值这一套操作完成后,原始数据基本就已进入可控状态,可以进行下一步的分组和聚合分析了。这里注意,我用subset=['订单号']的方式让dropna只检查指定列,比无差别的全行删除精细很多,在处理宽表时尤其实用。
5. 分组聚合与数据透视:从明细到结论的关键一跳
5.1 groupby的核心逻辑:拆分-应用-合并
分组聚合是Pandas中门槛最高的操作之一,但一旦掌握了,威力极大。groupby的核心思想可以拆成三步:拆分(把数据按照键分成若干组)、应用(对每组做聚合/变换/过滤)、合并(把结果拼接成最终输出)。
一个实际的业务场景:销售明细表里有全国各区域的订单数据,需要统计每个区域的销售额总额和订单量。
result = df.groupby('区域').agg( 销售额合计=('销售额', 'sum'), 订单量=('订单号', 'count') ).reset_index()这段代码的输出就是一张新的汇总表,每一行是一个区域,列是统计指标。注意.agg()里用('销售额', 'sum')这种元组形式,第一个元素是待聚合的列名,第二个元素是聚合函数。这个写法比传统的groupby['列名'].sum()更灵活,因为它可以在一次操作中对不同列用不同的聚合方式。
5.2 agg聚合函数的进阶用法
agg在一次分组操作里做多个维度的统计,实用性非常强。举个具体例子:
result = df.groupby('部门').agg( 平均薪资=('薪资', 'mean'), 最高薪资=('薪资', 'max'), 平均入职年份=('入职年份', 'mean'), 人数=('姓名', 'count') )这是"偏平化"的分组聚合写法。如果你需要的结果是"每列保留原始列名、每种聚合函数各占一列"的分层结构,可以写成列表形式:
result = df.groupby('部门')['薪资'].agg(['mean', 'max', 'min', 'count'])两种写法没有绝对的好坏,看后续输出的需要。偏平写法适合直接导出报表,分层写法适合中间步骤的进一步计算。
5.3 数据透视表:Excel用户的无痛迁移
如果你熟悉Excel的透视表,那pivot_table上手应该非常快,因为两者的逻辑是一一对应的。
import pandas as pd pivot = pd.pivot_table( df, values='销售额', # 需要聚合的数值列 index='区域', # 行维度 columns='产品类别', # 列维度 aggfunc='sum', # 聚合函数 fill_value=0 # 空值填充为0 )这个操作在Excel里要拖拽好一阵子,用Pandas一行代码就完成了。fill_value=0把没有对应数据的格子填为0,避免结果里出现一堆NaN让阅读体验变差。
5.4 分组后筛选:filter的巧用
除了aggregate,groupby还可以配合filter做分组筛选。比如筛选出"平均薪资超过12000的部门":
filtered = df.groupby('部门').filter(lambda x: x['薪资'].mean() > 12000)这里的lambda函数接收的是每个分组对应的子DataFrame,返回True或False来决定是否保留这组。这种方式在处理"分组级条件"时非常好用,比如筛选销售总额大于100万的客户群、保留样本量足够的分组等。
6. 真实数据处理中的避坑清单与经验技巧
6.1 读取大文件时常见的MemoryError
热搜词里"pandas库""pandas下载"背后隐藏的一类问题是:数据量一大,Pandas直接内存溢出,程序崩了。
一个常见的场景:读取一个2GB的CSV文件,Pandas默认会一次性把所有数据加载到内存,这时候很容易MemoryError。解决办法不是换机器,而是用chunksize分块读取:
chunk_list = [] for chunk in pd.read_csv('big_file.csv', chunksize=100000): # 对每个分块做初步处理 chunk_filtered = chunk[chunk['销售额'] > 1000] chunk_list.append(chunk_filtered) # 最后合并所有处理过的分块 df_result = pd.concat(chunk_list, ignore_index=True)chunksize=100000表示每次只读10万行进入内存,处理完释放再读下一批。整个过程内存占用能得到有效控制。
另一个思路是在读取时只选取需要的列,用usecols参数:
df = pd.read_csv('big_file.csv', usecols=['订单号', '销售额', '区域'])这个优化对宽表的提升极其明显,有些场景下能把内存占用降到原来的十分之一。
6.2 SettingWithCopyWarning不是bug,但你必须重视
这是Pandas新手最容易遇到的问题之一。用一个布尔筛选拿到一个子DataFrame后,直接对子DataFrame赋值,Pandas会抛出SettingWithCopyWarning:
df_sub = df[df['部门'] == '技术部'] df_sub['备注'] = '技术线' # 这里会触发警告这个警告的意思是:你操作的可能只是一个临时视图(view),而不是原数据的副本(copy)。修改这个视图,有可能改不到原数据,也可能改到了,行为不确定。
正确做法是在筛选后就明确复制一份:
df_sub = df[df['部门'] == '技术部'].copy() df_sub['备注'] = '技术线'加个.copy(),既消除了警告,也明确了语义:我要的就是一份独立的副本,后面的修改不影响原df。这算是我给所有入门者的一条军规级别的建议。
6.3 inplace=True该不该用
inplace=True这个参数,社区里争议不小。我个人的态度很明确:尽量少用,除非你非常清楚自己在干什么。
原因有几个。一是很多初学者用df.dropna(inplace=True)之后发现代码没报错但就是没生效,其实是上下文不对;二是显式写df = df.dropna()其实语义更清楚,任何人都能看出你在修改df;三是inplace参数并不是所有方法都有,有些方法根本没有这个参数,混用容易记混。
所以我的建议是统一风格,一律写成显式赋值的格式:
df = df.dropna() df = df.drop('备注', axis=1)这样代码的可读性、可维护性都更高。
6.4 时间序列处理的基本操作
电商、金融、运营分析都离不开时间序列数据。Pandas对时间序列的支持非常完善,热搜词里没直接出现"时间序列",但任何做月度销售分析的人都会用到。
读取数据时让Pandas把日期列解析成时间类型:
df['订单日期'] = pd.to_datetime(df['订单日期'])接下来可以很方便地按月/季度/年聚合:
# 按月统计销售额 df['月份'] = df['订单日期'].dt.to_period('M') monthly_sales = df.groupby('月份')['销售额'].sum()dt.to_period('M')这个操作把每一条日期归到对应的月份,然后直接groupby就完成了按月汇总。这个模式在业务中非常常用,值得熟练。
如果数据恰好是按日记录的,且需要填充缺失日期:
df_daily = df.set_index('订单日期').resample('D').sum().fillna(0)resample('D')是按天重采样,会把缺失的日期补充进来,配合fillna(0)把没有交易的日期填0。
6.5 导出Excel时的小细节
数据处理完成,最后一步就是导出。导出有几个容易忽略的细节值得注意:
# 宽度调整、隐藏索引、sheet命名 with pd.ExcelWriter('最终报表.xlsx', engine='openpyxl') as writer: df_final.to_excel(writer, sheet_name='汇总', index=False)一是index=False,前面说过了,避免导出无意义的索引列。二是如果导出的DataFrame特别宽,Excel列宽不会自动适应,打开后内容被截断,需要在Excel里手动调列宽,这个暂时没有特别优雅的Pandas原生解法,可以考虑用xlsxwriter引擎设置列宽:
with pd.ExcelWriter('最终报表.xlsx', engine='xlsxwriter') as writer: df_final.to_excel(writer, sheet_name='汇总', index=False) worksheet = writer.sheets['汇总'] worksheet.set_column('A:E', 15) # 设置A到E列宽度engine从openpyxl换成xlsxwriter,就能拿到worksheet对象来设置列宽格式参数。这种处理看起来不起眼,但在交付给业务方的正式报表里,是很能体现专业度的一个细节。
7. 性能优化:处理千万级数据的基础手段
7.1 vectorized操作与apply的选择
很多从Excel转过来的人,习惯用apply逐行处理数据:
df['新列'] = df.apply(lambda row: row['单价'] * row['数量'], axis=1)这段逻辑本身没错,但在数据量大的时候速度很慢,因为每一行都调用了Python函数,性能开销很大。向量化写法则是直接用列之间的运算:
df['新列'] = df['单价'] * df['数量']这个写法看起来平淡,但执行时底层调用了NumPy的向量化计算,速度差一个数量级是很正常的。在大数据量场景下,向量化操作应该是首选。apply并不是完全不能用,只是用它处理"无法用列间运算表达的逻辑"更合适,比如逐行解析一个复杂字符串。
7.2 减少不必要的复制操作
Pandas的很多操作默认会返回新对象,连续操作会不断产生中间副本,内存开销非常可观。性能调优的两个方向:要么减少中间变量的产生,用链式操作把多个步骤串在一起;要么充分利用chunksize分批处理,避免一次性把所有数据加载进内存。
对大多数入门到中级的使用者来说,能做到"能用向量化就不用apply、能用use_cols就不读全表、能分块就不一次性加载",性能问题基本不会成为瓶颈。真正的极端优化是大数据框架(比如Dask、PySpark)该管的事,Pandas阶段先把这些基础优化做好更务实。
我在应对千万级数据文件时,最常用的一套组合拳是:usecols选列减少内存 +chunksize分块处理 + 链式操作减少中间副本。三步走下来,绝大多数单机场景都能顺利跑完。
从安装到核心数据结构,从筛选清洗到分组聚合,从日常避坑到性能优化,这一套流程走下来,Pandas的整个知识体系就算是立起来了。剩下的就是遇到真实数据时多练,踩过的每个坑都会变成你后续处理数据时的直觉判断。
本文还有配套的精品资源,点击获取