news 2026/9/26 19:04:25

Pandas数据分析入门:Series与DataFrame核心操作详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Pandas数据分析入门:Series与DataFrame核心操作详解

1. 为什么数据分析绕不开Pandas

刚接触Python数据分析那会儿,我最先装的是NumPy。数组运算确实快,但一到处理带标签的表格数据就浑身难受——想按列名取数得自己记索引,想按条件筛选得写一堆布尔运算,缺失值处理更是要手动循环。直到用上Pandas,才真正体会到什么叫“为表格数据而生”。

Pandas是Python生态里做数据分析最核心的库,没有之一。它建立在NumPy之上,但把NumPy那种“面向数组”的思维升级成了“面向表格”的思维。你可以把它理解成Python里的Excel,但能力远超Excel——处理百万行数据毫无压力,支持复杂的行列索引、分组聚合、时间序列、缺失值处理,还能直接读写Excel、CSV、JSON、SQL等十几种数据源。

这篇文章适合谁看?如果你刚开始学Python数据分析,或者从Excel转过来想用代码处理数据,又或者已经用过Pandas但总觉得“会用但没系统搞明白”,那这篇内容就是写给你的。我会从Pandas最核心的两个数据结构讲起,把创建、索引、筛选、类型转换这些基础操作掰开揉碎,配上我实际踩过的坑和总结的技巧。看完之后,你至少能做到:拿到一份Excel或CSV文件,知道怎么读进来、怎么看数据长什么样、怎么按条件筛选、怎么处理缺失值、怎么把结果导出去。

Pandas的官方文档写得很全,但全不等于好用。很多新手打开官方文档就懵了——参数太多,示例太散,不知道从哪下手。我这篇就按“实际干活需要什么”的顺序来组织,不追求面面俱到,但求每个讲到的点都能直接上手用。

2. 两个核心数据结构:Series和DataFrame

2.1 Series:带标签的一维数组

Series是Pandas里最基础的数据结构,你可以把它想成“带索引的一列数据”。普通列表只有位置,Series每个元素都有一个标签(索引),这样你就能用标签来取值,而不是只能靠位置。

创建一个Series很简单:

import pandas as pd s = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd']) print(s)

输出是:

a 10 b 20 c 30 d 40 dtype: int64

左边是索引,右边是值。如果不指定index,Pandas会自动生成0到n-1的整数索引。Series的索引不要求唯一,也不要求有序,这给了很大的灵活性。

Series有两个核心属性需要记住:values返回底层的NumPy数组,index返回索引对象。实际用的时候,s.values和s.index能帮你快速看清数据长什么样。

注意:Series的索引可以是字符串、整数、时间戳,甚至混合类型。但混合类型索引在筛选时容易出问题,建议保持索引类型一致。

2.2 DataFrame:带行列标签的二维表格

DataFrame才是Pandas真正的主角。它是一个二维表格,有行索引和列名,每一列可以有不同的数据类型。你可以把它理解成“多个Series拼在一起,共享同一个行索引”。

创建DataFrame最常见的方式是用字典:

data = { '姓名': ['张三', '李四', '王五', '赵六'], '年龄': [25, 30, 28, 35], '城市': ['北京', '上海', '广州', '深圳'], '薪资': [15000, 20000, 18000, 25000] } df = pd.DataFrame(data) print(df)

输出:

姓名 年龄 城市 薪资 0 张三 25 北京 15000 1 李四 30 上海 20000 2 王五 28 广州 18000 3 赵六 35 深圳 25000

左边那列0、1、2、3是自动生成的行索引。列的顺序默认按字典键的插入顺序,Python 3.7之后字典有序,所以列顺序是稳定的。

DataFrame的shape属性返回(行数, 列数),columns返回列名索引,dtypes返回每列的数据类型。这三个属性是我拿到任何新数据后最先看的——先知道数据多大、有哪些列、每列什么类型,再决定下一步怎么处理。

2.3 从外部文件创建DataFrame

实际工作中,数据很少是手敲进去的,大部分时候是从Excel或CSV读进来的。

读CSV:

df = pd.read_csv('data.csv', encoding='utf-8')

读Excel:

df = pd.read_excel('data.xlsx', sheet_name='Sheet1')

这两个函数参数很多,但新手只需要关注几个关键的:

参数作用常用值
encoding文件编码'utf-8'、'gbk'
header表头行号0(默认第一行)、None(无表头)
names自定义列名列表
usecols只读某些列列名列表或索引列表
nrows只读前n行整数

中文CSV文件经常遇到编码问题。Windows上Excel导出的CSV默认是gbk编码,用utf-8读会报错。我的经验是:先试utf-8,报错就换gbk,再不行用chardet库检测编码。

