我正在尝试在 12 核机器上使用多处理来读取一个 Excel 文件——一个 60MB 的文件,每页有 15 张 10,000 行。使用 pandas.read_csv 导入所有工作表并且没有并行化仍然需要大约 33 秒。
如果我使用 pool.map() 它可以工作,但它比非并行版本需要更长的时间:150 秒对 33 秒!
如果我使用 pool.map_async() 需要 36 秒,但我似乎无法访问(因此无法检查)输出!
我的问题是:
- 我做错了什么? pool.map 和 pool.map_async 都需要大致 同时,即使我在 read_single_sheet 中设置 nrows=10 功能;同时读取 10 行或 10,000 行 - 怎么样 可能吗?
- 如何获得 pool.map_async() 的结果?我努力了
output = [p.get() for p in dataframes]
但它不起作用:
MapResult object is not iterable
- 这是 IO 限制多于 CPU 限制吗 问题?不过,为什么 pool.map 需要这么长时间?
从 CSV 读取相同的数据(每个 Excel 工作表保存到一个单独的 CSV)在我的机器上需要 2 秒。但是,对于我需要做的事情,CSV 并不是一个好的选择。我经常有 10 到 20 个中型标签;手动转换它们通常比等待 pandas 读取它们花费的时间更长,而且如果我收到更新版本,我必须再次进行手动转换。
我知道我可以在 Excel 中使用 VBA 脚本自动将每张工作表保存为 CSV,但是从 Excel 读取数据类型时通常可以正确推断出数据类型——对于 CSV 则不然,尤其是对于日期(我的日期从来不是 ISO yyyy- mm-dd):我必须识别日期字段、指定格式等——仅从 Excel 读取通常会更快。特别是因为这些任务往往是一次性的:我导入数据一次,如果我收到更新可能会导入 2 次或 3 次,将其存储在 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)
最佳答案
我将此作为答案发布是因为,虽然它没有回答如何在 Python 中执行此操作的问题,但它仍然提供了一种可行的替代方法来实质性地加快阅读时间,因此它可以任何 Python 用户都感兴趣;此外,它仅依赖于开源软件,并且只需要用户学习 R 中的几个命令。
我的解决方案是:在 R 中完成!
我发布了它 here ,这也显示了我的(非常少的)代码;基本上,在同一个文件中,R 的 readxl
耗时 5.6 秒。回顾一下:
- 来自 xlsx 的 Python:33 秒
- 来自 CSV 的 Python:大约2秒
- 来自 xlsx 的 R:5.6 秒
该链接还有一个答案,表明并行化可以进一步加快进程。
我认为关键区别在于 pandas.read_cs
v 依赖于 C 代码,而 pandas.read_excel
依赖于更多的 Python 代码。 R 的 readxl
可能基于 C。可能可以使用 C 解析器将 xlsx 文件导入 Python,但据我所知,目前还没有这样的解析器可用。
这是一个可行的解决方案,因为在导入到 R 之后,您可以轻松导出为保留所有数据类型信息的格式,Python 可以从中读取(SQL、parquet 等)。不是每个人都有可用的 SQL 服务器,但像 parquet 或 sqlite 这样的格式不需要任何额外的软件。
因此,对工作流程的更改是最小的:初始数据加载,至少在我的情况下,往往是一次性的,在 R 中,其他所有内容继续在 Python 中。强>
我还注意到使用 R 和 DBI::dbWriteTable
将相同的工作表导出到 SQL 的速度要快得多比pandas
(4.25 秒对 18.4 秒)。
关于python - 如何使用多处理将多个 Excel 工作表导入 Pandas ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55505311/