拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Polars Excel 读写实战指南:三种解析引擎的原理选型与 xlsxwriter 写出全解

Polars Excel 读写实战指南三种解析引擎的原理选型与 xlsxwriter 写出全解【免费下载链接】polarsExtremely fast Query Engine for DataFrames, written in Rust项目地址: https://gitcode.com/GitHub_Trending/po/polars导读本文围绕 Polars 的 Excel I/O 能力展开覆盖read_excel的 fastexcelcalamine、xlsx2csv、openpyxl 三类解析引擎的安装、选型与底层数据流以及write_excel借助 xlsxwriter 写出多工作表、带格式 Excel 文件的完整用法。读完你将掌握如何为不同 Excel 文件选择正确的解析引擎、如何按工作表名/编号/命名表格读取数据、如何控制列类型推断以及如何用 Polars 生成可直接交付给业务方的格式化工作簿。文中所有结论均可在本仓库源码中逐行验证。一、Excel 支持概览能力边界与性能取舍Polars 是一个以查询引擎为核心的数据处理库Excel 并非其主打的高性能列式存储格式。官方用户指南docs/source/user-guide/io/excel.md开篇就给出明确建议从性能角度出发如果业务允许应优先使用 Parquet、CSV 等格式只有在必须与 Excel 文件生态交互时才使用 Excel 读写。这一建议与 Polars 的整体定位一脉相承——Excel 的 XML/ZIP 容器结构和稀疏单元格模型决定了它很难达到列式格式的解析吞吐。因此理解 Excel 支持的本质是Polars 自身并不包含 Excel 解析器而是通过引擎engine机制委托给外部库完成格式解析再把结果送入 Polars 的列式内存布局。当前仓库中 Excel 能力在 Python 侧的矩阵如下依据 py-polars/pyproject.toml 的 extras 声明能力依赖库对应 extras说明读取.xlsx默认fastexcel 0.9polars[calamine]绑定 Rustcalaminecrate速度最快读取.xlsx备选openpyxl 3.0.0polars[openpyxl]灵活兜底可解析棘手文件读取.xlsx备选xlsx2csv 0.8.0polars[xlsx2csv]先转 CSV 再走 Polars 原生 CSV 读取写出.xlsxxlsxwriterpolars[xlsxwriter]Python 侧write_excel的唯一后端读取.odsfastexcel同 calamineread_ods同样委托给 calamine 引擎Rust 侧写出 Excel——当前不可用详见第六节在 py-polars/pyproject.toml 中还提供了一个聚合 extraexcel [polars[calamine,openpyxl,xlsx2csv,xlsxwriter]]一次性安装全部读写依赖即可。二、读取引擎三选一如何取舍Polars 没有原生 Excel 读取器pl.read_excel会按engine参数把解析工作委托给三类引擎官方指南 docs/source/user-guide/io/excel.md 的 Read 一节对此有详细描述。1. fastexcel / calamine默认且最快的引擎该引擎基于 Rust 的calaminecrate通过 Python 包fastexcel绑定。官方指南称其为远远最快的读取器。其关键优势在于它直接把.xlsx解析为 Apache Arrow 内存表示Polars 可以零拷贝消费这份数据不需要先落成中间文本格式。在源码层面注意一个细微差别官方指南中称它为 fastexcel而 read_excel 的engine参数实际取值是字符串calamine。类型别名定义于 py-polars/src/polars/_typing.pyExcelSpreadsheetEngine: TypeAlias Literal[calamine, openpyxl, xlsx2csv]从函数文档字符串可以看到引擎能力边界calamine 可读取所有主流 Excel 工作簿格式.xlsx、.xlsb、.xls并显著快于其他选项。仓库测试 py-polars/tests/unit/io/test_spreadsheet.py 中也确实用enginecalamine覆盖了.xlsb场景。2. xlsx2csv桥接原生 CSV 管线的引擎这个读取器先把.xlsx工作簿解析成内存中的 CSV再交给 Polars 自己的 CSV 读取器完成建表。它的好处在于CSV 读取阶段可以复用 Polars 高度优化的 CSV 解析与类型推断能力。源码实现在 functions.py引擎先把目标 sheet 用parser.convert(outfilecsv_buffer, sheetname...)写入StringIO再通过read_csv(..., separator,, truncate_ragged_linesTrue)完成解析。正因如此xlsx2csv 引擎的read_options本质上是read_csv的参数——文档字符串对此有明确说明See [read_csv]。默认值设置见 functions.py如skip_empty_linesFalse、skip_hidden_rowsFalse、floatformat%f等。3. openpyxl灵活兜底引擎官方指南指出它通常比 xlsx2csv 慢但对于难以解析的文件可能提供更多灵活性常作为其他引擎失效时的 fallback。源码 functions.py 显示它是通过openpyxl.load_workbook(source, data_onlyTrue)加载工作簿再逐行ws.iter_rows()取值构造 Series 的——纯 Python 逐单元格访问这正是其速度慢的原因。安装与版本门槛$ pip install fastexcel xlsx2csv openpyxl或者按需从 extras 安装推荐版本约束由项目声明$ pip install polars[excel] # 读写全都要 $ pip install polars[calamine] # 只要默认读取引擎 $ pip install polars[xlsxwriter] # 只要写出能力版本约束可查 py-polars/pyproject.toml。此外某些高级读取选项对fastexcel版本有硬性要求低于版本会直接抛出ModuleUpgradeRequiredError见 functions.py功能选项最低fastexcel版本schema_sample_rows采样推断 schema0.9use_columns按列读取0.10.2从bytes/BytesIO读取0.10table_name读取命名表格0.12三、read_excel基础用法与工作表选择以下示例取自本仓库的官方示例源文件 docs/source/src/python/user-guide/io/excel.pyimport polars as pl # 读取工作簿默认读取第一个工作表 df pl.read_excel(docs/assets/data/path.xlsx) # 指定要读取的工作表名称 df pl.read_excel(docs/assets/data/path.xlsx, sheet_nameSales)如果不指定sheet_namePolars 默认读取第一个 sheet。sheet_name与sheet_id从 1 开始的编号是互斥的同时指定会抛出ValueError校验逻辑见 functions.py。核心参数速查表read_excel的完整签名定义在 py-polars/src/polars/io/spreadsheet/functions.py各参数含义与默认值如下参数默认值作用与要点source必填文件路径、URL 或 file-like 对象也支持 glob/路径列表一次读多个工作簿v1.18sheet_idNone默认第 1 张工作表编号0表示读取全部 sheet 并返回{sheetname: DataFrame}字典sheet_nameNone工作表名称可与sheet_id互斥传入列表同样返回字典table_nameNone读取命名表格对象v1.20表名在整个工作簿内唯一enginecalaminecalamine/openpyxl/xlsx2csvv1.0 起默认值由 xlsx2csv 改为 calamineengine_optionsNone传给底层引擎构造器openpyxl 对应load_workbookxlsx2csv 对应Xlsx2csv(...)calamine 不支持read_optionsNone传给引擎的 sheet 读取方法calamine 对应load_sheet_*/load_tablexlsx2csv 对应read_csvopenpyxl 不支持has_headerTrue首行是否为表头False时列名自动生成为column_0、column_1…columnsNone只读部分列支持列名或列索引序列也可传单列名schema_overridesNone指定/覆盖一列或多列的 dtypeinfer_schema_length默认采样行数类型推断扫描的最大行数None表示全表扫描大文件会变慢仅 calamine 与 xlsx2csv 引擎支持include_file_pathsNone把源文件路径作为新列写入结果drop_empty_rowsTrue读取时剔除全空行drop_empty_colsTrue剔除无表头的空列空列判定因引擎而异raise_if_emptyTruesheet 无数据时抛NoDataErrorFalse时返回空 DataFrame多 sheet、命名表格与 glob 批量读取从源码 functions.py 可以确认三类典型的多结果场景# 读取全部工作表返回 {sheet名称: DataFrame} 字典 sheets pl.read_excel(data.xlsx, sheet_id0) # 按名称列表读取多个工作表 sheets pl.read_excel(data.xlsx, sheet_name[Sales, Marketing]) # 读取命名表格表格内数据被正确裁剪 df pl.read_excel(data.xlsx, table_nameSalesTable)一个容易被忽略的语义细节当sheet_name/sheet_id与table_name同时出现时如果指定 sheet 中不存在该命名表格会抛出RuntimeError。另外read_excel也支持传 glob 模式或路径列表一次合并多个工作簿# glob 匹配到的所有工作簿按同名 sheet 纵向拼接 df pl.read_excel(sales_*.xlsx, sheet_name2025)底层_unpack_read_results会把多个工作簿的结果按vertical_relaxed拼接见 functions.py并支持concat行为。结合引擎的实战示例官方文档给出了一个非常有代表性的组合示例源码同样来自 excel.py 所在章节配套的 docstring见 functions.py当 sheet 没有表头、需要跳过空行时用 xlsx2csv 引擎 双层 optionspl.read_excel( sourcetest.xlsx, sheet_id3, # 读第 3 张表 enginexlsx2csv, engine_options{skip_empty_lines: True}, read_options{has_header: False, new_columns: [a, b, c]}, )顶层参数与read_options之间的冲突会被显式拦截例如同时给 calamine 传columns与read_options[use_columns]或同时指定infer_schema_length与read_options[schema_sample_rows]都会触发ParameterCollisionError见 functions.py。类型推断不理想时的两个补救手段doctest 原例# 手动指定列类型并全量扫描推断其余列 df pl.read_excel( sourcetest.xlsx, schema_overrides{dt: pl.Date}, infer_schema_lengthNone, )四、读取的底层原理引擎分派与类型精修read_excel不是简单调用一次第三方库而是完整的解析流水线。从 functions.py 可以梳理出清晰的分层路径预处理_sources()展开 glob、处理~、识别 URL、把文件句柄统一化L54-L81。参数归一化_get_read_options()把顶层的has_header、infer_schema_length、columns翻译成各引擎认可的read_options键并做冲突校验。引擎实例化_initialise_spreadsheet_parser()按engine分支懒加载import_optional对应库并构造 parserL835-L902。逐 sheet 读取解析 sheet 名称列表后为每个 sheet 调用对应读取函数。三个引擎读取函数的数据流差异值得关注calamineL1032-L1187优先走load_sheet_eager拿到 Arrow 数组后from_arrow零拷贝转成 DataFrame注释明确说明eager loading is faster / more memory-efficient, but requires pyarrow若无 pyarrow 则退化为load_sheet。openpyxlL1190-L1299iter_rows逐行取值能识别工作簿中的命名表格对象ws.tables支持totalsRowCount合计行裁剪。xlsx2csvL1302-L1349整表转 CSV 后走read_csv并自动把 CSV 读出的 Boolean 类型转换回 Boolean。读取完成后还有一层类型精修dtype refinementcalamine 引擎可能把整数列读成 float若某 float 列的floor() 自身且非 NaN则回退强转为Int64仅含00:00:00时刻的 datetime 列会被收窄为DateL1160-L1187。这解释了为什么同一份 Excel 用 Polars 读出的类型往往比直接读原始值更干净。测试侧对三引擎的一致性与格式覆盖面做了约束在 py-polars/tests/unit/io/test_spreadsheet.py 中test_read_excel_basic_datatypes对[calamine, openpyxl, xlsx2csv]三个引擎逐一验证基础数据类型与schema_overrides的一致性同文件还覆盖了多 sheettest_read_excel_multiple_worksheets、多工作簿test_read_excel_multiple_workbooks、全部 sheettest_read_excel_all_sheets与.xlsb等场景。五、写出 Excel安装 xlsxwriter 并使用write_excel写入 Excel 需要在额外依赖xlsxwriter$ pip install xlsxwriter官方指南指出Rust 版 Polars 目前没有write_excel等价能力如果一定要从 Rust 写出.xlsx只能借助第三方xlsxwriterRust crate 自行实现。因此本文的写出部分仅针对 Python API。基础写出示例示例来自 docs/source/src/python/user-guide/io/excel.pydf pl.DataFrame({foo: [1, 2, 3], bar: [None, bak, baz]}) df.write_excel(docs/assets/data/path.xlsx) # 指定工作表名称 df.write_excel(docs/assets/data/path.xlsx, worksheetSales)write_excel是DataFrame的方法实现在 py-polars/src/polars/dataframe/frame.py方法返回创建的Workbook对象可继续通过 xlsxwriter 原生 API 补充加工。完整签名含各参数默认值如下df.write_excel( workbook, # 输出路径/Path/BytesIO/已存在 WorkBook worksheetNone, # 目标工作表名默认自动创建/定位空表 positionA1, # 数据写入的起始单元格 table_styleNone, # 命名表格样式如 Table Style Light 16 table_nameNone, column_formatsNone, # 列级格式覆盖 dtype_formatsNone, # 按 dtype 统一格式如 {pl.Date: mm/dd/yyyy} conditional_formatsNone, header_formatNone, column_totalsNone, # 如 {num: average} column_widthsNone, row_totalsNone, row_heightsNone, sparklinesNone, # 迷你图 formulasNone, # 自定义公式列 float_precision3, # 浮点显示精度 include_headerTrue, autofilterTrue, # 自动筛选 autofitFalse, # 是否自动列宽 hidden_columnsNone, hide_gridlinesFalse, sheet_zoomNone, freeze_panesNone, # 冻结窗格 use_zip64False, )生成富格式工作簿官方指南特意强调Polars 可以生成包含多个工作表与复杂格式的富 Excel 文件并建议查看write_excel的 API 文档获取细节。write_excel的 doctest见 frame.py给出了一份可直接改用的组合示例df.write_excel( positionB4, # 从 B4 开始写而不是默认 A1 table_styleTable Style Light 16, # 套用命名表格样式 dtype_formats{pl.Date: mm/dd/yyyy}, # 日期列用美式格式 column_totals{num: average}, # 给 num 列加平均值总计 float_precision6, # 提高浮点精度 autofitTrue, # 自动调整列宽 )关键设计是workbookworksheet可分离可以向同一个已打开的 xlsxwriterWorkbook多次调用write_excel把不同的 DataFrame 写入不同 worksheet、甚至同一 sheet 的不同位置各自套用不同的表格样式与条件格式再配合xlsxwriter原生 API 添加自定义标题。doctest 中正是示范了write the same frame to a named worksheet twice, applying different styles and conditional formatting to each table, adding custom-formatted table titles using explicit xlsxwriter integration的模式。六、写出原理与依赖结构write_excel的逻辑并非直接散落在frame.py而是集中托管在 py-polars/src/polars/io/spreadsheet/_write_utils.py工作簿写入的工具函数层其背后统一使用 xlsxwriter 的Workbook/WorksheetAPI。xlsxwriter 本身即面向写入优化它不加载现有文件内容而是按单元格流式生成 XML因此对巨型 DataFrame 的写出内存占用相对可控配合use_zip64True可以处理超过 4GB 的 Zip 约束。从依赖结构看写入与读取是完全正交的两套依赖树读取侧的 extrascalamine/openpyxl/xlsx2csv与写入侧的xlsxwriter互不依赖只装了polars[calamine]的安装包无法调用write_excel会提示缺少 xlsxwriter。这也是官方选择把两者拆成独立 extras 的原因见 py-polars/pyproject.toml。七、关键仓库文件索引官方用户指南原文docs/source/user-guide/io/excel.md指南配套可运行示例docs/source/src/python/user-guide/io/excel.pyread_excel/read_ods完整实现含全部参数 docstringpy-polars/src/polars/io/spreadsheet/functions.pywrite_excel方法签名与说明py-polars/src/polars/dataframe/frame.py写出辅助工具py-polars/src/polars/io/spreadsheet/_write_utils.py引擎类型别名定义py-polars/src/polars/_typing.py依赖 extras 声明py-polars/pyproject.toml引擎/格式覆盖测试py-polars/tests/unit/io/test_spreadsheet.py八、最佳实践小结结合官方指南与源码可以提炼出几条可直接落地的经验读取优先默认引擎不加engine参数即可享受 calamine 的 Arrow 零拷贝路径处理.xlsx/.xlsb/.xls全格式只有遇到解析异常的文件才按xlsx2csv → openpyxl的顺序尝试兜底。先读一列再扩展对超大 Excel用infer_schema_length限制采样行数先确认 schema必要时用schema_overrides锁列类型避免全量推断拖慢解析。多 sheet 返回结构是字典sheet_id0或sheet_name[...]时返回{sheet名: DataFrame}且所有read_options/schema_overrides是全局的——如需对不同 sheet 施加不同选项官方建议拆成多次调用。写出时善用同一个 Workbook需要多个 sheet 或复杂排版时用 xlsxwriter 的Workbook作为workbook参数连续写入多张表最后统一保存write_excel返回值可直接继续做二次加工。性能敏感场景绕开 ExcelExcel 读写始终存在格式本身的解析开销官方指南明确建议优先 Parquet/CSV——把 Excel 当作数据交换的输入/输出端把高性能分析留在 Polars 的原生格式上。【免费下载链接】polarsExtremely fast Query Engine for DataFrames, written in Rust项目地址: https://gitcode.com/GitHub_Trending/po/polars创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门