实操心得:读大文件时先用nrows=100读前100行看看结构,确认列名和数据类型没问题再全量读。直接读几个G的文件容易把内存撑爆。

3. 数据查看与索引操作

3.1 快速了解数据全貌

拿到DataFrame后,别急着分析,先花30秒把数据摸清楚。我习惯按这个顺序来:

df.head() # 看前5行 df.tail() # 看后5行 df.info() # 看每列类型和非空值数量 df.describe() # 看数值列的统计摘要 df.shape # 看行列数

info()特别有用,它会告诉你每列有多少非空值。如果某列非空值数量明显少于总行数,说明有缺失值,后面要处理。

describe()默认只统计数值列,输出count、mean、std、min、25%、50%、75%、max。如果想让类别列也参与统计,加参数include='all'。

3.2 列操作:选取、新增、删除

选一列:

df['姓名'] # 返回Series df[['姓名', '年龄']] # 返回DataFrame

注意单方括号和双方括号的区别:单方括号选一列返回Series,双方括号选多列返回DataFrame。这个区别在后续操作中很重要,因为Series和DataFrame支持的方法不完全一样。

新增一列:

df['年薪'] = df['薪资'] * 12

删除列:

df.drop('年薪', axis=1, inplace=True)

axis=1表示操作列,axis=0表示操作行。inplace=True表示直接在原DataFrame上修改,不返回新对象。我个人的习惯是不用inplace,而是重新赋值:df = df.drop('年薪', axis=1)。这样代码更清晰,也避免链式操作时的警告。

3.3 行操作:loc和iloc

这是Pandas新手最容易混淆的地方。记住一句话:loc用标签,iloc用位置。

df.loc[0] # 取索引为0的行 df.iloc[0] # 取第1行(位置0) df.loc[0:2] # 取索引0到2的行(包含2) df.iloc[0:2] # 取位置0到1的行(不包含2)

loc的切片是闭区间,iloc的切片是左闭右开——这和Python列表切片一致,但和loc不一致,容易搞混。

同时选行列:

df.loc[0:2, ['姓名', '年龄']] # 前3行的姓名和年龄列 df.iloc[0:2, 0:2] # 前2行前2列

常见坑:如果DataFrame的索引不是默认整数索引,比如是字符串索引,那df[0]会报错,必须用df.loc['标签']或df.iloc[0]。我建议养成习惯:取行一律用loc或iloc,不用方括号。

3.4 布尔索引:按条件筛选

这是Pandas最强大的功能之一。比如筛选年龄大于28的人:

df[df['年龄'] > 28]

多个条件用&(与)、|(或),每个条件必须用括号包起来:

df[(df['年龄'] > 28) & (df['城市'] == '北京')]

为什么必须加括号?因为Python中&的优先级比>高,不加括号会先算&再算比较,结果完全不对。这个坑我踩过不止一次。

筛选某列值在某个列表中:

df[df['城市'].isin(['北京', '上海'])]

筛选某列值不在列表中,前面加~:

df[~df['城市'].isin(['北京', '上海'])]

3.5 设置和重置索引

有时候需要把某一列设为索引,比如用日期做索引方便按时间筛选:

df.set_index('日期', inplace=True)

想恢复默认整数索引:

df.reset_index(inplace=True)

如果原来的索引有名字,reset后会变成一列。如果不想保留原索引,加drop=True。

4. 数据类型转换与缺失值处理

4.1 查看和转换数据类型

df.dtypes能看到每列的类型。常见类型有int64、float64、object(通常是字符串)、datetime64、bool。

转换类型用astype():

df['年龄'] = df['年龄'].astype('int32') df['薪资'] = df['薪资'].astype('float64')

字符串转数字要小心。如果字符串里有非数字字符,astype会报错。这时候用pd.to_numeric(),加参数errors='coerce'把无法转换的变成NaN:

df['薪资'] = pd.to_numeric(df['薪资'], errors='coerce')

日期转换用pd.to_datetime():

df['日期'] = pd.to_datetime(df['日期'], format='%Y-%m-%d')

不指定format也行,Pandas会自动推断,但数据量大时指定format能快很多。

4.2 缺失值检测与处理

检测缺失值:

df.isnull() # 返回布尔DataFrame df.isnull().sum() # 每列缺失值数量 df.isnull().sum().sum() # 总缺失值数量

处理缺失值有几种策略:

删除缺失值:

df.dropna() # 删除任何有缺失值的行 df.dropna(subset=['薪资']) # 只删除薪资列有缺失的行 df.dropna(how='all') # 只删除全为空的行

填充缺失值:

