Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/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表格导入pandas?_Python_Pandas_Python Multiprocessing - Fatal编程技术网

Python 如何通过多处理将多张Excel表格导入pandas?

Python 如何通过多处理将多张Excel表格导入pandas?,python,pandas,python-multiprocessing,Python,Pandas,Python Multiprocessing,我试图在12核机器上使用多处理来读取Excel文件——一个60MB的文件,每个文件有15张纸和10000行。导入带有pandas.read_csv的所有工作表,并且没有并行化仍然需要大约33秒 如果我使用pool.map(),它可以工作,但比非并行版本需要更长的时间:150秒比33秒 如果我使用pool.map\u async()需要36秒,但我似乎无法访问(因此无法检查)输出 我的问题是: 我做错了什么?pool.map和pool.map_异步都需要大约 即使我在read_single_工作

我试图在12核机器上使用多处理来读取Excel文件——一个60MB的文件,每个文件有15张纸和10000行。导入带有pandas.read_csv的所有工作表,并且没有并行化仍然需要大约33秒

如果我使用pool.map(),它可以工作,但比非并行版本需要更长的时间:150秒比33秒

如果我使用pool.map\u async()需要36秒,但我似乎无法访问(因此无法检查)输出

我的问题是:

  • 我做错了什么?pool.map和pool.map_异步都需要大约 即使我在read_single_工作表中设置nrows=10,也会在同一时间进行 功能;同时,无论它读取10行还是10000行,这是怎么回事 可能吗
  • 如何获得pool.map_async()的结果?我试过了
    output=[p.get()表示数据帧中的p]
    但它不起作用:
映射结果 对象是不可编辑的

  • 这是IO绑定还是CPU绑定 问题不过,pool.map为什么要花这么长时间
在我的机器上,从CSV读取相同的数据(每个Excel工作表保存到单独的CSV)需要2秒钟。然而,CSV对于我需要做的事情来说并不是一个好的选择。我经常有10到20个中等大小的标签;手动转换它们通常比等待pandas读取它们花费更长的时间,另外,如果我收到更新版本,我必须再次进行手动转换

我知道我可以使用Excel中的VBA脚本自动将每张工作表保存为CSV,但从Excel读取时通常会正确推断数据类型–CSV则不然,尤其是日期(我的日期从来不是ISO YY mm dd):我必须识别日期字段,指定格式,等等–仅从Excel中读取通常会更快。特别是因为这些任务往往是一次性的:我导入数据一次,如果收到更新,可能会导入两到三次,将其存储在SQL中,然后所有Python脚本都从SQL中读取

我用来读取文件的代码是:

import numpy as np
import pandas as pd
import time
import multiprocessing
from multiprocessing import Pool
def parallel_read():
    pool = Pool(num_cores)
    # reads 1 row only, to retrieve column names and sheet names
    mydic = pd.read_excel('excel_write_example.xlsx', nrows=1, sheet_name=None)
    sheets =[]
    for d in mydic:
        sheets.extend([d])
    dataframes  = pool.map( read_single_sheet , sheets  )
    return dataframes

def parallel_read_async():
    pool = Pool(num_cores)
    # reads 1 row only, to retrieve column names and sheet names
    mydic = pd.read_excel('excel_write_example.xlsx', nrows=1, sheet_name=None)
    sheets =[]
    for d in mydic:
        sheets.extend([d])
    dataframes  = pool.map_async( read_single_sheet , sheets  ) 
    output = None
    # this below doesn`t work - can`t understand why
    output = [p.get() for p in dataframes]
    return output

def read_single_sheet(sheet):
    out = pd.read_excel('excel_write_example.xlsx', sheet_name=sheet )
    return out

num_cores = multiprocessing.cpu_count() 

if __name__=='__main__':
    start=time.time()
    out_p = parallel_read()
    time_par = time.time() -start

    out_as = parallel_read_async()
    time_as = time.time() - start - time_par
我用来创建Excel的代码是:

import numpy as np
import pandas as pd

