Python读取Excel报表内存不足,如何通过指定列和dtype引擎优化降维?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1224个文字,预计阅读时间需要5分钟。
基本原因不是文件太大,而是使用`read_excel`默认将整个表(含隐藏列、空行、样式缓存、共享字符串等)全量填充进内存,再转换为`DataFrame对象。您只想取其中的3列,可以先解析前200列,再筛选。
典型表现:MemoryError 报错堆栈里一定有 openpyxl 或 xlrd 的调用链;任务管理器能看到 Python 进程内存飙升到几 GB 后崩掉。
- openpyxl 引擎对格式支持最全,但内存开销最大,尤其含合并单元格或条件格式时
- xlrd(仅 ≤1.2.0)已停止维护,不支持 .xlsx 新格式,但读纯数据时比 openpyxl 省约 30% 内存
- 使用
engine='odf'或engine='calamine'(需 pip install calamine-python)可跳过 XML 解析层,直接提取原始值,内存占用下降 50%+,但会丢弃所有样式和公式
只读指定列:usecols 参数的三种写法与陷阱
usecols 是最直接的降维手段,但它不是“选哪几列就读哪几列”,而是“先按规则筛列名/列号,再读”。错误用法反而会加重负担。
- 传字符串如
usecols="A,C,E:G":依赖 Excel 列标定位,如果源文件列顺序变动或含空列,极易漏读或错位 - 传整数列表如
usecols=[0, 2, 4, 5, 6]:稳定可靠,但必须数准索引(从 0 开始),且不能跳过首行——它在跳过 header 前就已定位列 - 传列名列表如
usecols=["订单号", "客户名称", "金额"]:最安全,但要求 header 行必须存在且列名完全匹配(区分大小写、空格、不可见字符);若列名含换行或特殊符号,需先用header=0读一行预览
注意:usecols 不影响底层引擎加载行为——openpyxl 仍会解压整个 .xlsx 包,只是 pandas 后续丢弃未选列的数据对象。真正省内存要配合引擎切换。
立即学习“Python免费学习笔记(深入)”;
dtype 指定不是锦上添花,是内存减负刚需
默认情况下,pandas 为每列推断类型:文本列变 object(实际是 Python str 对象指针数组),数字列可能被识别为 float64 即使全是整数。这两种类型内存开销远高于显式声明的 string[pyarrow] 或 int32。
- 文本列统一用
dtype={"客户名": "string[pyarrow]"}:比默认object节省 40%+ 内存,且支持向量化操作 - 整数列强制
int32或int16:避免 pandas 自动升为float64(因空值存在),再用nullable=True支持 pd.NA - 时间列用
datetime64[ns]:比object存 str 快 5 倍,内存少 60% - 禁止使用
dtype=object全局设置——它等于放弃所有类型优化,还拖慢后续计算
实操建议:先用 pd.read_excel(file, nrows=1000) 快速采样,跑 df.dtypes 和 df.memory_usage(deep=True),再反推合理 dtype。
calamine 引擎 + usecols + dtype 组合拳实测效果
这是目前(2026 年)处理 50MB+ Excel 报表最轻量稳定的组合。calamine 不走 openpyxl 的 DOM 树解析,而是用 Rust 直接流式提取单元格原始值,天然规避样式/公式开销。
import pandas as pd df = pd.read_excel( "report_2026Q1.xlsx", engine="calamine", usecols=["订单ID", "下单日期", "实付金额", "省份"], dtype={ "订单ID": "string[pyarrow]", "下单日期": "datetime64[ns]", "实付金额": "float32", "省份": "category" # 枚举型字段用 category 可压缩 70%+ 内存 }, parse_dates=["下单日期"] )
关键点:calamine 不支持 sheet_name 传函数或列表,只接受字符串或整数;若需多 sheet,得循环调用;它也不支持读取密码保护文件——这些限制恰恰是它轻量的代价。
真正容易被忽略的是:即使用了这套组合,如果报表本身含大量空行、冗余工作表或嵌入对象(图片、图表),仍会触发底层解压膨胀。务必先用 Excel 手动删掉无用 sheet、清除空行、另存为“值-only”版本,再交给 Python 处理。
本文共计1224个文字,预计阅读时间需要5分钟。
基本原因不是文件太大,而是使用`read_excel`默认将整个表(含隐藏列、空行、样式缓存、共享字符串等)全量填充进内存,再转换为`DataFrame对象。您只想取其中的3列,可以先解析前200列,再筛选。
典型表现:MemoryError 报错堆栈里一定有 openpyxl 或 xlrd 的调用链;任务管理器能看到 Python 进程内存飙升到几 GB 后崩掉。
- openpyxl 引擎对格式支持最全,但内存开销最大,尤其含合并单元格或条件格式时
- xlrd(仅 ≤1.2.0)已停止维护,不支持 .xlsx 新格式,但读纯数据时比 openpyxl 省约 30% 内存
- 使用
engine='odf'或engine='calamine'(需 pip install calamine-python)可跳过 XML 解析层,直接提取原始值,内存占用下降 50%+,但会丢弃所有样式和公式
只读指定列:usecols 参数的三种写法与陷阱
usecols 是最直接的降维手段,但它不是“选哪几列就读哪几列”,而是“先按规则筛列名/列号,再读”。错误用法反而会加重负担。
- 传字符串如
usecols="A,C,E:G":依赖 Excel 列标定位,如果源文件列顺序变动或含空列,极易漏读或错位 - 传整数列表如
usecols=[0, 2, 4, 5, 6]:稳定可靠,但必须数准索引(从 0 开始),且不能跳过首行——它在跳过 header 前就已定位列 - 传列名列表如
usecols=["订单号", "客户名称", "金额"]:最安全,但要求 header 行必须存在且列名完全匹配(区分大小写、空格、不可见字符);若列名含换行或特殊符号,需先用header=0读一行预览
注意:usecols 不影响底层引擎加载行为——openpyxl 仍会解压整个 .xlsx 包,只是 pandas 后续丢弃未选列的数据对象。真正省内存要配合引擎切换。
立即学习“Python免费学习笔记(深入)”;
dtype 指定不是锦上添花,是内存减负刚需
默认情况下,pandas 为每列推断类型:文本列变 object(实际是 Python str 对象指针数组),数字列可能被识别为 float64 即使全是整数。这两种类型内存开销远高于显式声明的 string[pyarrow] 或 int32。
- 文本列统一用
dtype={"客户名": "string[pyarrow]"}:比默认object节省 40%+ 内存,且支持向量化操作 - 整数列强制
int32或int16:避免 pandas 自动升为float64(因空值存在),再用nullable=True支持 pd.NA - 时间列用
datetime64[ns]:比object存 str 快 5 倍,内存少 60% - 禁止使用
dtype=object全局设置——它等于放弃所有类型优化,还拖慢后续计算
实操建议:先用 pd.read_excel(file, nrows=1000) 快速采样,跑 df.dtypes 和 df.memory_usage(deep=True),再反推合理 dtype。
calamine 引擎 + usecols + dtype 组合拳实测效果
这是目前(2026 年)处理 50MB+ Excel 报表最轻量稳定的组合。calamine 不走 openpyxl 的 DOM 树解析,而是用 Rust 直接流式提取单元格原始值,天然规避样式/公式开销。
import pandas as pd df = pd.read_excel( "report_2026Q1.xlsx", engine="calamine", usecols=["订单ID", "下单日期", "实付金额", "省份"], dtype={ "订单ID": "string[pyarrow]", "下单日期": "datetime64[ns]", "实付金额": "float32", "省份": "category" # 枚举型字段用 category 可压缩 70%+ 内存 }, parse_dates=["下单日期"] )
关键点:calamine 不支持 sheet_name 传函数或列表,只接受字符串或整数;若需多 sheet,得循环调用;它也不支持读取密码保护文件——这些限制恰恰是它轻量的代价。
真正容易被忽略的是:即使用了这套组合,如果报表本身含大量空行、冗余工作表或嵌入对象(图片、图表),仍会触发底层解压膨胀。务必先用 Excel 手动删掉无用 sheet、清除空行、另存为“值-only”版本,再交给 Python 处理。

