Самый быстрый способ написать фрейм данных BIG pandas

#python #pandas #performance #dataframe #file

#python #pandas #Производительность #фрейм данных #файл

Вопрос:

Я провел тест, в котором были протестированы 10 способов записи и 10 способов чтения фрейма данных. Я нашел тест здесь (я внес некоторые изменения и добавил Parquet в список) Лучшими способами были :

 df.to_feather('test.feather') :
39.34544535900204s

table=pyarrow.Table.from_pandas(df)
pq.write_table(table, "test_parquet_write_snappy_dict.parquet",
               use_dictionary=True, version='2.0', compression='snappy') :
40.6873751259991s

table=pyarrow.Table.from_pandas(df, nthreads=4)
pq.write_table(table, "test_parquet_write_snappy_dict.parquet",
               use_dictionary=True, version='2.0', compression='snappy') :
41.051620177000586s
  

для написания

и

 pd.read_hdf('test_fixed.hdf', 'test') :
1.5275615360005759

pd.read_feather('test.feather') :
20.635139821002667

pd.read_pickle('test.pkl') :
37.21131302599679
  

для чтения.

Вот фрейм данных :

 sz = 50000000
df = pd.DataFrame({'A': randn(sz), 'B': randn(sz), 'C': randn(sz), 'D': randn(sz)})
  

У меня есть два вопроса. Как read_hdf в 20 раз быстрее, чем read_feather, если to_hdf этого нет даже в первых трех тестах записи?

И, во-вторых, 40 секунд все еще слишком медленный для моих нужд. Есть ли способ улучшить эту скорость? Либо используя разные параметры с to_feather или write_table , либо используя функцию / модуль, о котором я не знаю?

Я не прошу кого-то искать меня, я могу сделать это сам, и я не хочу тратить чье-либо время. Я ищу кого-то, кто уже знает эту проблему и мог бы привести меня к самому быстрому способу, который он знает.

Комментарии:

1. Я бы с недоверием отнесся к тестированию чтения HDF с такой разницей в скорости. Может быть, также вычислить «контрольную сумму» (скажем, сумму одного столбца?) для чтения данных и сравнения их с известным значением. Это обеспечит надежность вашего ввода-вывода, а также гарантирует, что данные не загружаются лениво.

2. Хорошо. Тест чтения HDF был моим неудачным. Это не быстро.

Ответ №1:

Это не совсем ответ сам по себе, но вот более подробный тест различных методов для данных, подобных вашему…

 import timeit

import numpy as np
import pandas as pd
from numpy.random import randn, randint


def generate_data(n):
    df = pd.DataFrame(
        {
            "dt": randint(1_600_000_000, 1_700_000_000, size=n) * 1000,
            "a": randn(n),
            "b": randn(n),
            "c": randn(n),
        }
    )
    df.dt = pd.to_datetime(df.dt, unit="s")
    df.set_index("dt", inplace=True)
    return df


def benchmark(df, name, saver, loader):
    verify(df, loader, saver)
    save_timer = timeit.Timer(lambda: saver(df))
    load_timer = timeit.Timer(lambda: loader().a.sum())
    save_n, save_time = save_timer.autorange()
    load_n, load_time = load_timer.autorange()
    total_time = (load_time / load_n)   (save_time / save_n)
    print(
        f"{name:<15s} : "
        f"{save_n / save_time:>20.3f} save/s : "
        f"{load_n / load_time:>20.3f} load sum/s : "
        f"{1 / total_time: >20.3f} total speed"
    )


def verify(df, loader, saver):
    saver(df)
    loaded = loader()
    assert np.allclose(loaded.a.sum(), df.a.sum())
    assert np.allclose(loaded.b.sum(), df.b.sum())
    assert list(loaded.columns) == list(df.columns), loaded.columns


def save_feather(df):
    df = df.reset_index()
    df.to_feather("dummy.feather")


def load_feather():
    df = pd.read_feather("dummy.feather")
    df.set_index("dt", inplace=True)
    return df


def main():
    df = generate_data(5_000_000)
    benchmark(df, "dummy", lambda df: None, lambda: df)
    benchmark(df, "csv", lambda df: df.to_csv("dummy.csv"), lambda: pd.read_csv("dummy.csv", index_col="dt"))
    benchmark(df, "hdf", lambda df: df.to_hdf("dummy.h5", "dummy"), lambda: pd.read_hdf("dummy.h5", "dummy"))
    benchmark(df, "pickle", lambda df: df.to_pickle("dummy.pickle"), lambda: pd.read_pickle("dummy.pickle"))
    benchmark(df, "feather", save_feather, load_feather)
    benchmark(
        df,
        "parquet",
        lambda df: df.to_parquet("dummy.parquet", allow_truncated_timestamps=True),
        lambda: pd.read_parquet("dummy.parquet"),
    )


if __name__ == "__main__":
    main()
  

На моем компьютере (Ryzen 7 3700X, SSD-диск, Windows 10, Python 3.8, новейшие Pandas и тому подобное) и в DF с миллионом строк (не удосужился дождаться результатов CSV) я получаю

 dummy           :         10475677.467 save/s :              186.737 load sum/s :              186.734 total speed
csv             :                0.185 save/s :                0.970 load sum/s :                0.156 total speed
hdf             :               18.289 save/s :               28.514 load sum/s :               11.142 total speed
pickle          :               14.058 save/s :               31.962 load sum/s :                9.764 total speed
feather         :               34.766 save/s :               41.436 load sum/s :               18.904 total speed
parquet         :                7.707 save/s :               19.603 load sum/s :                5.532 total speed
  

так что HDF5 определенно не на порядок быстрее.

Комментарии:

1. Как вы можете так быстро создавать тесты xD И да, ваши результаты показывают мне, что feather действительно самый быстрый, без параметров, которые могли бы улучшить другие функции. Я, вероятно, буду придерживаться feather и попытаюсь ускорить его!