前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >分析 Pandas 源码,解决读取 Excel 报错问题

分析 Pandas 源码,解决读取 Excel 报错问题

作者头像
simpleapples
发布2020-05-12 13:16:26
2K0
发布2020-05-12 13:16:26
举报
文章被收录于专栏:Python私房菜Python私房菜

01

问题描述

使用 Pandas 的 read_excel 方法读取一个 16 万行的 Excel 文件报 AssertionError 错误:

代码语言:javascript
复制
  "/Users/XXX/excel_test/venv/lib/python3.7/site-packages/xlrd/xlsx.py", line 637, in do_row
    assert 0 <= self.rowx < X12_MAX_ROWS
AssertionError

02

背后原理

Excel 文件有两种默认格式,在 Excel 2007 以前,使用扩展名为 .xls 格式的文件,这种文件格式是一种特定的二进制格式,最多支持 65,536 行(在 Excel 97 之前支持的最大行数是 16,384),256 列表格。从 Excel 2007 版开始,默认采用了基于 XML 的新的文件格式 .xlsx,支持的表格行数达到了 1,048,576,列数达到了 16,384。需要注意的是,将 .xlsx 格式的文件转换为 .xls 格式的文件时,65,536 行和 256 列之后的数据都会被丢弃。

Pandas 读取 Excel 文件的引擎是 xlrd,xlrd 在读取 Excel 文件时,xlrd/xlsx.py(https://github.com/python-excel/xlrd/blob/master/xlrd/xlsx.py) 文件的 637 行会对行号做断言,判断行号是否在 0 - 1,048,576(Excel支持的最大行数) 的范围内。这段代码是这样的:

代码语言:javascript
复制
row_number = row_elem.get('r')
if row_number is None: # Yes, it's optional.
    self.rowx += 1
    explicit_row_number = 0
    if self.verbosity and not self.warned_no_row_num:
        self.dumpout("no row number; assuming rowx=%d", self.rowx)
        self.warned_no_row_num = 1
else:
    self.rowx = row_number - 1
    explicit_row_number = 1
assert 0 <= self.rowx < X12_MAX_ROWS

03

解决办法

除了 xlrd, Pandas 还支持 openpyxl(0.25 版),openpyxl 是一个专门用来操作 .xlsx 格式文件的 Python 库,和 xlrd 相比它的速度会慢一些,但是不会碰到上面所说的问题。这是 openpyxl 中 reader/excel.py(https://bitbucket.org/openpyxl/openpyxl/src/default/openpyxl/reader/excel.py) 文件处理行的代码:

代码语言:javascript
复制
def parse_row(self, row):
    attrs = dict(row.attrib)


    if "r" in attrs:
        self.max_row = int(attrs['r'])
    else:
        self.max_row += 1
    keys = set(attrs)
    for key in keys:
        if key.startswith('{'):
            del attrs[key]


    keys = set(attrs)
    if keys != set(['r', 'spans']) and keys != set(['r']):
        # don't create dimension objects unless they have relevant information
        self.row_dimensions[attrs['r']] = attrs


    cells = [self.parse_cell(el) for el in row]
    return self.max_row, cells

openpyxl 在处理行时,并没有对行号进行断言,即使行号第一位是 0,也不会导致报错,但这会导致第一行数据的缺失,需要进行额外处理

04

使用 Pandas + openpyxl 读取 Excel 文件

首先安装 openpyxl:

代码语言:javascript
复制
pip install openpyxl

Pandas 的 read_excel 方法中,有 engine 字段,可以指定所使用的处理 Excel 文件的引擎,填入 openpyxl,再读取文件就可以了。

代码语言:javascript
复制
import pandas as pd

df = pd.read_excel('./data.xlsx', engine='openpyxl')
print(len(df))  # 160000

05

参考文档

https://office-watch.com/2010/excel-a-history-of-rows-and-columns/

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_excel.html

https://github.com/python-excel/xlrd/

https://bitbucket.org/openpyxl/openpyxl/src

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python私房菜 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档