df.fillna(0) # 用0填充 df['薪资'].fillna(df['薪资'].mean()) # 用均值填充 df['城市'].fillna('未知') # 用固定值填充

向前填充和向后填充:

df.fillna(method='ffill') # 用前一个值填充 df.fillna(method='bfill') # 用后一个值填充

实操心得:填充缺失值没有万能方案。数值列用均值或中位数,类别列用众数或“未知”,时间序列用前向填充。关键是填充后要检查分布有没有被扭曲。我一般会对比填充前后describe()的结果,如果均值变化超过5%,就要重新考虑填充策略。

4.3 重复值处理

检测重复行:

df.duplicated() # 返回布尔Series df.duplicated().sum() # 重复行数量

删除重复行:

df.drop_duplicates() # 完全重复的行 df.drop_duplicates(subset=['姓名']) # 姓名列重复的行 df.drop_duplicates(subset=['姓名'], keep='last') # 保留最后一条

keep参数默认是'first',保留第一条;'last'保留最后一条;False则全部删除。

5. 数据排序、分组与聚合

5.1 排序

按某一列排序:

df.sort_values('薪资', ascending=False)

按多列排序:

df.sort_values(['城市', '薪资'], ascending=[True, False])

按索引排序:

df.sort_index()

排序后索引会跟着数据走,如果想让索引重新从0开始,加ignore_index=True。

5.2 分组聚合

这是Pandas最核心的分析功能。按城市分组算平均薪资:

df.groupby('城市')['薪资'].mean()

按城市分组算多个统计量:

df.groupby('城市')['薪资'].agg(['mean', 'max', 'min', 'count'])

对不同列做不同聚合:

df.groupby('城市').agg({ '薪资': ['mean', 'max'], '年龄': 'mean' })

groupby的结果是一个GroupBy对象,不直接显示数据,需要接一个聚合函数才会出结果。常用的聚合函数有:mean、sum、count、max、min、std、median、nunique。

5.3 数据透视表

Pandas的pivot_table和Excel的数据透视表功能类似:

pd.pivot_table(df, values='薪资', index='城市', columns='性别', aggfunc='mean')

这个功能在交叉分析时特别有用,比如想看不同城市不同性别的平均薪资,一行代码就出来了。

6. 文件读写与导出

6.1 读Excel的常见问题

pd.read_excel()依赖openpyxl库(读xlsx)或xlrd库(读xls)。如果报错说缺少引擎,装一下就行:

pip install openpyxl

读多个sheet:

xls = pd.ExcelFile('data.xlsx') print(xls.sheet_names) # 查看所有sheet名 df = pd.read_excel(xls, sheet_name='Sheet2')

6.2 写Excel和CSV

导出CSV:

df.to_csv('output.csv', index=False, encoding='utf-8-sig')

index=False表示不写行索引。encoding='utf-8-sig'带BOM头,用Excel打开不会乱码。如果对方用WPS或老版本Excel,用gbk编码更稳。

导出Excel:

df.to_excel('output.xlsx', index=False, sheet_name='结果')

导出多个sheet:

with pd.ExcelWriter('output.xlsx') as writer: df1.to_excel(writer, sheet_name='Sheet1', index=False) df2.to_excel(writer, sheet_name='Sheet2', index=False)

注意:写Excel时如果文件被其他程序占用,会报PermissionError。确保目标文件没有被Excel打开。

7. 常见问题与排查技巧

7.1 SettingWithCopyWarning警告

这个警告几乎每个Pandas用户都遇到过。原因是Pandas无法确定你是在操作原DataFrame的视图还是副本。比如:

df[df['年龄'] > 28]['薪资'] = 30000 # 会触发警告,且可能不生效

正确做法是用loc:

df.loc[df['年龄'] > 28, '薪资'] = 30000

或者先复制一份:

subset = df[df['年龄'] > 28].copy() subset['薪资'] = 30000

7.2 中文列名和路径问题

中文列名本身没问题,但在某些操作中容易因为编码问题出错。我的建议是:如果数据要长期维护,列名用英文;如果只是临时分析,中文列名更方便阅读。

文件路径含中文时,Windows上一般没问题,Linux上要注意编码。用pathlib处理路径更稳:

from pathlib import Path file_path = Path('数据') / '销售数据.xlsx' df = pd.read_excel(file_path)

7.3 内存不足

处理大文件时内存不够,可以分块读:

chunks = pd.read_csv('big_file.csv', chunksize=100000) for chunk in chunks: process(chunk)

或者只读需要的列:

df = pd.read_csv('big_file.csv', usecols=['姓名', '薪资'])

还可以指定更小的数据类型:

