在本文中,我将介绍在 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 中数据加载操作性能的优势。

最后修改:2024 年 05 月 20 日
本站福利|微信扫描二维码,永久享受 96 折充话费电费