問題描述
使用 Pandas 的 read_excel
方法讀取一個 16 萬行的 Excel 文件報 AssertionError
錯誤:
"/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
背后原理
Excel 文件有兩種默認格式末盔,在 Excel 2007 以前,使用擴展名為 .xls
格式的文件,這種文件格式是一種特定的二進制格式恨憎,最多支持 65,536 行(在 Excel 97 之前支持的最大行數(shù)是 16,384)蔼啦,256 列表格豪治。從 Excel 2007 版開始局齿,默認采用了基于 XML 的新的文件格式 .xlsx
养铸,支持的表格行數(shù)達到了 1,048,576饭庞,列數(shù)達到了 16,384戒悠。需要注意的是,將 .xlsx
格式的文件轉(zhuǎn)換為 .xls
格式的文件時舟山,65,536 行和 256 列之后的數(shù)據(jù)都會被丟棄绸狐。
版本 | 最大行數(shù) | 最大列數(shù) | 文件格式 |
---|---|---|---|
Excel 97 之前 | 16,384 | 256 | .xls |
Excel 97 到 Excel 2003 | 65,536 | 256 | .xls |
Excel 2007 及以后版本 | 1,048,576 | 16,384 | .xlsx |
Pandas 讀取 Excel 文件的引擎是 xlrd
,xlrd
在讀取 Excel 文件時累盗,xlrd/xlsx.py
文件的 637 行會對行號做斷言寒矿,判斷行號是否在 0 - 1,048,576(Excel支持的最大行數(shù)) 的范圍內(nèi)。這段代碼是這樣的:
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
代碼會從 Excel 文件中獲取 row_number若债,這個 row_number 是每一行的行號符相,正常文件行號從 1 開始,而出現(xiàn)問題的文件行號從 0 開始蠢琳,當行號為 0啊终,進入 else 語句镜豹,導致越界問題。
解決辦法
除了 xlrd
蓝牲, Pandas 還支持 openpyxl
(0.25 版)逛艰,openpyxl
是一個專門用來操作 .xlsx
格式文件的 Python 庫,和 xlrd
相比它的速度會慢一些搞旭,但是不會碰到上面所說的問題散怖。這是 openpyxl 中 reader/excel.py
文件處理行的代碼:
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镇眷,也不會導致報錯,但這會導致第一行數(shù)據(jù)的缺失翎嫡,需要進行額外處理欠动。
使用 Pandas + openpyxl 讀取 Excel 文件
首先安裝 openpyxl
:
pip install openpyxl
Pandas 的 read_excel 方法中,有 engine
字段惑申,可以指定所使用的處理 Excel 文件的引擎具伍,填入 openpyxl
,再讀取文件就可以了圈驼。
import pandas as pd
df = pd.read_excel('./data.xlsx', engine='openpyxl')
print(len(df)) # 160000
參考文檔
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