首页 > 解决方案 > Openpyxl 的 iter_rows 非常慢,即使 read_only=True?

问题描述

我尝试编写一个 Python-3 函数,将 xlsx 文件中的数字数据读取到 numpy 数组中。我通常只想从特定工作表中读取特定区域。这些区域可能很小(十几个单元格)或相当大(5000 x 10,000 很容易)。我对文本几乎不感兴趣,对功能、数字、格式一点也不感兴趣。到目前为止,这是我的方法(我编写的代码仅供我自己使用,因此我不遵循一些/许多约定和 PEP):

def xlsreadOnly(file, rangeName, sheet = 'Sheet1', dataOnly = True, forceNum = False):
    from openpyxl import load_workbook
    from openpyxl.utils.cell import coordinate_from_string, column_index_from_string
    from numpy import empty, nan
    import io

    with open(file, 'rb') as f:
        in_mem_file = io.BytesIO(f.read())

    wb = load_workbook(filename = in_mem_file, read_only = True, data_only = dataOnly)
    ws = wb[sheet]

    # find the indeces of left-upper and right-lower cells
    areal = rangeName
    w = areal.find(":")
    lu = coordinate_from_string(areal[0:w])
    luR = lu[1]
    luC = column_index_from_string(lu[0])
    rl = coordinate_from_string(areal[w+1:])
    rlR = rl[1]
    rlC = column_index_from_string(rl[0])
    # initialize variable raw 
    raw = empty([rlR-luR+1, rlC-luC+1], dtype = 'object')
            
    ctor = 0
    # iterate over the rows from left-upper to right-lower cell
    for row in ws.iter_rows(min_row=luR, max_row=rlR, min_col=luC, max_col=rlC, values_only=True):
        raw[ctor, :] = np.array(row)
        ctor += 1
    
    return raw

我使用 an in_mem_file,因为它在早期版本中加快了该功能。工作簿加载为read_only,感兴趣的区域可分段为左上排 ( luR)、右下排 ( lrR) 等。该变量raw预先以适当的大小初始化,因此没有append.

有趣的部分似乎是循环

    for row in ws.iter_rows(min_row=luR, max_row=rlR, min_col=luC, max_col=rlC, values_only=True):

我读取的工作表大小为 2535 x 4763。如果我读取大小为 100 x 4763 的区域,则该函数需要大约 4.2 秒(i5-9600、3.7GHz、16GB RAM、SSD),这听起来对我来说太长了. 如果我将区域缩小到 100 x 3,仍然需要 4.0 秒(是的,对于 300 个单元格!)。看起来好像列数实际上是无关紧要的。但是,时间几乎与行数呈线性关系,因此将区域增加到 500 x 4763 大约需要 22 秒。读取整个文件需要相应的时间。

删除转换为 numpy 数组raw[ctor, :] = np.array(row)几乎不会增加计算时间。

我真的认为我错过了一些非常明显的东西,但是在搜索了几天之后,我仍然没有看到它!预先真诚地感谢您指出我的错误。

编辑:@Charlie Clark,你的评论是 100% 正确的,代码不是很容易阅读,并且有一些不必要的代码。我做了一些改变,希望现在更好。我还在必要时更新了文本。我忘了提到从一个小工作表中读取相同的 100x3 区域只需几毫秒。所以问题似乎出在(我的理解)iter_rows()for循环中。

标签: pythonnumpyopenpyxl

解决方案


推荐阅读