Dask.dataframe.to_parquet делает очень большой файл - PullRequest
0 голосов
/ 24 апреля 2019

Я преобразую 10 больших файлов фиксированной ширины (в среднем 19 ГБ) в паркет.Я делаю это, складывая файлы фиксированной ширины

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 МБ файлов общим объемом 340 ГБ, и это все еще растет.Есть ли способ, которым я могу читать файлы в dask-фрейме данных, не складывая их, и будет ли это быстрее?И что я могу изменить, чтобы уменьшить размер выходного файла?Насколько я понимаю, паркет сжимается и должен быть меньше, чем файл .txt.

edit Добавлен код для воспроизведения проблемы: Этот код занял 4 минуты для запуска на моей машине.Он создал файл 'test.csv' размером 96 МБ и файл 'test.parquet' размером 239 МБ.Я использую файл с фиксированной шириной для кода, с которым у меня сейчас проблемы, но 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'))

1 Ответ

2 голосов
/ 24 апреля 2019

Код, который вы предоставляете, создает CSV размером 100 МБ и набор данных для паркета размером 93 МБ. Разница в том, что, вероятно, вам не хватает snappy, библиотеки сжатия.

Это нетипично для случайных текстовых данных, которые обычно плохо сжимаются. Существуют некоторые приемы, которые можно воспроизвести с помощью столбца с фиксированной шириной (это позволяет fastparquet, но он используется редко) и категориальное / словарное кодирование (которое будет зависеть от количества данных).

Некоторые заметки

  • 500 столбцов - это высокий уровень, это означает, что у вас нет «табличных» данных в том смысле, для чего предназначен паркет; блоки схемы и сведений для всех этих столбцов занимают место и дублируются между файлами
  • из-за большого количества столбцов число строк в разделе намного меньше, чем обычно, поэтому объем служебной памяти в meatadata пропорционально выше
  • можно отказаться от создания минимальной / максимальной статистики для фрагмента столбца и не создавать файл метаданных, а вместо этого полагаться на одинаковые схемы в каждом файле; но это не то, что легко доступно пользователю. (первый существует только в пиаре)
  • текст хранится в блоках (длина) (данных) для каждой строки, где длина составляет 4 байта; поэтому, если текстовые строки имеют длину 2 байта, они будут храниться как 6 байтов в данных паркета и 3 байта в CSV (из-за запятой). Вариантное кодирование разделяет длины так, чтобы они могли эффективно храниться в виде целых чисел (сработало бы очень хорошо, поскольку все они имеют одинаковое значение), но none каркасов паркета фактически реализует это.
...