有没有更快的方法来使用pandas连接巨大的数据帧(40GB)
Is there a faster way to concat huge data frames (40GB) using pandas
我有 3 个 40 GB 大小的巨大数据框,我使用块打开它们。然后,我想将它们连接在一起。这是我尝试过的:
path = 'path/to/myfiles'
files = [os.path.join(path,i) for i in os.listdir(path) if i.endswith('tsv')]
for file in files:
cols = ['col1','col2','col3']
chunks = pd.read_table(file, sep='\t', names=cols, chunksize=10000000)
但是,当我尝试连接所有文件时,它会花费很长时间。
我想提出一些建议来连接所有数据帧 quicker/faster.
.tsv
和 .csv
相对于 read/write 来说是相当慢的格式。我发现镶木地板最适合我最终做的大部分事情。它的读写速度非常快,还允许您轻松地将文件的分块文件夹作为单个 table 读回。它确实需要字符串列名,但是:
In [102]: df = pd.DataFrame(np.random.random((100000, 100)), columns=[str(i) for i in range(100)])
In [103]: %time df.to_parquet("out.parquet")
Wall time: 980 ms
In [104]: %time df.to_csv("out.csv")
Wall time: 14 s
In [105]: %time df = pd.read_parquet("out.parquet")
Wall time: 195 ms
In [106]: %time df = pd.read_csv("out.csv")
Wall time: 1.53 s
如果您无法控制这些分块文件的格式,您显然需要至少支付一次读取它们的费用,但从长远来看,转换它们仍然可以为您节省一些时间 运行 如果你做了很多其他 read/writes.
- CSV/TSV 是一种非常慢的文件格式,未优化。
- 您可能不需要将整个数据集保存在内存中。您的用例可能不需要对整个组合 (120GB) 数据集进行完全随机的列和行访问 .
- (你能连续处理每个 row/chunk/group(例如邮政编码、user_id 等)吗?例如计算聚合、汇总统计、特征?或者你是否需要能够应用任意跨列(哪些列)或行(哪些列)进行过滤?例如 “获取过去 N 天内使用服务 X 的所有用户 ID”。您可以选择更高性能的文件格式根据您的用例。还有其他文件格式(HDFS、PARQUET 等)。有些针对列访问或行访问进行了优化,有些针对顺序或随机访问进行了优化。还有 PySpark。
- 您不一定需要将数据集组合成一个巨大的 120GB 文件。
- 你说运行时很慢,但很可能你正在耗尽内存(在这种情况下运行时会耗尽 window),所以你首先要检查你的内存使用情况。
- 您的代码试图读入并存储每个文件的所有块,而不是在三个文件中逐块处理它们:
for file in files: ... chunks = pd.read_table(file, ... chunksize=10000000)
。参见 Iterating through files chunk by chunk, in pandas。
- 修复后,
chunksize=1e7
参数不是内存块的大小;它只是块中的行数。这个值大得离谱。如果组合数据帧的一行要占用 10Kb,那么一大块 1e7 这样的行将占用 100Gb(!),这不适合大多数机器。
- 如果您必须坚持使用 CSV,对三个文件中的每一个文件处理一个块,然后将其输出写入文件,不要让所有块都在内存中徘徊。 同时减少你的块大小(尝试例如 1e5 或更少,并测量内存和运行时的改进)。也不要对其进行硬编码,找出每台机器的合理值,and/or 使其成为命令行参数。监控您的内存使用情况。
我有 3 个 40 GB 大小的巨大数据框,我使用块打开它们。然后,我想将它们连接在一起。这是我尝试过的:
path = 'path/to/myfiles'
files = [os.path.join(path,i) for i in os.listdir(path) if i.endswith('tsv')]
for file in files:
cols = ['col1','col2','col3']
chunks = pd.read_table(file, sep='\t', names=cols, chunksize=10000000)
但是,当我尝试连接所有文件时,它会花费很长时间。 我想提出一些建议来连接所有数据帧 quicker/faster.
.tsv
和 .csv
相对于 read/write 来说是相当慢的格式。我发现镶木地板最适合我最终做的大部分事情。它的读写速度非常快,还允许您轻松地将文件的分块文件夹作为单个 table 读回。它确实需要字符串列名,但是:
In [102]: df = pd.DataFrame(np.random.random((100000, 100)), columns=[str(i) for i in range(100)])
In [103]: %time df.to_parquet("out.parquet")
Wall time: 980 ms
In [104]: %time df.to_csv("out.csv")
Wall time: 14 s
In [105]: %time df = pd.read_parquet("out.parquet")
Wall time: 195 ms
In [106]: %time df = pd.read_csv("out.csv")
Wall time: 1.53 s
如果您无法控制这些分块文件的格式,您显然需要至少支付一次读取它们的费用,但从长远来看,转换它们仍然可以为您节省一些时间 运行 如果你做了很多其他 read/writes.
- CSV/TSV 是一种非常慢的文件格式,未优化。
- 您可能不需要将整个数据集保存在内存中。您的用例可能不需要对整个组合 (120GB) 数据集进行完全随机的列和行访问 .
- (你能连续处理每个 row/chunk/group(例如邮政编码、user_id 等)吗?例如计算聚合、汇总统计、特征?或者你是否需要能够应用任意跨列(哪些列)或行(哪些列)进行过滤?例如 “获取过去 N 天内使用服务 X 的所有用户 ID”。您可以选择更高性能的文件格式根据您的用例。还有其他文件格式(HDFS、PARQUET 等)。有些针对列访问或行访问进行了优化,有些针对顺序或随机访问进行了优化。还有 PySpark。
- 您不一定需要将数据集组合成一个巨大的 120GB 文件。
- 你说运行时很慢,但很可能你正在耗尽内存(在这种情况下运行时会耗尽 window),所以你首先要检查你的内存使用情况。
- 您的代码试图读入并存储每个文件的所有块,而不是在三个文件中逐块处理它们:
for file in files: ... chunks = pd.read_table(file, ... chunksize=10000000)
。参见 Iterating through files chunk by chunk, in pandas。 - 修复后,
chunksize=1e7
参数不是内存块的大小;它只是块中的行数。这个值大得离谱。如果组合数据帧的一行要占用 10Kb,那么一大块 1e7 这样的行将占用 100Gb(!),这不适合大多数机器。
- 如果您必须坚持使用 CSV,对三个文件中的每一个文件处理一个块,然后将其输出写入文件,不要让所有块都在内存中徘徊。 同时减少你的块大小(尝试例如 1e5 或更少,并测量内存和运行时的改进)。也不要对其进行硬编码,找出每台机器的合理值,and/or 使其成为命令行参数。监控您的内存使用情况。