df = pd.read_csv('big_file.csv', dtype={'年龄': 'int32', '薪资': 'float32'})

7.4 常见问题速查表

问题原因解决方法
读CSV乱码编码不匹配换encoding参数,试utf-8、gbk、utf-8-sig
读Excel报错缺少引擎pip install openpyxl
筛选结果为空条件类型不匹配检查列类型,字符串和数字不能直接比较
分组后列消失分组列变成了索引加as_index=False或reset_index()
排序后索引乱索引跟着数据走加ignore_index=True
填充缺失值不生效用了inplace但没接收返回值重新赋值或加inplace=True

8. 我踩过的坑和总结的技巧

第一个坑是链式索引。刚开始用Pandas时,我总喜欢写df[df['A'] > 1]['B'] = 2这种链式操作,结果要么报警告,要么改了没效果。后来养成习惯:只要涉及修改,一律用df.loc[条件, 列名] = 值。

第二个坑是数据类型。从Excel读进来的数字列,如果某一行有个“暂无”之类的文本,整列会变成object类型。这时候做数值计算就会报错。我的做法是:读完数据先df.info()看一眼,发现类型不对就用pd.to_numeric(errors='coerce')转,把无法转换的变成NaN再处理。

第三个坑是索引对齐。两个DataFrame做运算时,Pandas会自动按索引对齐,索引不匹配的位置会变成NaN。这个特性有时候很有用,但如果不注意就会得到一堆NaN。解决办法是运算前先reset_index()或者确认两边索引一致。

第四个坑是inplace参数。早期版本很多函数支持inplace=True,但新版本逐渐在弱化这个参数。我现在基本不用inplace,而是重新赋值,代码更清晰,也不容易出错。

最后分享一个提高效率的技巧:把常用的数据探查代码封装成一个函数,每次拿到新数据先跑一遍。比如:

def explore(df): print(f"形状: {df.shape}") print(f"列名: {df.columns.tolist()}") print(f"类型:\n{df.dtypes}") print(f"缺失值:\n{df.isnull().sum()}") print(f"重复行: {df.duplicated().sum()}") print(df.head())

这个函数帮我省了大量重复敲代码的时间,也避免了遗漏检查项。Pandas的内容很多,但核心就是这些:数据结构、索引、筛选、类型转换、缺失值、分组聚合、文件读写。把这些练熟,日常数据分析任务基本都能应付。后面再学合并、时间序列、窗口函数这些进阶内容,就有了扎实的基础。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 19:03:24

MarkText中文工作流重建手册:从安装到专业技术写作

1. MarkText不是Typora的平替,而是另一条技术路径的实践者MarkText中文版——这个在2024年GitHub趋势榜上反复出现的名字,常被新手误读为“Typora汉化版”或“免费替代品”。但实际接触过它的人都清楚:它根本不是Typora的影子,而是…

作者头像 李华
网站建设 2026/9/26 19:01:02

富士通U9310X Win10驱动安装全解析:硬件ID匹配与INF改造

1. 项目概述:为什么一台停产十年的老商务本,现在装驱动还值得专门写一篇长文?富士通LifeBook U9310X——这台2012年发布的超轻薄商务本,当年以798克机身、全金属C面和可选的1080p触控屏惊艳市场。它不是游戏本,也不是网…

作者头像 李华
网站建设 2026/9/26 19:00:02

学生智能选课系统课设通关指南:MySQL数据库与JavaWeb事务实战

简介:mysql学生智能选课系统毕业设计资源包,面向高校计算机相关专业学生、课程设计参与者及需要快速搭建选课平台的开发人员。系统采用SSM框架与MySQL数据库,围绕校园选课场景完成学生在线选课、教师课程管理、课程信息发布等功能&#xff0c…

作者头像 李华
网站建设 2026/9/26 18:58:36

LangChain.js Agent 长期记忆实战:Milvus 向量数据库检索与调优

1. 为什么短期记忆撑不起一个真正的 Agent做过 LangChain.js Agent 的人大概都有过这种体验:聊了七八轮之后,Agent 开始"失忆",前面告诉它的用户偏好、业务约束、已经确认过的结论,它统统不记得了。你翻文档发现有个Buf…

作者头像 李华
网站建设 2026/9/26 18:57:46

AI代码审查误报压制:按类别采纳率与门禁设置实战

1. AI 代码审查的误报困局与破局思路AI 代码审查工具这两年铺得很快,几乎每个中大型研发团队都在 CI 流水线里挂了至少一个。但真正用起来之后,绝大多数团队都会撞上同一堵墙:误报太多,开发者开始无视评论。这个现象有个很形象的说…

作者头像 李华