在本文中,我将介绍在 Python 中加载数据的五种方法。在讨论结束时,我们将实现三个数量级的速度提升,使处理速度快得令人难以置信。
实验设置
假设我们需要加载 10 个 Excel 文件,每个文件包含 20,000 行和 25 列,总计约 70MB。当您将事务数据从 SAP 等 ERP 系统传输到 Python 中进行分析时,这种情况非常典型。
首先,我们将生成这些虚拟数据,并通过导入必要的库来设置我们的环境(稍后我们将深入探讨使用 pickle 和 joblib 等库的具体细节)。
import pandas as pd
import numpy as np
from joblib import Parallel, delayed
import time
for file_number in range(10):
values = np.random.uniform(size=(20000,25))
pd.DataFrame(values).to_csv(f"Dummy {file_number}.csv")
pd.DataFrame(values).to_excel(f"Dummy {file_number}.xlsx")
pd.DataFrame(values).to_pickle(f"Dummy {file_number}.pickle")
用 Python 加载数据的 5 种方法
1:使用 Pandas 加载 Excel 文件
我们将从加载 Excel 文件的最简单方法开始。我们将初始化一个 Pandas DataFrame,然后按顺序将每个 Excel 文件附加到其中。这种方法提供了一种清晰而直接的方式,可将多个来源的数据编译到一个结构中进行分析。
start = time.time()
df = pd.read_excel("Dummy 0.xlsx")
for file_number in range(1,10):
df.append(pd.read_excel(f"Dummy {file_number}.xlsx"))
end = time.time()
print("Excel:", end - start)
运行大约需要 50 秒。相当慢。
将 Excel 文件转换为 CSV 格式后,加载时间大幅缩短至 0.63 秒,比之前快了近 10 倍。Python 处理 CSV 文件的速度通常比 Excel 文件快得多,通常快达 100 倍。因此,使用 CSV 是处理大型数据集的高效策略。
不过,一个明显的缺点是,与 .xlsx 文件相比,CSV 文件的大小通常较大。例如,在我们的示例中,CSV 文件每个 9.5MB,而 .xlsx 文件只有 6.4MB。
2:更智能地创建 Pandas 数据框
为了进一步改进数据加载过程,我们可以优化创建 Pandas DataFrames 的方式。我们不必将每个文件直接附加到现有的 DataFrame 中,因为这样会很耗时:
1.我们将每个 Excel 或 CSV 文件加载到一个单独的 DataFrame 中。
2.2. 将这些 DataFrame 保存在一个列表中。 3.最后,我们将列表中的所有 DataFrame 连接成一个 DataFrame。
这种方法通常比增量追加每个文件更快,因为它减少了重复扩展 DataFrame 所带来的开销。
start = time.time()
df = []
for file_number in range(10):
temp = pd.read_csv(f"Dummy {file_number}.csv")
df.append(temp)
df = pd.concat(df, ignore_index=True)
end = time.time()
print("CSV2:", end - start)
我们的加载时间略有缩短。根据我的经验,这种技术在处理较大的 DataFrames(通常超过 100MB 大小)时尤其有效。
3:使用 Joblib 并行 CSV 导入
为了进一步加快加载过程,可以考虑并行导入多个文件。我们可以同时并行加载 10 个文件,而不是按顺序加载每个文件。
这种方法利用了 joblib
库的功能,它简化了 Python 中的并行处理。通过使用 joblib
库,我们可以将文件加载任务分配给多个内核或线程,从而大幅缩短整体加载时间。
start = time.time()
def loop(file_number):
return pd.read_csv(f"Dummy {file_number}.csv")
df = Parallel(n_jobs=-1, verbose=10)(delayed(loop)(file_number) for file_number in range(10))
df = pd.concat(df, ignore_index=True)
end = time.time()
print("CSV//:", end - start)
与单核版本相比,我们成功地将速度提高了一倍。不过,需要注意的是,增加内核数量并不能线性提升性能。例如,在配备 M1 芯片的 Mac Air 上使用 8 个内核,我观察到的速度提升是 2 倍,而不是 8 倍。
使用 Joblib 在 Python 中实现简单并行化
Joblib 是一个简单的 Python 库,专为并行处理而设计。它的操作类似于列表理解,但有一个关键区别:每次迭代都在单独的线程上执行。这种方法允许同时处理任务。下面是实现方法:
def loop(file_number):
return pd.read_csv(f"Dummy {file_number}.csv")
df = Parallel(n_jobs=-1, verbose=10)(delayed(loop)(file_number) for file_number in range(10))
#equivalent to
df = [loop(file_number) for file_number in range(10)]
4:利用 Pickle 文件
要想更快地存储和检索数据,可以考虑使用 Pickle 文件。Pickle 是一种 Python 专用格式,设计用于序列化和反序列化对象,与 .csv 文件相比,可以更快地加载数据。
不过,一个明显的缺点是,pickle 文件不是人类可读的。与 .csv 文件不同,您不能在文本编辑器或电子表格程序中打开 pickle 文件,直接查看或编辑其内容。
start = time.time()
def loop(file_number):
return pd.read_pickle(f"Dummy {file_number}.pickle")
df = Parallel(n_jobs=-1, verbose=10)(delayed(loop)(file_number) for file_number in range(10))
df = pd.concat(df, ignore_index=True)
end = time.time()
print("Pickle//:", end - start)
我们成功地将处理时间缩短了 80%!
总的来说,使用 pickle 文件比使用 .csv 文件要快得多。不过,pickle 文件通常会占用更多的硬盘存储空间(但在本例中不会)。
实际上,系统通常不会直接以 pickle 格式导出数据。我建议在以下情况下使用 pickle 文件:
1.供 Python 内部使用:如果您要保存 Python 进程中的数据,并且不需要在 Excel 或其他非 Python 环境中打开这些数据,那么可以将 DataFrames 存储为 pickle 文件。这非常适合您打算在 Python 脚本或应用程序中重复使用的数据。
2.用于频繁访问文件:如果您重复加载相同的文件,那么在首次加载后将其保存为 pickle 文件会很有效。未来的进程可以直接从 pickle 文件加载,绕过较慢的 .csv 加载过程。
举例说明要管理每月更新的事务数据,可以在首次加载后将每个月的数据从 .csv 文件转换为 .pickle 文件。这样,您就可以快速访问 pickle 格式的历史数据,从而在每月新数据到来时简化工作流程。
5: 并行加载 Excel 文件
如果您发现自己收到 Excel 文件,并且必须直接处理这些文件,那么仍然可以使用并行处理来提高效率。您可以使用 joblib
库并行加载这些文件,就像处理其他格式文件一样。
要实现这一点,需要调整循环中的函数,以便专门处理 Excel 文件。这种修改包括使用专门用于加载 Excel 文件的函数,然后使用 joblib
将这些任务分配给多个处理器。这种方法可以大大减少同时加载多个 Excel 文件所需的时间。
start = time.time()
def loop(file_number):
return pd.read_excel(f"Dummy {file_number}.xlsx")
df = Parallel(n_jobs=-1, verbose=10)(delayed(loop)(file_number) for file_number in range(10))
df = pd.concat(df, ignore_index=True)
end = time.time()
print("Excel//:", end - start)
我们成功地将加载时间缩短了 70%,从 50 秒减至 13 秒。
此外,你还可以利用这个并行加载过程来即时创建 pickle 文件。这样,下次需要加载这些文件时,就可以利用腌制文件所提供的明显更快的加载时间,确保近乎瞬时地访问数据。这种方法不仅能优化初始加载过程,还能简化未来与相同数据集的交互。
通过各种数据加载方法,我们大大提高了效率,减少了处理大型数据集所需的时间:
- Excel 文件:最初需要 50 秒才能加载。
- CSV 文件:缩短至 0.63 秒。
- 更智能的 CSV 加载:进一步改进为 0.62 秒。
- 并行 CSV 加载:缩短至 0.34 秒。
- 并行拾取加载:大幅缩短至 0.07 秒,不到十分之一秒。
- 并行 Excel 加载:缩短至 13.5 秒。
这些结果凸显了优化文件格式和利用并行处理提高 Python 中数据加载操作性能的优势。