十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

pandas 1.3.2实战指南:数据清洗、Excel读写与性能优化避坑手册

pandas 1.3.2实战指南:数据清洗、Excel读写与性能优化避坑手册 简介Pandas 1.3.2 是 Python 数据分析生态中的经典稳定版本这份 PDF 是该版本的官方英文文档面向希望系统学习 Pandas 的初学者、数据分析和数据科学从业者。压缩包内只有 1 个 PDF整体大小约 14.01MB适合离线保存和关键词检索。文档主体分为入门指南和用户指南两大部分入门部分介绍安装方式、包体概览、快速上手并与电子表格、R、SQL 等工具做了对比用户指南则对对象创建、数据查看与选择、缺失值处理、算术运算、数据合并、分组聚合、数据重塑、时间序列、分类数据和绘图等核心主题展开说明基本覆盖日常工作所需的全部关键操作。该资源目前已有 157 人学习口碑和实用性较好。对想要摆脱零散文章、建立完整知识体系的数据分析入门者来说这份官方文档手册无疑是一份高价值的工具书。 pandas 1.3.2 这个版本号乍一看平平无奇但它恰恰卡在 pandas 生态的一个关键节点上。我最近翻到一份命名为 “pandas1.3.2.pdf” 的资料顺手又把这版本文档翻了一遍发现很多人要么还在用着 1.1 甚至 0.25 的老写法要么已经跳到 2.x 却被 API 变更折腾得够呛。结合这段时间在数据清洗、Excel 读写、类型转换这些高频场景里的实操我觉得有必要把 1.3.2 这个版本相关的实战经验好好捋一捋——尤其是那些文档里写了但你没注意、或者压根没写但你一定会踩的坑。这篇文章不是文档翻译也不是入门科普而是围绕 pandas 1.3.2 在实际项目里的真实使用经验。内容覆盖环境搭建、Excel 读写、数据清洗、类型转换、性能优化这几个最常被搜索的方向所有代码我都用 1.3.2 实测验证过。如果你是那种“明明按教程写了却总是报错”的读者这篇文章大概率能帮你少走不少弯路。1. 为什么我盯着 1.3.2 这个版本不放先聊点背景。pandas 1.3.2 发布于 2021 年 8 月属于 1.3.x 系列的小版本迭代。放在当时看它就是个常规 bugfix 版本但放在整个 pandas 版本演进史里它占了一个很有意思的位置这是 Copy-on-Write 机制大改之前的最后一个稳定系列之一也是很多第三方库比如 Excel 读写引擎、金融数据接口明确声明兼容的版本区间。为什么我会特别在意这个版本因为在实际工作中我见过太多“pandas 版本不一致导致生产环境行为不同”的案例。举个例子df.drop()这个操作在 1.3.2 里默认inplaceFalse返回一个新对象但如果你从老项目里继承了一段代码里面写着df.drop(columns[a], inplaceTrue)在 1.3.2 上跑没有问题可一旦升到 2.0 以上部分链式赋值的警告会从 Warning 变成 FutureWarning 甚至直接报错。版本之间的行为差异往往比功能缺失更折磨人。1.3.2 还有一个隐藏优势它对 Python 3.7~3.9 的支持非常稳定而这段时间恰好是很多企业内部数据环境的 Python 版本区间。如果你所在的项目组还在用 Python 3.8 跑数据分析任务直接装 pandas 2.x 可能连依赖都解析不过去但 pandas 1.3.2 几乎不会遇到这种兼容性噩梦。另外从学习角度来说1.3.2 的 API 设计比老版本更规范又没有引入 2.x 那些复杂的新机制比如 nullable dtypes 的全面默认化、Copy-on-Write 的默认开启。对初学者来讲1.3.2 是一个“学了不会白学踩坑不会太深”的版本。这也是为什么很多网课、书籍、甚至部分高校教材到现在仍然以 1.3.x 系列作为演示环境。提示如果你在 PyCharm 里新建项目默认可能给你装到 pandas 2.x。如果你想复现我下面的所有代码建议手动指定版本安装pandas1.3.2。2. 环境搭建里最容易翻车的三个细节关于 pandas 安装网上一搜一大把教程但大多数教程只告诉你“pip install pandas”就完事了完全没提版本锁定、依赖冲突和 IDE 解释器路径的问题。这就是很多人“明明按步骤做了却报 ModuleNotFoundError”的根本原因。2.1 指定版本安装的正确姿势先看最基本的安装命令pip install pandas1.3.2如果你用的是 conda则是conda install pandas1.3.2这里有个细节直接用pip install pandas装到的通常是最新版。假如你的项目里其他依赖比如 numpy、openpyxl已经升级到了和 pandas 1.3.2 不兼容的版本pip 会在解析依赖时自动升级或降级相关包。为了避免它“好心办坏事”建议用约束文件锁定核心依赖pip install pandas1.3.2 numpy1.20.0,1.22.0为什么要锁 numpy因为 pandas 1.3.2 在编译和运行层面和 numpy 的 ABI二进制接口绑定很紧。numpy 1.22 之后对 Python 3.10 的适配更好但如果你在 Python 3.8/3.9 环境下装了 numpy 1.24 甚至更高版本pandas 1.3.2 可能会在导入时直接抛出类似于_ARRAY_API not found的错误。这不是 pandas 本身的问题而是 numpy 2.x 移除了旧版 API 导致的兼容性破裂。2.2 PyCharm 里装包总失败多半是解释器选错了“pycharm怎么安装pandas包”这个搜索词常年霸榜我估计有 80% 的人卡在同一个地方项目解释器Project Interpreter选成了系统全局 Python或者选了虚拟环境但 pip 指向不对。在 PyCharm 里正确操作是File → Settings → Project → Python Interpreter → 点齿轮 → Add → 选择 Virtualenv Environment → New environmentBase interpreter 选你系统里的 Python 3.8 或 3.9。创建完虚拟环境之后再点下方的“”搜索 pandas然后在右侧版本下拉框手动选择 1.3.2。还有一个容易被忽略的点PyCharm 安装包时如果网络不稳定会直接失败。这时候不要反复重试而是换国内镜像源pip install pandas1.3.2 -i https://pypi.tuna.tsinghua.edu.cn/simple2.3 验证安装是否真的成功了很多教程教你import pandas as pd不报错就算成功但我觉得这不够。你要确认当前运行时用的到底是哪个 pandas、哪个路径下的 pandasimport pandas as pd print(pd.__version__) # 1.3.2 print(pd.__file__) # 确认 import 的是虚拟环境里的那个这两个输出非常重要。尤其是__file__它能帮你定位“明明 pip list 里有 pandas为什么 import 还是报错”的问题——大概率是当前 Python 解释器路径不对import 到了 site-packages 里的另一个 pandas。3. Excel 读写远比你想的更有讲究搜索热词里“pandas读取excel文件”和“pandas读写excel文件”占了很大比重这确实是职场里最高频的需求之一。但大多数教程只展示了最简单的pd.read_excel(xxx.xlsx)一旦遇到多 sheet、指定数据类型、保留公式、超大文件就各种翻车。3.1 read_excel 的隐藏参数pandas 1.3.2 读取 Excel 依赖两个底层引擎openpyxl支持 .xlsx和xlrd对旧版 .xls 支持更好。1.3.2 默认对 .xlsx 文件使用 openpyxl但有个常见报错是ImportError: Missing optional dependency openpyxl——因为 pandas 不会默认安装这个依赖你需要手动装pip install openpyxl官网文档没强调的是read_excel里的dtype参数在实战中能救命。Excel 里的“001”这类编号默认会被读成数值 1丢掉了前导零。解决方式是import pandas as pd df pd.read_excel(员工信息.xlsx, sheet_nameSheet1, dtype{员工编号: str})同理日期列有时候会被读成 datetime64有时候又变成字符串统一用parse_dates[入职日期]来控制更靠谱。还有usecols参数也很实用。一个大 Excel 有几十列你只需要其中三列直接pd.read_excel(xxx.xlsx, usecols[姓名,部门,薪资])就可以减少内存占用和读取时间。在 1.3.2 里usecols 支持传列名列表、列索引列表甚至支持 Excel 的列区间写法usecolsA:C非常灵活。3.2 写出 Excel 时的格式控制写入方面df.to_excel(output.xlsx, indexFalse)是最基础的操作。但如果你希望把多个 DataFrame 写到同一个 Excel 的不同 sheet 里很多人会写多个to_excel调用——结果发现后面的覆盖了前面的。正确做法是借助ExcelWriterwith pd.ExcelWriter(多表输出.xlsx, engineopenpyxl) as writer: df_sales.to_excel(writer, sheet_name销售表, indexFalse) df_stock.to_excel(writer, sheet_name库存表, indexFalse)这里有个 1.3.2 特有的小坑如果不指定engineopenpyxl而文件已存在且你传的路径后缀是 .xlsxpandas 会默认使用 openpyxl但如果你在ExcelWriter里加modea追加模式去修改已有文件必须明确指定引擎否则可能报错说找不到 writer 对象。另外to_excel时如果你不想把索引列写进去千万记得indexFalse。我见过很多人导出报表后Excel 第一列多出一列无意义的行号看起来特别业余其实就是忘了这个参数。4. 数据清洗实战从脏数据到干净表的完整链路“pandas数据清洗实战”和“头歌pandas数据预处理”这两个热词反映出一个真实需求考试、作业、面试题里经常要求你用 pandas 处理脏数据。但在实际工作中数据清洗的难点不是“不会用函数”而是“不知道按什么顺序处理”。我简单列一条经过验证的清洗链路读取 → 预览 → 去重 → 处理缺失 → 类型转换 → 格式规整。4.1 去重别只盯着 drop_duplicatesdrop_duplicates()是去重的核心函数但它默认是“整行所有列都相同才去重”。实际业务里你可能只想根据“用户ID”或“订单号”去重df.drop_duplicates(subset[订单号], keepfirst, inplaceTrue)keep参数控制保留哪一行first保留第一条last保留最后一条False是删除所有重复行。这个参数在 1.3.2 里非常稳定但要提醒一下如果你后续还要用索引去关联其他表去重后最好重置一下索引df df.drop_duplicates(subset[订单号]).reset_index(dropTrue)不重置索引的话行号会出现跳跃后面做df.loc[100]可能会定位到根本不是第 100 行的数据。4.2 缺失值处理的三个层级处理缺失值大部分教程只会教你dropna()和fillna()。但现实中要分三层看第一层先搞清楚缺失值长什么样。pandas 1.3.2 里df.info()可以查看每列非空值数量配合df.isnull().sum()可以快速定位哪些列缺得最凶。第二层区分“真缺失”和“假缺失”。Excel 里经常有空字符串读进来之后不是 NaN而是空字符串。这种数据isnull()识别不出来但df[列名].value_counts()会显示一个空串的计数。遇到这种情况要先统一替换df[备注] df[备注].replace(, pd.NA)第三层选择填充策略。数值列用中位数填充比均值更稳健因为均值容易被极端值拉偏分类型列用众数填充时间序列用前向填充methodffill更合理。1.3.2 里fillna(methodffill)是合规写法但如果你升到 2.x这个方法参数会被废弃改成df.ffill()。这也是我前面说“1.3.2 学了不白学但要注意版本差异”的原因之一。4.3 真实案例订单数据清洗的完整顺序假设你拿到一张订单表包含订单号、用户ID、商品名称、下单时间、金额、备注六列。完整清洗流程如下# 1. 读取时直接指定类型 df pd.read_excel(order.xlsx, dtype{订单号: str, 用户ID: str}) # 2. 去除完全重复的行 df df.drop_duplicates().reset_index(dropTrue) # 3. 统一金额列去掉货币符号转成浮点数 df[金额] df[金额].astype(str).str.replace(¥, ).astype(float) # 4. 下单时间转成 datetime非法值置为 NaT df[下单时间] pd.to_datetime(df[下单时间], errorscoerce) # 5. 缺失金额的用中位数填充缺失备注的填无 df[金额] df[金额].fillna(df[金额].median()) df[备注] df[备注].fillna(无) # 6. 按下单时间排序重新设置索引 df df.sort_values(下单时间).reset_index(dropTrue)这里每一步都有明确意图不是乱调 API。errorscoerce尤其值得记住它能把无法解析的日期变成 NaT而不是直接让整个程序崩掉。等你处理真实业务数据时会发现这个参数比try...except好用太多。5. 数据类型转换与 drop 操作的高频翻车点热词里有“pandas drop”和“pandas 数据类型转换”这俩其实是平时被提问最多的两个功能。因为看起来简单反而更容易出问题。5.1 astype 和 to_numeric 怎么选数据类型转换最常用的是astype()但它有一个脾气如果你想把一列字符串 “123”、“456”、“abc” 转成整数它会直接抛ValueError。这时候就要用pd.to_numeric()加上errorscoercedf[数量] pd.to_numeric(df[数量], errorscoerce)无法转换的值会变成 NaN不会被中断。之后再决定是填充默认值还是删除那些行。另外1.3.2 里astype还支持一种更简洁的写法把整个 DataFrame 的多列一次性转换。df df.astype({年龄: int, 薪资: float})这个写法在列特别多时非常省代码。官方文档里把它叫做 dict-style 转换我觉得是 1.3.x 系列最实用的增强之一。5.2 drop 的两种用法和 inplace 之争drop最常见的用法是按列名删列df df.drop(columns[备注, 内部标记])或者按行索引删行df df.drop(index[0, 2, 5])这里有一个从老版本延续下来的争议点inplaceTrue到底能不能用我的建议是能不用就尽量不用。inplaceTrue的语义是原地修改但 pandas 1.3.2 里很多操作即使设了inplaceTrue内部仍然是先创建新对象再赋值并没有真正节省内存。更关键的是如果你想链式调用比如先删列再删行inplaceTrue就没法写成一行。习惯用返回新对象的方式代码可读性更好也更利于调试。5.3 一个容易忽略的引用陷阱很多人不知道df.drop(columns列名)默认返回一个视图还是副本。在 pandas 1.3.2 里这部分行为在某些边界情况下并不完全一致。为了避免“修改副本导致原表也跟着变”的问题建议在需要操作副本时显式调用.copy()df_clean df.drop(columns[备注]).copy() df_clean.loc[0, 金额] 9999如果不加.copy()在某些情况下 pandas 可能只返回了一个视图你改动df_clean原表df也会被连带修改。这个坑非常隐蔽排查起来极其耗时提前用.copy()可以彻底避开。6. 当数据量变大性能优化与并发读取的实操方案搜索热词里有一段很典型的代码片段import time / import random / import requests / from concurrent.futures import ThreadPoolExecutor / as_completed还提到了“获取金融数据”。这说明很多人已经不满足于单机小数据量的处理而是想用 pandas 配合并发去抓取外部接口、构造 DataFrame。这里我分享一下 1.3.2 环境下实测可行的方案。6.1 用 ThreadPoolExecutor 并发抓数假设你要从某个接口批量拉取多只股票的历史行情单线程循环请求非常慢。用ThreadPoolExecutor并发请求可以大幅缩短耗时import time import random import requests import pandas as pd from concurrent.futures import ThreadPoolExecutor, as_completed def fetch_stock_data(stock_code): url fhttps://example.com/api/stock/{stock_code} resp requests.get(url, timeout10) data resp.json() # 这里把 JSON 转成 DataFrame 的行 return {code: stock_code, price: data.get(close), ts: data.get(timestamp)} stock_list [600000, 600001, 600002, 600003, 600004] results [] with ThreadPoolExecutor(max_workers5) as executor: future_map {executor.submit(fetch_stock_data, code): code for code in stock_list} for future in as_completed(future_map): try: result future.result() results.append(result) except Exception as e: print(f请求失败: {future_map[future]}, error: {e}) df pd.DataFrame(results)这里有个关键经验不要在主线程里挨个future.result()那样并发效果会退化回串行。应该先提交所有任务再用as_completed按完成顺序取结果。每个请求之间可以加一个极小的随机延时避免目标接口瞬时压力过大。6.2 read_csv 与 read_excel 的大文件加速技巧如果你手里的 CSV 动辄几个 GB直接用pd.read_csv(data.csv)经常会内存爆炸。1.3.2 里有几个参数组合非常实用df pd.read_csv(large.csv, dtype{用户ID: str}, parse_dates[时间], usecols[用户ID, 时间, 金额], nrows100000) # 先读 10 万行试水nrows这个参数特别适合“先抽样看看数据结构”的场景。等你确认列类型没问题再放开全部读取。另外如果你只是想快速做一个聚合统计可以配合chunksize分块读取total 0 for chunk in pd.read_csv(large.csv, chunksize50000, usecols[金额]): total chunk[金额].sum() print(total)这一招能让你在 1GB 数据集上只占几百 MB 内存完成求和优势非常明显。6.3 大数据量下尽量避免 apply 的性能自救pandas 的apply很方便但性能一言难尽。在 1.3.2 里如果对一列字符串做清洗操作用向量化的str方法通常比apply快一个数量级# 慢 df[清洗后] df[原始].apply(lambda x: x.strip().lower()) # 快 df[清洗后] df[原始].str.strip().str.lower()数据量少的时候区别不明显几百万行时差距就是几分钟和几秒钟的区别。还有一个容易被忽略的category类型如果某列是有限枚举值比如“省份”列只有 34 个值把它转成category可以节省内存并提升 groupby 效率df[省份] df[省份].astype(category)这些优化在 1.3.2 里都支持而且不会像 2.x 那样引入太多新的 dtype 规则上手更简单。7. 我踩过的版本坑与收尾建议写到这里我想分享几个实际踩过的坑帮大家提前避雷。第一个坑是 pandas 1.3.2 与 openpyxl 的版本搭配。当时我处理一个带格式的 Excel 模板to_excel写完后格式全丢了。后来发现 openpyxl 2.6 和 3.0 的行为差异很大pandas 1.3.2 官方要求的是 openpyxl3.0.0如果你环境里残留了旧版 openpyxl写出的文件很可能打不开。第二个坑是pd.to_datetime的时区问题。1.3.2 里如果你读取的时间字符串带 UTC 后缀生成的 Series 是带时区信息的 datetime64[ns, UTC]而 Excel 写入时可能因为时区不一致导致日期偏移 8 小时。解决办法是在 to_datetime 之后统一dt.tz_localize(None)去掉时区信息。第三个坑跟内存有关。1.3.2 在处理包含大量字符串的 DataFrame 时内存占用会比数值型数据高很多。如果你发现处理中途电脑卡死优先检查是不是有字符串列忘记转成 category 了。我在实际使用中发现pandas 1.3.2 虽然不是一个“版本越新越好”的选择但它确实是一个“学到手能立刻用、用起来不闹心”的版本。如果你现在还停留在pd.read_csv和df.head()的阶段建议从这篇文章里的数据清洗链路和类型转换策略开始练手如果你已经在做并发抓数和性能优化那更要稳住版本把每个函数的行为边界摸清楚。最后再分享一个小技巧遇到 pandas 报错不要只看最后一行把完整的 Traceback 展开看到底是在什么版本、什么操作下触发的。很多时候不是你的代码写错了而是版本行为变了。pandas 1.3.2 的文档和源码都还比较容易读真有疑问直接翻源码反而最快。本文还有配套的精品资源点击获取
返回列表