羽毛和镶木地板有什么区别?

Dar*_*aut 50 python pandas parquet feather pyarrow

两者都是用于数据分析系统的柱状(磁盘)存储格式.两者都集成在Apache Arrow(用于python的pyarrow包)中,旨在与Arrow对应作为柱状内存分析层.

两种格式有何不同?

在可能的情况下,你是否总是喜欢使用羽毛?

羽毛镶木地板更合适,反之亦然的用途是什么?


附录

我在这里找到了一些提示https://github.com/wesm/feather/issues/188,但考虑到这个项目的年龄,它可能有点过时了.

不是一个严肃的速度测试,因为我只是倾倒并加载一个完整的Dataframe,但如果您之前从未听说过这些格式,那么会给您一些印象:

 # 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
Run Code Online (Sandbox Code Playgroud)

Wes*_*ney 73

  • Parquet格式专为长期存储而设计,其中Arrow更适合短期或临时存储(在1.0.0版本发布后,Arrow可能更适合长期存储,因为二进制格式将稳定)

  • Parquet比Feather更昂贵,因为它具有更多的编码和压缩层.羽毛是未经修改的原始柱状箭头记忆.我们可能会在将来为Feather添加简单的压缩.

  • 由于字典编码,RLE编码和数据页面压缩,Parquet文件通常比Feather文件小得多

  • Parquet是分析的标准存储格式,由许多不同的系统支持:Spark,Hive,Impala,各种AWS服务,以及BigQuery未来等等.因此,如果您正在进行分析,Parquet是一个很好的选择作为参考存储格式多个系统查询

您展示的基准测试将会非常嘈杂,因为您读取和写入的数据非常小.您应该尝试压缩至少100MB或更高的1GB数据以获得更多信息性基准,例如http://wesmckinney.com/blog/python-parquet-multithreading/

希望这可以帮助

  • @WesMcKinney我注意到你的答案是在2018年写的。2.3年后,你仍然认为Arrow(羽毛)不适合长期存储(与Parquet相比)?有具体原因吗?喜欢稳定?格式演变?或者? (19认同)
  • W. McKinney 表示,feather (v2) 现已稳定:/sf/ask/4486278401/ 1-0-1 (10认同)
  • 我相信这个答案已经过时了。我们应该更新或删除 (7认同)
  • 是的,“未压缩”将始终是一个选项 (4认同)
  • 感谢您的回答,但问题是在羽毛和镶木地板之间,您在回答时提到了“箭头”。这让事情变得更加混乱。 (3认同)
  • HDF5 更通用、更笨重……而且大多数时候速度也慢很多。 (2认同)
  • 仅添加一个观察结果,镶木地板格式的 200,000 张图像需要 4 GB,而羽毛格式则需要 6 GB。使用 pandas pd.read_parquet 和 pd.read_feather 读取数据。pd.read_parquet 花费了大约 4 分钟,但 pd.read_feather 花费了 11 秒。这是一个巨大的差异。参考:https://www.kaggle.com/corochann/bangali-ai-super-fast-data-loading-with-feather (2认同)

Art*_*tra 18

我还将在镶木地板和羽毛之间的比较中包括不同的压缩方法,以检查导入/导出速度及其使用的存储量。

\n

我建议为想要更好的 csv 替代方案的普通用户提供两种选择:

\n
    \n
  • 带“gzip”压缩的 parquet(用于存储):导出比 .csv 快得多(如果需要压缩 csv,则 parquet 要快得多)。导入速度比 csv 快大约 2 倍。压缩后的文件大小约为原始文件大小的 22%,与压缩的 csv 文件大小大致相同。
  • \n
  • Feather 与“zstd”压缩(用于 I/O 速度):与 csv 相比,Feather 导出的导出速度快 20 倍,导入速度快约 6 倍。存储空间约为原始文件大小的 32%,比 parquet“gzip”和 csv 压缩的文件大小差 10%,但仍然不错。
  • \n
\n

两者都是比所有类别(I/O 速度和存储)中的普通 csv 文件更好的选择。

\n

我分析了以下格式:

\n
    \n
  1. 数据集
  2. \n
  3. 使用“zip”压缩的 csv
  4. \n
  5. 使用“zstd”压缩的羽毛
  6. \n
  7. 使用“lz4”压缩的羽毛
  8. \n
  9. 使用“snappy”压缩的镶木地板
  10. \n
  11. 使用“gzip”压缩的镶木地板
  12. \n
  13. 使用“brotli”压缩的镶木地板
  14. \n
\n

