我如何使这个函数连接来自单个文件的Excel工作表更高效?

我有几个Excel文件,我想从中生成单独的数据框,这将是每个文件中的任意子表单的连接。

重要的是我能够对表单进行子集分类(在这里我通过索引到sheet_names的列表),并且以某种方式跟踪出处(正如我在这里用assign方法所做的那样)。

这个代码目前可行,但是我担心我错过了一些基本的方法来提高效率(比如当我用一个20页的文件结束时)。

我已经回顾了其他几个与连接多个CSV或Excel文件有关的问题,但很难将这些问题归结为在一个文件中parsing工作表的问题,从效率的angular度来看。

这个问题部分是由于我曾经使用过的生成器来连接Excel文件,但我很难将这些情况推广到这个。

在GitHub上的示例Excel文件

 import pandas as pd import xlrd import xlwt def file_parser(file): df_list = [] for x in file.sheet_names[1::]: df = file.parse(x).assign(Source=x) df_list.append(df) return df_list 

1 如何parsingExcel表格中的数据框(使用Python,可能是Pandas)

将多个csv文件导入到pandas并连接成一个DataFrame

Pands ExcelFile.parse()以dict读取文件,而不是数据框

“高效”可以有不同的解释。 根据你的描述(特别是提到的发电机),我猜你的意思是记忆和计算效率(尽量less使用内存,避免在同一数据上重复循环)。 有了这个想法,这是一回事:

 def df_gen(filename, sheet_names): with xlrd.open_workbook(filename, on_demand=True) as xl_file: for sheet in sheet_names: yield pd.read_excel( xl_file, sheetname=sheet, engine='xlrd').assign(source=sheet) # tell xlrd to let the sheet leave memory xl_file.unload_sheet(sheet) 

这使得xlrd的“按需工作表”function可以避免将整个Excel文档加载到内存中。 在构buildDataFrames之后,表格会从内存中显式卸载。 因为这使用yield是一个生成器,同时创build多less个dataframe取决于您的使用情况。 以下是将此生成器传递给pandas.concat的示例用法:

 df = pd.concat(df_gen('file_name.xlsx', ['sheet1', 'sheet2']), ignore_index=True) 

但是请注意,在进行连接之前, concat 实现了生成器中的所有内容,因此,除了我的函数有意pipe理xlrd工作簿的资源使用情况之外,这不一定比构build列表更有效。 在这种情况下,我想你最终将有1或2个数据拷贝到内存中,这取决于concat的内部。

如果你真的担心内存,你可以使用这个生成器一次迭代地创build一个dataframe:

 # create a generator gen = df_gen(str(filename), sheet_names) # get starting point df = next(gen) # iterate over the rest of the generator for next_df in gen: df = df.append(next_df, ignore_index=True) 

我希望这样的计算效率要比同时调用所有期望数据框的concat效率要低,尽pipe我还没有研究过是否真的如此。 在这种情况下,我想你最终只能在内存中的所有数据的一个副本,加上一个额外的工作表的数据每个循环通过发电机的副本。

你最了解你的情况,但除非这些是真正令人印象深刻的Excel文件,否则我不会花费大量的精力来优化内存和计算,而不是看起来像是胜利。 考虑到这一点,下面是一个简短的函数,它利用pandas.read_excel一次读取多个表的能力:

 def sheets_to_df(filename, sheet_names): df_dict = pd.read_excel(filename, sheetname=sheet_names) return pd.concat( (df.assign(source=sheet) for sheet, df in dfs.items()), ignore_index=True) 

有一件事要注意的是,当传入一个文件名时, read_excel将加载整个Excel文档 (例如,不使用xlrd的“on demand”function)。 所以,虽然这在代码行方面是有效的,但在内存方面绝对不是有效的。 我认为这简短地结束了内存中的所有数据2-3次:一次在df_dict ,一次在最后的连接dataframe(可能再次取决于concat的内部)。 但是一旦这个函数返回,你只剩下最后一个dataframe中的一个副本。 如果您打算阅读大部分表格,这不会是一个巨大的浪费(假设他们至less两次都适合记忆),但如果您打算只阅读一小部分表格,这可能有点儿浪费。

我希望这有帮助! 你可以得到这个Jupyter笔记本在这里: https ://gist.github.com/jiffyclub/9ab668f63c3d0f9adf3e730dc37cd419