Jakie są różnice między piórami a parkietem?

89

Oba są kolumnowymi (dyskowymi) formatami pamięci do użytku w systemach analizy danych. Oba są zintegrowane z Apache Arrow ( pyarrow pakiet dla Pythona) i są zaprojektowane tak, aby odpowiadały Arrow jako kolumna warstwa analityczna w pamięci.

Czym różnią się oba formaty?

Czy podczas pracy z pandami zawsze powinieneś preferować pióra, jeśli to możliwe?

Jakie są przypadki użycia, w których pióro jest bardziej odpowiednie niż parkiet i na odwrót?


dodatek

Znalazłem kilka wskazówek tutaj https://github.com/wesm/feather/issues/188 , ale biorąc pod uwagę młody wiek tego projektu, prawdopodobnie jest on nieco nieaktualny.

Nie jest to poważny test szybkości, ponieważ po prostu zrzucam i ładuję całą ramkę Dataframe, ale aby zrobić wrażenie, jeśli nigdy wcześniej nie słyszałeś o formatach:

 # IPython    
import numpy as np
import pandas as pd
import pyarrow as pa
import pyarrow.feather as feather
import pyarrow.parquet as pq
import fastparquet as fp


df = pd.DataFrame({'one': [-1, np.nan, 2.5],
                   'two': ['foo', 'bar', 'baz'],
                   'three': [True, False, True]})

print("pandas df to disk ####################################################")
print('example_feather:')
%timeit feather.write_feather(df, 'example_feather')
# 2.62 ms ± 35.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
print('example_parquet:')
%timeit pq.write_table(pa.Table.from_pandas(df), 'example.parquet')
# 3.19 ms ± 51 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
print()

print("for comparison:")
print('example_pickle:')
%timeit df.to_pickle('example_pickle')
# 2.75 ms ± 18.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
print('example_fp_parquet:')
%timeit fp.write('example_fp_parquet', df)
# 7.06 ms ± 205 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
print('example_hdf:')
%timeit df.to_hdf('example_hdf', 'key_to_store', mode='w', table=True)
# 24.6 ms ± 4.45 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)
print()

print("pandas df from disk ##################################################")
print('example_feather:')
%timeit feather.read_feather('example_feather')
# 969 µs ± 1.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
print('example_parquet:')
%timeit pq.read_table('example.parquet').to_pandas()
# 1.9 ms ± 5.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

print("for comparison:")
print('example_pickle:')
%timeit pd.read_pickle('example_pickle')
# 1.07 ms ± 6.21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
print('example_fp_parquet:')
%timeit fp.ParquetFile('example_fp_parquet').to_pandas()
# 4.53 ms ± 260 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
print('example_hdf:')
%timeit pd.read_hdf('example_hdf')
# 10 ms ± 43.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# pandas version: 0.22.0
# fastparquet version: 0.1.3
# numpy version: 1.13.3
# pandas version: 0.22.0
# pyarrow version: 0.8.0
# sys.version: 3.6.3
# example Dataframe taken from https://arrow.apache.org/docs/python/parquet.html
Darkonaut
źródło

Odpowiedzi:

130
  • Format Parquet jest przeznaczony do przechowywania długoterminowego, gdzie Arrow jest bardziej przeznaczony do przechowywania krótkoterminowego lub efemerycznego (Arrow może być bardziej odpowiedni do przechowywania długoterminowego po wydaniu 1.0.0, ponieważ format binarny będzie wtedy stabilny)

  • Parkiet jest droższy w zapisie niż Feather, ponieważ zawiera więcej warstw kodowania i kompresji. Pióro jest niezmodyfikowaną surową kolumnową pamięcią Strzały. Prawdopodobnie w przyszłości dodamy prostą kompresję do Feather.

  • Ze względu na kodowanie słownika, kodowanie RLE i kompresję stron danych, pliki Parquet będą często znacznie mniejsze niż pliki Feather

  • Parquet to standardowy format przechowywania danych analitycznych, który jest obsługiwany przez wiele różnych systemów: Spark, Hive, Impala, różne usługi AWS, w przyszłości BigQuery itp. Jeśli więc zajmujesz się analizą, Parquet jest dobrym rozwiązaniem jako format referencyjny dla zapytania przez wiele systemów

Testy porównawcze, które pokazałeś, będą bardzo hałaśliwe, ponieważ dane, które czytasz i zapisujesz, są bardzo małe. Powinieneś spróbować skompresować co najmniej 100 MB lub więcej 1 GB danych, aby uzyskać bardziej pouczające testy porównawcze, patrz np. Http://wesmckinney.com/blog/python-parquet-multithreading/

Mam nadzieję że to pomoże

Wes McKinney
źródło
2
Tak, "nieskompresowane" zawsze będzie opcją
Wes McKinney,
1
Zauważyłem, że twoja generate_floatsfunkcja w kodzie testu porównawczego tutaj wesmckinney.com/blog/python-parquet-update nie gwarantuje unique_values. Są po prostu przypadkowe. Przy n = 100M mam duplikaty dwóch z dziesięciu przebiegów. Wspomnę tylko, jeśli ktoś używa tej funkcji, w której należy zagwarantować unikalność.
Darkonaut
1
@Darkonaut tylko się zastanawiał ... kompresja powoduje zmniejszenie rozmiaru, więc szybsze byłoby wczytanie jej do pamięci. Może się zdarzyć, że dodatkowe przetwarzanie związane z kompresją / dekompresją będzie nadal szybsze niż konieczność odczytu większej liczby bajtów. A może masz sytuację, o której nie myślę?
PascalVKooten
1
HDF5 jest bardziej ogólny i cięższy ... przez większość czasu również znacznie wolniejszy.
ivo Welch
3
@WesMcKinney Zauważyłem, że twoja odpowiedź została napisana w 2018 roku. Czy po 2,3 latach nadal uważasz, że Arrow (pióro) nie nadaje się do długoterminowego przechowywania (w porównaniu do Parquet)? Czy jest jakiś konkretny powód? Jak stabilność? ewolucja formatu? lub?
HCSF