sheets = 15
rows= int(10e3)

writer = pd.ExcelWriter('excel_write_example.xlsx')

def create_data(sheets, rows):
    df = {} # dictionary of dataframes
    for i in range(sheets):
        df[i] = pd.DataFrame(data= np.random.rand(rows,30) )
        df[i]['a'] = 'some long random text'
        df[i]['b'] = 'some more random text'
        df[i]['c'] = 'yet more text'
    return df

def data_to_excel(df, writer):
    for d in df:
        df[d].to_excel(writer, sheet_name = str(d), index=False)
    writer.close()

df = create_data(sheets, rows)
data_to_excel(df, writer)

下面简要介绍了如何绕过文件锁并在对代码进行少量更改的情况下实现并发:

导入io
导入xlrd
从functools导入部分
def read_表(浅黄色,表名):
#仅读取1行,以检索列名和图纸名
df=pd.read\u excel(buff,sheetname=sheetname)
返回df
如果“名称”=“\uuuuuuuu主要”:
开始=时间。时间()
time\u par=time.time()-开始
xl=xlrd.open_工作簿(“myfile.xls”)#您填写此
sheets=xl.book.sheet_name()
buff=io.BytesIO()
xl.转储(buff)
buff.seek(0)
目标=部分(读表,浅黄色)
将池(num_进程)作为p:
dfs=p.map(目标,图纸名称)
time\u as=time.time()-start-time\u par

这里发生了几件事:

  • 调用
    pd.read\u excel('excel\u write\u example.xlsx',nrows=1,sheet\u name=None)
    实际上占用了
    parallel\u read\u async
    似乎要花费的36秒
    map\u async
    立即返回,为您提供
    MapResult
    对象,您通过尝试对其进行迭代立即导致异常,因此在此版本中,
    read\u single\u sheet
    函数基本上没有做任何工作
  • 此外,
    pd.read\u excel
    with
    sheet\u name=None
    所用的时间与
    sheet\u name='1'
    等所用的时间一样长。因此,在您的
    parallel\u read
    函数中,每个进程都在解析每张工作表的每一行。这就是为什么要花这么长时间
现在我已经写出来了,我记得我的公司遇到了同样的问题,我们最终实现了我们自己的xlsx解析器。熊猫使用的xlrd无法在不完全解析的情况下打开xlsx文件


如果您可以选择生成(或接收?)xls文件,那么使用这些文件应该会更快。除此之外,如果非并行处理的速度不可接受,那么导出到csv选项可能是您的最佳选择。

我将此作为一个答案发布,因为虽然它没有回答如何在Python中实现这一点的问题,但它仍然提供了一个切实可行的替代方案,可以大大加快读取时间,因此,任何Python用户都可能对它感兴趣;此外,它只依赖于开源软件,并且只需要用户学习R中的几个命令

我的解决方案是:在R中完成

我发布了关于它的信息,这也显示了我的(非常小的)代码;基本上,在同一个文件上,R的readxl花费了5.6秒。重述:

  • 来自xlsx的Python:33秒
  • 来自CSV的Python:约2秒
  • 来自xlsx的R:5.6秒
该链接还有一个答案,表明并行化可以进一步加快进程

我认为关键的区别在于
pandas.read\u cs
v依赖于C代码,而
pandas.read\u excel
依赖于更多的Python代码。R的
readxl
可能基于C。可以使用C解析器将xlsx文件导入到Python中,但目前还没有这样的解析器

这是一个可行的解决方案,因为在导入到R中之后,您可以轻松地导出为一种格式,该格式保留了关于数据类型的所有信息,并且Python可以从中读取(SQL、parquet等)。并非每个人都有可用的SQL server,但是像parquet或sqlite这样的格式不需要任何额外的软件

因此对工作流的更改是最小的:初始数据加载(至少在我的例子中是一次性的)在R中,其他所有内容都继续在Python中。

我还注意到,使用R和
DBI::dbWriteTable
将相同的工作表导出到SQL要比使用
pandas
快得多(4.2)