探究 Pandas 讀取 Excel 文件報(bào)錯(cuò)問題

問題描述

使用 Pandas 的 read_excel 方法讀取一個(gè) 16 萬行的 Excel 文件報(bào) AssertionError 錯(cuò)誤:

  "/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 文件有兩種默認(rèn)格式,在 Excel 2007 以前,使用擴(kuò)展名為 .xls 格式的文件,這種文件格式是一種特定的二進(jìn)制格式,最多支持 65,536 行(在 Excel 97 之前支持的最大行數(shù)是 16,384),256 列表格。從 Excel 2007 版開始,默認(rèn)采用了基于 XML 的新的文件格式 .xlsx,支持的表格行數(shù)達(dá)到了 1,048,576,列數(shù)達(dá)到了 16,384。需要注意的是,將 .xlsx 格式的文件轉(zhuǎn)換為 .xls 格式的文件時(shí),65,536 行和 256 列之后的數(shù)據(jù)都會(huì)被丟棄。

版本 最大行數(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 文件時(shí),xlrd/xlsx.py 文件的 637 行會(huì)對行號(hào)做斷言,判斷行號(hào)是否在 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

代碼會(huì)從 Excel 文件中獲取 row_number,這個(gè) row_number 是每一行的行號(hào),正常文件行號(hào)從 1 開始,而出現(xiàn)問題的文件行號(hào)從 0 開始,當(dāng)行號(hào)為 0,進(jìn)入 else 語句,導(dǎo)致越界問題。

解決辦法

除了 xlrd, Pandas 還支持 openpyxl(0.25 版),openpyxl 是一個(gè)專門用來操作 .xlsx 格式文件的 Python 庫,和 xlrd 相比它的速度會(huì)慢一些,但是不會(huì)碰到上面所說的問題。這是 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 在處理行時(shí),并沒有對行號(hào)進(jìn)行斷言,即使行號(hào)第一位是 0,也不會(huì)導(dǎo)致報(bào)錯(cuò),但這會(huì)導(dǎo)致第一行數(shù)據(jù)的缺失,需要進(jìn)行額外處理。

使用 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

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容