\n
import zipfile\nimport pandas as pd\nfolder_path = (r"...\\\\intraday")\nzip_path = zipfile.ZipFile(folder_path + "\\\\AAPL.zip")    \ntest_data = pd.read_csv(zip_path.open('AAPL.csv'))\n\n\n# EXPORT, STORAGE AND IMPORT TESTS\n# ------------------------------------------\n# - FORMAT .csv \n\n# export\n%%timeit\ntest_data.to_csv(folder_path + "\\\\AAPL.csv", index=False)\n# 12.8 s \xc2\xb1 399 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n\n# storage\n# AAPL.csv exported using python.\n# 169.034 KB\n\n# import\n%%timeit\ntest_data = pd.read_csv(folder_path + "\\\\AAPL.csv")\n# 1.56 s \xc2\xb1 14.1 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n\n# ------------------------------------------\n# - FORMAT zipped .csv \n\n# export\n%%timeit\ntest_data.to_csv(folder_path + "\\\\AAPL.csv")\n# 12.8 s \xc2\xb1 399 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n# OBSERVATION: this does not include the time I spent manually zipping the .csv\n\n# storage\n# AAPL.csv zipped with .zip "normal" compression using 7-zip software.\n# 36.782 KB\n\n# import\nzip_path = zipfile.ZipFile(folder_path + "\\AAPL.zip")\n%%timeit\ntest_data = pd.read_csv(zip_path.open('AAPL.csv'))\n# 2.31 s \xc2\xb1 43.9 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n\n# ------------------------------------------\n# - FORMAT .feather using "zstd" compression.\n\n# export\n%%timeit\ntest_data.to_feather(folder_path + "\\\\AAPL.feather", compression='zstd')\n# 460 ms \xc2\xb1 13.3 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n\n# storage\n# AAPL.feather exported with python using zstd\n# 54.924 KB\n\n# import\n%%timeit\ntest_data = pd.read_feather(folder_path + "\\\\AAPL.feather")\n# 310 ms \xc2\xb1 11.4 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n\n# ------------------------------------------\n# - FORMAT .feather using "lz4" compression.\n# Only works installing with pip, not with conda. Bad sign.\n\n# export\n%%timeit\ntest_data.to_feather(folder_path + "\\\\AAPL.feather", compression='lz4')\n# 392 ms \xc2\xb1 14.6 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n\n# storage\n# AAPL.feather exported with python using "lz4"\n# 79.668 KB    \n\n# import\n%%timeit\ntest_data = pd.read_feather(folder_path + "\\\\AAPL.feather")\n# 255 ms \xc2\xb1 4.79 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n\n# ------------------------------------------\n# - FORMAT .parquet using compression "snappy"\n\n# export\n%%timeit\ntest_data.to_parquet(folder_path + "\\\\AAPL.parquet", compression='snappy')\n# 2.82 s \xc2\xb1 47.9 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n\n# storage\n# AAPL.parquet exported with python using "snappy"\n# 62.383 KB\n\n# import\n%%timeit\ntest_data = pd.read_parquet(folder_path + "\\\\AAPL.parquet")\n# 701 ms \xc2\xb1 19.8 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n\n# ------------------------------------------\n# - FORMAT .parquet using compression "gzip"\n\n# export\n%%timeit\ntest_data.to_parquet(folder_path + "\\\\AAPL.parquet", compression='gzip')\n# 10.8 s \xc2\xb1 77.6 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n\n# storage\n# AAPL.parquet exported with python using "gzip"\n# 37.595 KB\n\n# import\n%%timeit\ntest_data = pd.read_parquet(folder_path + "\\\\AAPL.parquet")\n# 1.18 s \xc2\xb1 80.9 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n\n# ------------------------------------------\n# - FORMAT .parquet using compression "brotli"\n\n# export\n%%timeit\ntest_data.to_parquet(folder_path + "\\\\AAPL.parquet", compression='brotli')\n# around 5min each loop. I did not run %%timeit on this one.\n\n# storage\n# AAPL.parquet exported with python using "brotli"\n# 29.425 KB    \n\n# import\n%%timeit\ntest_data = pd.read_parquet(folder_path + "\\\\AAPL.parquet")\n# 1.04 s \xc2\xb1 72 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n
Run Code Online (Sandbox Code Playgroud)\n

观察结果:

\n
    \n
  • Feather 似乎更适合轻量级数据,因为它写入和加载速度更快。实木复合地板具有更好的存储比率。
  • \n
  • Feather 库的支持和维护最初让我感到担忧,但是该文件格式与 pandas 具有良好的集成,我可以使用conda“zstd”压缩方法安装依赖项。
  • \n
  • 迄今为止最好的存储是带有“brotli”压缩的镶木地板,但导出需要很长时间。导出完成后,它具有良好的导入速度,但导入速度仍然比 Feather 慢 2.5 倍。
  • \n
\n

  • 不错的基准!有时量化事物非常有帮助。因此,我可能会改用 Feather——它似乎优于使用 Parquet + snappy 压缩,后者是 Parquet 的默认压缩方法,也是我当前正在使用的压缩方法。 (2认同)