【问题标题】:How to open excel file fast in Python?如何在 Python 中快速打开 excel 文件?
【发布时间】:2018-08-15 06:08:04
【问题描述】:

我现在使用PyExcelerator 来读取 excel 文件,但它非常很慢。由于我总是需要打开超过 100MB 的 excel 文件,所以我只加载一个文件需要二十多分钟。

我需要的功能是:

  • 打开 Excel 文件,选择特定表格,然后将它们加载到字典或列表对象中。
  • 有时:选择特定列并仅加载具有特定值的特定列的整行。
  • 读取受密码保护的 Excel 文件。

而我现在使用的代码是:

book = pyExcelerator.parse_xls(filepath)
parsed_dictionary = defaultdict(lambda: '', book[0][1])
number_of_columns = 44
result_list = []
number_of_rows = 500000
for i in range(0, number_of_rows):
    ok = False
    result_list.append([])
    for h in range(0, number_of_columns):
        item = parsed_dictionary[i,h]
        if type(item) is StringType or type(item) is UnicodeType:
            item = item.replace("\t","").strip()
        result_list[i].append(item)
        if item != '':
            ok = True
    if not ok:
        break

有什么建议吗?

【问题讨论】:

  • 你试过其他库了吗? (我没有这方面的技术知识,我只是感兴趣)
  • 是的,我试过了,但是那些总是没有写 xls 的功能。阅读大 xls 后,我还必须进行一些计算并将结果保存到小 xls 中。
  • @FelixYan:很高兴知道,希望你能得到一些好的答案!
  • 对于写作部分,你可以使用xlwt,或者,如果你只是写值,你可以使用CSV format(可以很容易地导入Excel)。
  • 这 20 分钟是否仅包括 pyExcelerator.parse_xls() 还是您计算自己的后续代码?

标签: python excel


【解决方案1】:

pyExcelerator 似乎没有得到维护。要编写 xls 文件,请使用 xlwt,它是 pyExcelerator 的一个分支,具有错误修复和许多增强功能。 pyExcelerator 的(非常基本的)xls 读取功能已从 xlwt 中根除。要读取 xls 文件,请使用 xlrd。

如果加载 100MB xls 文件需要 20 分钟,您必须使用以下一种或多种:速度较慢的计算机、可用内存很少的计算机或较旧版本的 Python。

pyExcelerator 和 xlrd 都不读取受密码保护的文件。

这里是a link that covers xlrd and xlwt

免责声明:我是 xlrd 的作者和 xlwt 的维护者。

【讨论】:

  • 谢谢你,我会试试这两个。事实上,我正在使用 AMD Phenom II X4 945 和 4G RAM,其中 2G 或更多是免费的、SSD 和 x86_64 Linux 操作系统中的 Python 2.7。其他地方的阅读过程可能会更慢。
【解决方案2】:

xlrd 非常适合读取文件,xlwt 非常适合写入。根据我的经验,两者都优于 pyExcelerator。

【讨论】:

    【解决方案3】:

    您可以尝试在单个语句中将列表预分配为其大小,而不是像这样一次附加一个项目:(一个大的内存分配应该比许多小的内存分配更快)

    book = pyExcelerator.parse_xls(filepath)
    parsed_dictionary = defaultdict(lambda: '', book[0][1])
    number_of_columns = 44
    number_of_rows = 500000
    result_list = [] * number_of_rows 
    for i in range(0, number_of_rows):
        ok = False
        #result_list.append([])
        for h in range(0, number_of_columns):
            item = parsed_dictionary[i,h]
            if type(item) is StringType or type(item) is UnicodeType:
                item = item.replace("\t","").strip()
            result_list[i].append(item)
            if item != '':
                ok = True
        if not ok:
            break
    

    如果这样做可以显着提高性能,您还可以尝试为每个列表项预先分配列数,然后按索引分配它们,而不是一次附加一个值。这是一个 sn-p,它在单个语句中创建一个 10x10 的二维列表,初始值为 0:

    L = [[0] * 10 for i in range(10)]
    

    如此折叠到您的代码中,它可能会像这样工作:

    book = pyExcelerator.parse_xls(filepath)
    parsed_dictionary = defaultdict(lambda: '', book[0][1])
    number_of_columns = 44
    number_of_rows = 500000
    result_list = [[''] * number_of_rows for x in range(number_of_columns)]
    for i in range(0, number_of_rows):
        ok = False
        #result_list.append([])
        for h in range(0, number_of_columns):
            item = parsed_dictionary[i,h]
            if type(item) is StringType or type(item) is UnicodeType:
                item = item.replace("\t","").strip()
            result_list[i,h] = item
            if item != '':
                ok = True
        if not ok:
            break
    

    【讨论】:

    • 问题是,我不知道xls文件的大小。所以number_of_rows 变量只是我猜的最大尺寸。那么……预分配会占用太多内存吗?
    • 你知道列数但不知道行数?列数是否固定?无论如何,这可能值得一试。用两种不同的算法对子集进行性能比较,比如 1000 行。您可以从那里进行测量。
    • 谢谢。当然值得一试:P。你是对的,列数是固定的,我不知道行数。
    • 您可以通过迭代直到item != '' 并增加一个计数器来确定行数。这将是分配之前的一个额外步骤,但这将确定上限。
    • 您可以做的另一件事是使用性能监控应用程序查看您的流程。注意内存增长,尤其是页面错误。页面错误会扼杀像您这样的嵌套循环,而预分配是解决它们的好方法。
    【解决方案4】:

    与您的问题无关:如果您尝试检查是否没有任何列是空字符串,那么您最初设置 ok = True,然后在内部循环中执行此操作 (@987654322 @)。另外,您可以使用isinstance(item, basestring) 来测试变量是否为字符串。

    修订版

    for i in range(0, number_of_rows):
        ok = True
        result_list.append([])
        for h in range(0, number_of_columns):
            item = parsed_dictionary[i,h]
            if isinstance(item, basestring):
                item = item.replace("\t","").strip()
            result_list[i].append(item)
            ok = ok and item != ''
    
        if not ok:
            break
    

    【讨论】:

    • 谢谢!这么长时间以来,我对type(item) is StringType or type(item) is UnicodeType 的事情感到不舒服!但我不认为ok = ok and item != '' 之后易于阅读,只是有点hacky :)
    【解决方案5】:

    我最近建立了一个可能感兴趣的库:https://github.com/ktr/sxl。它本质上尝试像 Python 处理普通文件一样“流式传输” Excel 文件,因此当您只需要数据子集(尤其是在文件开头附近)时,它的速度非常快。

    【讨论】:

      猜你喜欢
      • 2013-10-17
      • 2011-03-15
      • 2012-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-02
      • 2013-08-12
      • 1970-01-01
      相关资源
      最近更新 更多