【问题标题】:Speeding Up Excel Data to Pandas将 Excel 数据加速到 Pandas
【发布时间】:2019-11-01 21:50:55
【问题描述】:

我有一段非常简单的代码,其中有一组文件名,我需要打开每个文件名并提取一些数据以供以后操作。

for file in unique_file_names[1:]:
        file_name = rootdir + "/" + str(file)
        test_time = time.clock()    
        try:
            wb_loop = load_workbook(file_name, read_only=True, data_only=True)
            ws_loop = wb_loop["SHEET1"]
            df = pd.DataFrame(ws_loop.values)
            print("Opening Workbook:         ", time.clock()-test_time)

            newarray = np.vstack((newarray, df.loc[4:43,:13].values))
            print("Data Manipulation:         ", time.clock()-test_time)

所以我尝试了几个不同的模块来读取 excel 文件,包括直接使用 pandas.read_excel() 这是最佳方法,设法将打开工作簿的时间缩短到 1.5-2 秒,并且 numpy堆叠大约需要 0.03 秒。

我认为根据索引将数据分配到数组中的第三维可能会更快,但我更专注于加快加载电子表格的时间,有什么建议吗?

编辑:我还创建了一个多线程池来尝试加快速度,但由于某种原因,它开始使用 15Gb 内存并导致我的计算机崩溃

编辑 2:

因此,完成此操作的最快方法是根据接受的答案建议使用 xlrd。我还意识到在循环结束时删除工作簿会更快。最终代码看起来像

for file in unique_file_names[1:]:
        file_name = rootdir + "/" + str(file)
        test_time = time.clock()    
        try:
            wb_loop = xlrd.open_workbook(file_name, on_demand = True)
            ws_loop = wb_loop.sheet_by_name("Sheet1")
            print("Opening Workbook:         ", time.clock()-test_time)

            df = pd.DataFrame([ws_loop.row_values(n) for n in  range(ws_loop.nrows)])            

            newarray = np.vstack((newarray, df.loc[4:43,:13].values))
            del wb_loop

            print("Data Manipulation:         ", time.clock()-test_time)

        except:
            pass
        counter+=1
        print("%s %% Done" %(counter*100/len(unique_file_names)))

    wb_new = xlwt.Workbook()
    ws_new = wb_new.add_sheet("Test")
    ws_new.write(newarray)
    wb_new.save(r"C:Libraries/Documents/NewOutput.xls")

这会输出每个循环 1.6-1.8 秒的平均时间。感谢大家的帮助。

【问题讨论】:

  • 将 Excel 文件读入 Pandas 自然比其他选项(CSV、Pickle、HDF5)要慢。如果您希望提高性能,我强烈建议您考虑这些其他格式。
  • 除非我在打开之前自己进行了转换,否则是不可能的
  • 你试过read_excel()sheet_name="SHEET1"dtype=object吗?这些通常是读取数据时明显的优化。
  • 我试了一下,上次我尝试它时它把时间提高到了大约 3 秒。可能不得不再试一次

标签: python excel python-3.x pandas performance


【解决方案1】:

这是一个快速基准测试(扩展 this one)。显然,对于测试 .xlsx 文件,直接使用 xlrd 比 pandas 稍快。如果 .csv 文件可用,读取它们肯定会快得多,但使用 LibreOffice 转换它们要慢得多:

pd_base 1.96 [in seconds]
pd_float 2.03
pd_object 2.01 [see cs95´s comment to your question]
pd_xlrd 1.95
pyxl_base 2.15
xlrd_base 1.79
csv_ready 0.17
csv_convert 18.72

代码如下:

import pandas as pd
import openpyxl
import xlrd
import subprocess

file = 'test.xlsx'
df = pd.DataFrame([[i+j for i in range(50)] for j in range(100)])
df.to_excel(file, index=False)
df.to_csv(file.replace('.xlsx', '.csv'), index=False)

def pd_base():
    df = pd.read_excel(file)
def pd_float():
    df = pd.read_excel(file, dtype=np.int)
def pd_object():
    df = pd.read_excel(file, sheet_name="Sheet1", dtype=object)
def pd_xlrd():
    df = pd.read_excel(file, engine='xlrd')
def pyxl_base():
    wb = openpyxl.load_workbook(file, read_only=True, keep_links=False, data_only=True)
    sh = wb.active
    df = pd.DataFrame(sh.values)
def xlrd_base():
    wb = xlrd.open_workbook(file)
    sh = wb.sheet_by_index(0)
    df = pd.DataFrame([sh.row_values(n) for n in  range(sh.nrows)])
def csv_ready():    
    df = pd.read_csv(file.replace('.xlsx', '.csv'))
def csv_convert():    
    out = subprocess.check_output(['libreoffice --headless --convert-to csv test.xlsx'], shell=True, stderr=subprocess.STDOUT)
    df = pd.read_csv(file.replace('.xlsx', '.csv'))

def measure(func, nums=50):
    temp = time.time()
    for num in range(nums):
        func()
    diff = time.time() - temp
    print(func.__name__, '%.2f' % diff)

for func in [pd_base, pd_float, pd_object, pd_xlrd, pyxl_base, xlrd_base, csv_ready, csv_convert]:
    measure(func)    

【讨论】:

    【解决方案2】:

    两个提示:

    • ProcessPoolExecutor 具有比纯多处理池更好的接口
    • 如果要加载大文件,则必须控制内存使用方式。

    如果您不提供类型,大多数库将使用可能的最大值(64 位)。如果即使在控制了类型之后您的数据仍无法放入内存,您需要考虑分区和溢出到磁盘。

    下面是您编写的控制数据类型和执行器接口的代码示例

    from concurrent.futures import ProcessPoolExecutor
    from openpyxl import load_workbook
    import pandas as pd
    import numpy as np
    
    
    def load_single(file):
        file_name = rootdir + "/" + str(file)
        wb_loop = load_workbook(file_name, read_only=True, data_only=True)
        ws_loop = wb_loop["SHEET1"]
        df = pd.DataFrame(ws_loop.values)
        partial_array = df.loc[4:43, :13].values.astype(np.float32)
        return partial_array
    
    def run():
        executor = ProcessPoolExecutor(max_workers=4)
        files = unique_file_names[1:]
        results = executor.map(load_single, files)
        new_array = np.empty((0, 39), dtype=np.float32)
        for partial_array in results:
            new_array = np.vstack([new_array, partial_array])
    

    【讨论】:

    • 我尝试过使用它,但我没有运气,不过还是感谢您的建议
    猜你喜欢
    • 1970-01-01
    • 2021-12-22
    • 1970-01-01
    • 2014-10-02
    • 1970-01-01
    • 1970-01-01
    • 2022-08-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多