【问题标题】:Dask.dataframe.to_parquet making extremely large fileDask.dataframe.to_parquet 制作非常大的文件
【发布时间】:2019-04-24 14:30:49
【问题描述】:

我正在将 10 个固定宽度的大型文件(平均 19GB)转换为镶木地板。 我通过堆叠固定宽度的文件来做到这一点

file_list = [files]

stacked_files = open(stacked.txt,'a')
for i in file_list:
    f = open(i)
    for line in f:
        stacked_files.write(line)
    f.close()
    print(i,(time.time() - file_start)//60)
stacked_files.close()

此过程需要 3 小时才能完成。 然后我使用 dask 读取文件,并将其转换为镶木地板。 我已经安装了 fastparquet

df = dd.read_fwf(stacked.txt, colspecs = colspecs, names = names)
df.to_parquet('parquet.parquet')

我计划为此添加一些处理,例如通过重置索引对其进行排序并在列上进行计算,但现在我学习 dask,我想看看将其更改为镶木地板是如何工作的。 这已经运行了 2 天,已经制作了超过 2200 个 151 MB 的文件,总计 340GB,并且还在增长。 有没有一种方法可以在不堆叠文件的情况下将文件读入 dask 数据帧,这样会更快吗? 有什么可以改变的以使输出文件更小吗?我的理解是镶木地板是压缩的,应该小于 .txt 文件。

编辑 添加了重现问题的代码: 这段代码在我的机器上运行了 4 分钟。它创建了一个文件“test.csv” 96 MB 并创建了一个文件“test.parquet” 239 MB。 我正在为我目前遇到问题的代码使用固定宽度文件,但 csv 似乎重现了将文件大小增加三倍的效果。

import dask.dataframe as dd
import pandas as pd
import random
import os
test_file_folder = 'folder'

#create 500 columns
colnames = []
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
first_letter = 0
for i in range(500):
    second_letter = i%26
    colnames.append(letters[first_letter]+letters[second_letter])
    if i%26 == 0 and i !=0:
        first_letter +=1

#create a dictionary with 100,000 data points in each key with column names as keys
df = {}
for i in colnames:
    temp = []
    for x in range(100000):
        temp.append(random.choice(letters))
    df[i] = temp

#create the df and send it to csv
df = pd.DataFrame.from_dict(df)

df.to_csv(os.path.join(test_file_folder,'test.csv'))

ddf = dd.read_csv(os.path.join(test_file_folder,'test.csv'))
ddf.to_parquet(os.path.join(test_file_folder,'test.parquet'))

【问题讨论】:

  • 您是否考虑过一次阅读并转换成 parquet 文件?获得比txt 更大的parquet 真的很奇怪。您使用的是哪个引擎?
  • 我将其保留为默认值。考虑到我只安装了 fastparquet,我假设它将使用 fastparquet
  • 你能提供一个mcve吗?即使使用 numpy 生成的数据。
  • 添加到我的编辑中

标签: dask parquet


【解决方案1】:

您提供的代码生成 100MB 的 CSV 和 93MB 的 parquet 数据集。不同的是,你可能缺少 snappy 压缩库。

这对于随机文本数据来说并非不典型,因为它们通常不能很好地压缩。您可以使用固定宽度列(fastparquet 允许这样做,但很少使用)和分类/字典编码(这将取决于数据的基数)来玩一些技巧。

一些笔记

  • 500 列很高,这意味着您并没有真正意义上的“表格”数据,因为 parquet 是为此而生的;所有这些列的架构和详细信息块占用空间并在文件之间重复
  • 由于列数较多,每个分区的行数比通常情况下要少得多,因此肉类数据的空间开销相应较高
  • 可以放弃为每个列块生成最小/最大统计信息,并且不制作元数据文件,而是依赖于每个文件中相同的架构;但这不是容易暴露给用户的东西。 (前者只存在于 PR 中)
  • 文本由每个字符串的(长度)(数据)块存储,其中长度为4个字节;因此,如果文本字符串每个为 2 字节,则它们将在 parquet 数据中存储为 6 个字节,在 CSV 中存储为 3 个字节(因为逗号)。变体编码将长度分开,以便它们可以有效地存储为整数(因为它们都是相同的值,所以效果非常好),但是 没有 实木复合地板框架实际上实现了这一点。

【讨论】:

  • 安装 snappy 也给了我一个 93MB 的文件。谢谢!你有什么更好的方法来存储我可以在 Dask 中使用的 500 列文件吗?
  • 如果这真的是一个数值数组,我会使用 zarr 和 dask.array。如果不了解数据的用途,很难说。
  • 它是2亿行,400/500的列要么是字母要么是空格。
  • “字母或空格” - 听起来很像数字或分类。如果您使用 int8 或 cat,您会发现 parquet 在速度和尺寸方面的性能要好得多;但是是的,这可以使用类似数组的格式存储,例如 zarr。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多