Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使此函数从单个文件连接Excel工作表更有效?_Python_Excel_Python 3.x_Pandas - Fatal编程技术网

Python 如何使此函数从单个文件连接Excel工作表更有效?

Python 如何使此函数从单个文件连接Excel工作表更有效?,python,excel,python-3.x,pandas,Python,Excel,Python 3.x,Pandas,我有几个Excel文件,我想从中生成单独的数据框,这些数据框是每个文件中任意图纸子集的串联 重要的是,我能够对工作表进行子集划分(在这里,我通过索引到工作表名称列表),并以某种方式跟踪出处(就像我在这里使用赋值方法所做的那样) 这段代码目前可以工作,但我担心我缺少一些基本的方法来提高效率(比如当我得到一个有20张纸的文件时) 我已经回顾了其他几个关于连接(例如)多个CSV或Excel文件的问题1,但很难将这些问题推广到解析一个文件中的工作表的问题,即效率问题 这个问题的部分原因是我以前使用生成器

我有几个Excel文件,我想从中生成单独的数据框,这些数据框是每个文件中任意图纸子集的串联

重要的是,我能够对工作表进行子集划分(在这里,我通过索引到
工作表名称列表
),并以某种方式跟踪出处(就像我在这里使用
赋值
方法所做的那样)

这段代码目前可以工作,但我担心我缺少一些基本的方法来提高效率(比如当我得到一个有20张纸的文件时)

我已经回顾了其他几个关于连接(例如)多个CSV或Excel文件的问题1,但很难将这些问题推广到解析一个文件中的工作表的问题,即效率问题

这个问题的部分原因是我以前使用生成器连接Excel文件,但我很难将这些情况推广到这一个


一,

“高效”可以有不同的解释。根据您的描述(特别是提到生成器),我猜您指的是内存和计算效率(使用尽可能少的内存,避免重复循环相同的数据)。考虑到这一点,我们有一个办法:

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的特性来避免将整个Excel文档加载到内存中。在构造数据帧后,将从内存中显式卸载工作表。因为它使用
yield
它是一个生成器,同时创建多少数据帧取决于您的使用情况。下面是将此生成器传递给pandas.concat的示例用法:

df = pd.concat(df_gen('file_name.xlsx', ['sheet1', 'sheet2']), ignore_index=True)
但是,请注意,在进行连接之前,生成器中的所有内容都要进行连接,因此这并不一定比您构建列表的示例更有效,只是我的函数有意管理xlrd工作簿的资源使用。在这种情况下,我认为根据
concat
的内部结构,一次在内存中存储1到2份数据

如果您真的担心内存问题,可以使用生成器一次迭代地构建一个数据帧一张表:

# 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
,尽管我还没有研究这是否是真的。在这种情况下,我认为您一次只能得到内存中所有数据的一个副本,再加上通过生成器的每个循环的一个额外的工作表数据副本

你最了解自己的情况,但除非这些是真正令人印象深刻的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
will(例如,不使用xlrd的“按需”功能)。因此,虽然这在代码行方面是有效的,但在内存方面肯定不是有效的。我认为这会导致内存中的所有数据出现2-3次:一次出现在
df_dict
中,一次出现在最终连接的数据帧中(可能还取决于
concat
的内部结构)。但是一旦这个函数返回,在最后的数据帧中只剩下一个副本。如果你打算阅读大部分的工作表,这不会是一个巨大的浪费(假设它们都能在内存中存储至少两次),但是如果你打算只阅读工作表的一小部分,这可能会有点浪费


我希望这有帮助!您可以在此处将其作为Jupyter笔记本使用:

工作表名称是否与您需要的相同?或者你从来都不想要第一张纸?@djk47463对于前几个文件,我发现省略第一张纸就足够了,但从你的评论中我看到,你认为应该将其标记为关闭。我认为,经过编辑,这个人可以提出一个可行的问题,我理解你为什么不这样做。下次投票时,我会考虑的,谢谢。
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)