但凡用Python做数据分析pandas是你绕不开的一个库。我见过不少新手下载了一堆教程结果连数据结构都没搞明白就上手跑代码最后被各种报错劝退。也有朋友在头歌Educoder平台上做pandas作业题目看着简单但提交评测就是过不了问我能不能一次性把pandas基础讲清楚。这篇文章我就以实际使用经验为主线把pandas从安装、数据结构创建、读写Excel和文本文件、数据类型转换、正则表达式配合、数据清洗一直到ewm函数参数这些高频考点全部串一遍。文中的代码示例都是我平时工作里直接能用的写法每个关键参数我都尽量解释“为什么这么设”你照着敲一遍基本就能应付日常数据处理和头歌上的基础关卡了。适合刚学Python数据分析的初学者也适合那些用过pandas但遇到报错还是一头雾水的朋友。1. 环境准备与安装别让环境问题挡住第一步1.1 PyCharm里安装pandas包的两种方式先说安装。很多人在PyCharm里装pandas第一反应是打开File菜单去找Settings再逐个点开Project下的Python Interpreter点右上角的加号搜索pandas等它转圈下载。这种方式本身没错但有一个问题下载源默认是官方PyPI在国内网络环境下经常跑到一半就超时失败。我的建议是先把pip的下载源换成国内镜像比如清华的源再来装。第二种方式是直接在PyCharm底部的Terminal终端里执行pip install pandas如果当前Python环境不是系统自带的而是项目里单独创建的虚拟环境要确认这个终端确实激活了对应的虚拟环境。判断方法很简单终端命令行的前面如果出现了项目名比如(venv) C:\Users\...这样说明是在虚拟环境里如果看不到项目名只是C:\Users\...那很可能装到全局Python里去了PyCharm的项目解释器里还是找不到pandas。如果你是刚装了Anaconda那pandas早就内置了打开PyCharm新建项目时解释器记得选conda环境而不是默认的Project Venv否则又会重复装一遍。这里给一个检查是否安装成功的标准方法在终端或Python控制台执行import pandas as pd print(pd.__version__)能正常输出版本号比如2.0.3就说明环境OK。没输出或直接报ModuleNotFoundError那就说明pandas没装对位置回到上面检查解释器。1.2 安装后仍然报错的常见原因有一种情况特别坑明明在PyCharm的设置里看到pandas已经安装成功但运行代码还是提示找不到模块。八成是因为PyCharm的项目解释器和你使用pip安装时的Python是两套环境。PyCharm里点击右下角的解释器名称弹出的列表里可以看到当前项目到底用的是哪一个Python解释器然后在终端里执行python -c import sys; print(sys.executable)看一下自己用的是哪一个。两者一致才靠谱。还有兼容性问题需要注意。pandas对Python版本有要求如果你还在用古老的Python 3.6甚至Python 2.7市面上新版pandas2.x系列装不上去。这种情况下pip会尝试下载一个对应当前Python版本的旧版pandas而旧版pandas在部分功能上和新代码有差异。遇到这种情况建议升级Python环境起码3.9以上否则做数据清洗时部分新参数会不生效排查起来很费劲。2. 数据结构创建先搞懂Series和DataFrame再动手2.1 Series是一列带标签的数据很多教程喜欢一上来就堆概念我换一种说法Series在pandas里本质上就是带有索引的一维数组可以把它理解成一张单列的Excel表格。创建Series最常用的方式是从列表创建import pandas as pd s pd.Series([10, 20, 30, 40]) print(s)输出结果里左边是索引默认0、1、2、3右边是具体的值。如果你想让索引有实际意义比如按日期排列可以显式指定index参数s pd.Series([10, 20, 30, 40], index[周一, 周二, 周三, 周四])这里要注意一个细节index的长度必须和数据的长度一致否则会直接报ValueError: Length of values does not match length of index这是新手经常触发的错误。创建一个Series只需要记住它是一维的、带索引的、可以存任意类型的数据。在头歌的pandas数据结构创建题里常见的考法就是用字典去创建Seriess pd.Series({苹果: 5.5, 香蕉: 3.2, 橘子: 4.8})字典的key自动变成索引value变成数据这比自己手动指定index更方便推荐优先使用。2.2 DataFrame是二维表格的核心DataFrame可以理解成Excel里的一个工作表有行索引也有列索引。日常处理数据时99%的操作都在DataFrame上。最常见的创建方式是从字典创建字典的key变成列名value一般是列表列表的长度必须一致df pd.DataFrame({ 姓名: [张三, 李四, 王五], 年龄: [25, 30, 22], 城市: [北京, 上海, 深圳] })还有几个高频创建方式需要掌握。第一种是从嵌套列表创建适合你手里是一行行数据的情况data [[张三, 25, 北京], [李四, 30, 上海], [王五, 22, 深圳]] df pd.DataFrame(data, columns[姓名, 年龄, 城市])第二种是从numpy数组创建适合用科学计算时把矩阵包装成表格。第三种是从列表套字典的更复杂结构中创建每条记录一个字典columns会自动统一。创建一个dataframe时一定要想清楚你是以“列为主”还是“行为主”这决定了应该用字典套列表、列表套字典还是嵌套列表。为了方便起见我整理了一个Series和DataFrame的关键对比理解了这张表基础题基本就稳了数据结构维度索引概念默认索引创建方式Series一维单一索引0到n-1pd.Series(列表或字典)DataFrame二维行索引列索引0到n-1pd.DataFrame(字典或列表嵌套)Index对象一维特化的索引数组无默认由DataFrame或Series自动生成3. 数据读写Excel和文本文件是日常主力3.1 读取Excel文件的几个关键参数pandas读写Excel文件是数据分析里最常碰到的场景之一毕竟业务侧的数据多数以Excel表格归档。读取函数pd.read_excel()有几个参数你必须要熟练第一个是sheet_name比如一个工作簿里有多个Sheet需要按名称读取df pd.read_excel(销售数据.xlsx, sheet_name2024年7月)如果不指定sheet_name默认只会读取第一个Sheet。sheet_name也可以传入整数0表示第一个Sheet传入列表还能一次读取多个Sheet返回一个字典结构不过新手期先掌握名称读取就够了。第二个是header参数默认值为0表示把第一行当作列名。如果Excel表格上面有两行大标题真正的表头在第三行那就需要设置header2pandas会自动跳过上面两行。反过来如果某个表格没有表头全是纯数据就传headerNone并用names[列1, 列2]手动指定列名否则pandas会用0、1、2这样的数字当列名后续操作非常别扭。第三个高频参数是usecols只读取指定列以节省内存比如usecols[姓名, 年龄]。写出Excel文件的函数是to_excel()有一个参数官方默认True但实践中建议一定要设成False就是index参数df.to_excel(输出结果.xlsx, indexFalse)如果不设indexFalse输出文件里会多出一列从0开始的行索引这在交付给同事或交给老师评测时经常算错误格式。此外多Sheet写出需要借助pd.ExcelWriter比如同时输出两个表格到同一个文件的不同Sheet里。3.2 文本文件读取的核心参数这里说的文本文件主要指CSV和TSV这类用分隔符划分列的文件。read_csv()是读取函数需要注意的坑比Excel多一些。第一个坑是编码问题。df pd.read_csv(订单.csv, encodingutf-8)国内Excel另存的CSV文件默认是GBK编码直接用utf-8读取会报UnicodeDecodeError解决办法是把encoding参数改成gbk。这里我说一个经验值读Excel生成的文件报编码错误优先试gbk读程序生成的CSV优先试utf-8两种都不行再试gb18030这个编码兼容性更强能覆盖绝大多数中文场景。第二个坑是分隔符。默认情况下read_csv默认分隔符是逗号如果遇到制表符分隔的TSV文件就要指定sep\t。有些特殊文件用的是分号或竖线分隔同样要用sep去匹配。第三个坑是skiprows和nrows。skiprows可以跳过文件前面若干行注释或无效信息nrows则限制只读取前N行适合在大文件上先快速预览df_preview pd.read_csv(超大文件.csv, nrows100) # 先读前100行看结构写出文本文件时有一个比Excel更容易踩的坑直接用to_csv(结果.csv)然后拿Excel打开这个文件中文全部变成乱码。这是因为默认编码是utf-8Excel默认不认。解决办法很简单df.to_csv(结果.csv, indexFalse, encodingutf-8-sig)utf-8-sig编码会在文件开头加入一个BOM标记Excel读取时就能正确识别是utf-8编码。这个小细节头歌作业评测里也经常用到输出格式不规范会导致判题失败。4. 数据类型转换与正则表达式预处理的两把利器4.1 用dtypes定位类型问题和astype转换pandas每一列都有数据类型常见的有int64、float64、object字符串为主、datetime64[ns]。查看所有列类型用df.dtypes属性查看单列用df[列名].dtype。数据处理中最常见的类型问题是读进来的数字列变成了object类型。例如Excel里某列有个别单元格是“-”或者“N/A”pandas就会把整列推断成字符串后续做数值计算直接报错。遇到这种情况我惯用的方法是pd.to_numeric配合errors参数df[金额] pd.to_numeric(df[金额], errorscoerce)errorscoerce会把无法转换的内容强制变成NaN能转的数字保留下来。这一步处理完后再去看那列到底有哪些非数字内容用df[金额].isna()去定位。直接使用astype(int)在这种场景下往往直接抛异常因为它在转换时遇到非法值不会跳过所以我不建议对脏数据使用astype做类型转换。但是如果手头的数据是干净的期望把浮点列转成整数列astype就非常好用df[销量] df[销量].astype(int)这里顺带提一个常见坑某列明明显示的是日期形式但用astype转成日期类型会报错。正确做法是用pd.to_datetime()df[下单时间] pd.to_datetime(df[下单时间], format%Y-%m-%d)format参数加上最稳虽然pandas会自动推断但遇到混合格式时会识别出错。日期格式字符串里%Y是四位年份%m是两位月份%d是两位日这些可以对照文档查阅mac和Windows环境下表现一致。4.2 正则表达式在pandas中的应用技巧热搜词里有人把“正则表达式”误打成了“正在表达式”心想既然是高频搜索词那应该不少人在pandas里用正则时遇到困难。正则表达式在pandas里的应用核心是配合str访问器完成三类操作。第一类是筛选匹配模式的行用str.contains()加上正则# 筛选出所有包含手机号联系人 df_mobile df[df[联系方式].str.contains(r^1[3-9]\d{9}$, naFalse)]naFalse的作用是把缺失值当作不匹配来处理否则遇到NaN会直接报错。第二类是提取关键信息用str.extract()把字符串里的部分内容提取为新列# 从订单号中提取两位的年份信息 df[年份] df[订单号].str.extract(r(\d{4}))圆括号部分就是想提取的组。第三类是批量替换用str.replace()注意默认情况下它会按正则去匹配而不是普通的字符串替换所以如果只是想替换逗号这类普通字符最好把正则表达式写成r,而不是裸逗号避免歧义。df[金额] df[金额].str.replace(r[,], , regexTrue)这条命令可以把千分位分隔符和中文逗号一次性清掉是清洗金额字段的好帮手。正则这块我强调一个经验在pandas里写正则时字符串前面务必加r例如r\d这样Python不会把\d解析成转义字符正则规则才能原样传给底层引擎。5. 数据清洗实操从缺失值到重复值一步步处理5.1 缺失值的定位与三种填充思路数据清洗是pandas的看家本领头歌作业里也专门有pandas数据清洗的关卡。第一步永远是定位缺失值df.isnull().sum()isnull()返回一个布尔型DataFramesum()按列统计True的个数一眼就能看出每列缺失多少。isna()和它完全等价哪个顺手用哪个就行。第二步是决定怎么处理。如果你的数据集较大缺失行占比不高直接丢弃df_clean df.dropna()dropna()默认是只要某一行存在任意缺失值就删除整行。如果只关注某些关键列是否存在缺失值要用subset参数指定df_clean df.dropna(subset[姓名, 电话])如果你不想删行而是想把缺失值补上fillna()是主力。常见的三种填法都很实用# 用常数填充 df[备注] df[备注].fillna(无) # 数值列用均值填充 df[年龄] df[年龄].fillna(df[年龄].mean()) # 时间序列用前向填充 df[价格] df[价格].fillna(methodffill)前向填充就是拿上一行的值来填空适合股票价格、库存这类连续变量的场景。填完以后最好重新执行一次df_clean.isnull().sum().sum()确保缺失值清零了再进入下一步。5.2 重复值和异常值的处理套路重复值处理是另一个必考项。通常用duplicated()标记重复行配合drop_duplicates()去重df_no_dup df.drop_duplicates(subset[订单号], keepfirst)这里subset指定判断重复的字段子集只按订单号判断只要订单号相同就视为重复记录。keepfirst表示保留重复行中的第一条这是最常用的配置。如果不指定subset则是必须所有列完全一致才算重复这种要求比较严格实际中用处相对有限。异常值排查我个人习惯先用df.describe()看数值列的分布重点看min、max和均值之间是否有明显不合理的地方。比如人均购买金额的最大值如果显示是999999999那基本可以断定是脏数据。定位到异常值之后最简单的处理方式是用布尔条件把它过滤掉df df[(df[订单金额] 0) (df[订单金额] 100000)]这里注意pandas的逻辑与、逻辑或要用和|不要用Python的and和or这是一个高频报错点。还有一种替换的写法把异常值替换成缺失值再走fillna流程df.loc[df[订单金额] 100000, 订单金额] pd.NA这条命令用的.loc定位加列赋值熟练之后你会发现写复杂逻辑离不开它。6. ewm函数参数详解别只会算平均6.1 什么是指数加权移动平均ewmExponentially Weighted Moving Average函数在pandas官方文档里是有独立条目的热度不低。如果只看字面意思它和rolling().mean()很像都是计算移动平均但区别在于rolling窗口内的每个数据权重相同而ewm会给近期数据更大的权重权重随距离当前时间的远近按指数衰减。简单理解就是“越近的数据越重要”。为什么实际业务里经常用ewm而不是简单移动平均因为最近几天的变化趋势往往比一个月前的数据更能反映当前状态股票均线、销量趋势预测、异常监控这些场景都需要对近期数据更敏感。我举个例子如果有一组连续数值直接用ewm计算不需要像rolling那样设定窗口大小而是通过衰减参数来控制权重分布import pandas as pd s pd.Series([100, 102, 101, 105, 110]) ewm_result s.ewm(span3).mean() print(ewm_result)6.2 ewm核心参数与换算关系ewm函数里最核心的参数是com、span、halflife和alpha它们本质上是同一种东西的四种等价表达方式。alpha是权重衰减因子取值在0到1之间。四个参数的换算关系如下参数传入方式与alpha的换算关系alpha直接指定衰减因子alpha alphaspan指定跨度alpha 2 / (span 1)com指定质心center of massalpha 1 / (1 com)halflife指定半衰期alpha 1 - exp(-ln(2) / halflife)平时用得最多的是span因为它的含义比较好理解跨度越大对历史数据越“宽容”曲线越平滑。比如设置span5相当于在计算近5个周期左右的加权均值。下面这段代码可以把换算过程验证一遍s pd.Series([1, 2, 3, 4, 5]) result_span s.ewm(span3).mean() result_alpha s.ewm(alpha0.5).mean() print(result_span) print(result_alpha)算出来结果完全一致因为span3对应alpha0.5。我自己在实际复盘时习惯用span写起来直观调参时如果发现曲线太跳就把span调大比如从3调到5如果曲线反应太慢就把span调小。另外还有一个容易忽视的参数adjust。adjustTrue默认时ewm在计算时会考虑每个元素的权重修正adjustFalse时直接用递归公式y_t (1 - alpha) * y_{t-1} alpha * x_t。两者的差异在数据序列较短时比较明显长序列下会趋于一致。做算法题时如果结果和平台预期对不上试着切换一下adjust的参数往往就是这里的问题。7. 常见问题与排查技巧实录7.1 高频报错速查表这一节直接把实际项目里踩过的坑整理成表格遇到问题可以先来这里对号入座报错信息常见原因解决思路ModuleNotFoundError: No module named pandas当前解释器环境没安装pandas检查PyCharm解释器在Terminal中确认环境是否激活安装pandasFileNotFoundError文件路径不对或文件不在当前目录使用os.getcwd()查看当前工作目录用绝对路径传入read_csv或read_excelUnicodeDecodeError编码不一致多半是GBK文件用了utf-8读取把encoding切换到gbk或gb18030KeyError: 列名DataFrame里没有这个列先执行df.columns打印所有列名注意全角空格和大小写差异ValueError: Length of values does not match length of index新列的数据长度和DataFrame行数不一致检查创建新列时后面的列表长度如果需要对齐改用df[列] Series类型数据或使用loc定位SettingWithCopyWarning对切片副本做赋值操作在赋值前使用.copy()创建显式副本或改用.loc切片进行赋值MemoryError文件过大一次性载入内存不足用usecols只读必要列或设置nrows分批读取再或者用chunksize分块处理单独说一下SettingWithCopyWarning这个警告特别常见但又不影响程序运行很多人直接忽略。结果某天发现数据根本没改成功回头查才发现是警告在提醒你你操作的可能是DataFrame的临时副本而不是原数据。我的习惯是在做任何子集筛选后立刻加.copy()df_subset df[df[城市] 北京].copy() df_subset[区域] 华北这样一来df_subset就是独立的新DataFrame后续操作完全可控不会再出现修改不生效的诡异问题。7.2 在头歌平台做题时的三个实用提醒很多人在头歌平台上刷pandas基础题有一些平台特有的注意事项值得提一下。第一头歌评测环境里通常已经预装了pandas不需要在代码里写安装命令也不建议写。你只需要关心你的代码逻辑评测时它会在一个干净环境里重新执行。第二题目给定的是一个模板文件文件名和路径以题目的说明为准不要直接用本地路径。比如题目要求读取test.csv本地文件也放在项目根目录那直接写pd.read_csv(test.csv)就行前面不要拼C:\Users\...这种绝对路径评测环境里根本不存在那个路径。第三如果题目要求输出特定的打印格式比如“输出df的行数和列数格式为(行数, 列数)”那就老老实实用print(df.shape)不要自己加无关的说明文字或中文引号。评测系统经常是逐字符比对输出多一个空格都算错。我一般在本地模拟测试时会把自己代码运行后的输出和题目示例输出并排摆在一起按字符逐字检查。df.shape返回的是一个元组格式比如(10, 4)正好符合“行数, 列数”的题设。头歌作业里还经常出现要求“使用pandas读取成绩.xlsx中指定Sheet并输出前几行”这类题此时read_excel的sheet_name和nrows配合使用就很关键。8. 一个综合小练习把上面的内容串起来用光看不练假把式。我在这里用一个综合案例把全流程走一遍场景是有一份CSV文件里面有客户的订单记录包含“订单号”、“客户名”、“金额”、“下单日期”但数据里有缺失值、有重复记录、金额列混入了逗号。需要清洗后按日期排序再输出到Excel文件。import pandas as pd # 1. 读取原始文件 df pd.read_csv(订单列表.csv, encodinggbk) # 2. 查看基本信息和缺失情况 print(df.info()) print(df.isnull().sum()) # 3. 清理金额列去掉逗号并转成数值 df[金额] df[金额].astype(str).str.replace(r,, , regexTrue) df[金额] pd.to_numeric(df[金额], errorscoerce) # 4. 解析日期 df[下单日期] pd.to_datetime(df[下单日期]) # 5. 删除重复订单号 df df.drop_duplicates(subset[订单号], keepfirst) # 6. 删除关键列缺失的行 df df.dropna(subset[订单号, 客户名, 金额]) # 7. 按日期排序 df df.sort_values(下单日期) # 8. 写出Excel去掉行索引 df.to_excel(订单清洗结果.xlsx, indexFalse)这个流程就是我平时处理订单数据的简化版。要先看结构再定位问题再逐项清洗最后输出结果。每一步执行后我都建议打印df.shape确认行数变化比如删完重复项行数从1000变成了980这种变化是预期的心里就有数了。9. 最后再分享一点我的使用习惯pandas的基础内容到这里该讲的都讲了从安装环境、数据结构、文件读写、类型转换、正则配合、数据清洗到ewm参数整条线走下来日常大部分数据处理任务都能应付。我说说自己的习惯吧每次拿到一个新的DataFrame第一件事永远是df.head()配合df.info()先把数据长什么样、每列是什么类型看清楚再决定后面怎么处理。很多人上来就处理结果处理半天发现数据读进来就已经错了。用df.info()还能顺便看到Dtypes和Non-Null Count缺失情况一目了然。另外动手写清洗代码之前我会单独弄一个Excel样例文件在PyCharm里先跑通再转移到大文件上。小样本测试的成本极低但排查问题的效率非常高。如果你有自己常用的数据处理模板慢慢积累下来会发现pandas真正的威力是让你把脏活累活标准化。下次你再看head歌作业或者实际项目的复杂表格就不会再害怕了。
阅读完成 · 觉得有帮助?