开发中常见的数据格式
开发中常见的数据格式对比:Json/csv/pickle/parquet/feather 等
介绍
| CSV | JSON | Parquet | Avro | |
|---|---|---|---|---|
| 是否是列式 | 否 | 否 | 是 | 否 |
| 是否可压缩 | 是 | 是 | 是 | 是 |
| 是否可分拆 | 是 | 是 | 是 | 是 |
| 易于人们阅读 | 是 | 是 | 否 | 否 |
| 是否支持复杂数据结构 | 否 | 是 | 是 | 是 |
| 是否支持 schema 进化 | 否 | 否 | 是 | 是 |
- JSON(
JavaScript Object Notation,JavaScript 对象符号) 是一种轻量级数据交换格式,优点- JSON 支持层级结构,简化了在一个文档中存储关联数据和展示复杂关系的难度
- 大多数语言提供了简化 JSON 序列化的工具库,或内建支持 JSON 序列化/反序列化
- JSON 支持对象列表,帮助避免列表转换成关系型数据模型时的不确定性
- JSON 是一种被 NoSQL 数据库广泛使用的文件格式,比如 MongoDB,Couchbase 和 Azure Cosmos DB
- 目前大部分工具都内置支持 JSON
- JSON Lines(也称
newline-delimited JSON) 格式要求,是一种方便的结构化数据存储格式,一次处理一条记录- UTF-8 Encoding
- Each Line is a Valid JSON Value
- Line Separator is ‘\n’
- Suggested Conventions:
.jsonl- 压缩
.jsonl.gzor.jsonl.bz2
- 压缩
- CSV 文件(逗号分割不同列的值)常被使用普通文本格式的系统用作交换它们的表格数据
- 优点
- CSV 易于人们理解和手动编辑
- CSV 提供了简单易懂的信息格式
- 几乎所有现存的系统都可以处理 CSV
- CSV 易于实现和解析
- CSV 格式紧凑
- 缺点:
- CSV 只能处理扁平化的数据
- 不支持设置列的数据类型
- 没有标准方式表示二进制数据
- CSV 的导入问题(不区分
NULL和null引用 - 对特殊字符的支持很差
- 缺少标准
- 优点
- Excel 有最大行数
1048576的限制 Apache Avro是由 Hadoop 工作组于 2009 年发布。它是基于行的格式,并且具备高度的可分拆性- Apache arrow 是高性能的,用于内存计算的,列式数据存储格式,Python 库为 PyArrow
- hdf5 设计用于快速 I/O 处理和存储,它是一个高性能的数据管理套件,可以用于存储、管理和处理大型复杂数据
- jay Datatable 使用
.jay(二进制)格式,使得读取数据集的速度非常快 - python pickle 模块实现二进制协议,用于序列化和反序列化 Python 对象结构
Parquet
- Parquet 是一种专为大数据处理系统优化的一种高效、高性能的
列式存储文件格式,由 Twitter 和 Cloudera 联合开发,使用包括:Apache Spark、Apache Hive、Apache Flink 和 Presto - 特性:
- 列式存储格式:提高查询性能
- 高效压缩和编码:降低存储成本,高读写性能
- 支持的压缩方式:Snappy、Gzip 和 LZO 等
- 支持 Schema 更新
- 支持复杂数据类型
- Parquet 存储格式:
行组是 Parquet 文件中最大的数据单位- 一个 Parquet 文件可以有一个或多个行组
列和页列是 Parquet 中存储数据的主要结构页是 Parquet 中最小的数据单位,也是压缩和编码的基本单位,编码技术包括:字典编码(dictionary encoding)Run-length encoding(RLE)位打包(bit packing)
import pandas as pd
df = pd.read_csv('example.csv')
df.to_parquet('output.parquet')Feather
- Feather 是一种用于存储
数据帧的数据格式,高速读写压缩二进制文件- 它最初是为了
Python和R之间快速交互而设计的,初衷很简单,就是尽可能高效地完成数据在内存中转换的效率
- 它最初是为了
pip install feather-format
# 写
feather.write_dataframe(df, 'data.feather')
# 读
df = feather.read_dataframe('data.feather')
# pandas操作方式,写
df.to_feather(path, compression, compression_level)
# -- path:文件路径
# -- compression:是否压缩以及如何压缩,支持(zstd/uncompressde/lz4)三种方式
# -- compression_level:压缩水平(lz4不支持该参数)
# 加载
df = pd.read_feather('data.feather')
df = pd.read_feather(path='data.feather', columns=["a","b","c"])数据对比
- 依赖
pip3 install numpy===1.26.3 pandas===1.5.3 tables===3.9.2 fastparquet===2024.5.0 tabulate===0.9.0 -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com生成数据
对比测试源码
因机器性能问题,代码调整如下:
# generate_data.py
# row_num = int(1e7)
row_num = int(1e6)
# pk.py
repeat=3,
number=3,
$ ls -lhart
648M ... test_csv.csv测试结果
| method_name | file_size | write_time_mean | write_time_std | read_time_mean | read_time_std | method_describe | |
|---|---|---|---|---|---|---|---|
| 0 | CSV | 134.227 | 24.6678 | 1 | 3.97902 | 0 | 有索引的 CSV 文件格式 |
| 1 | CSV No Index | 127.657 | 24.653 | 0 | 3.51784 | 0 | 无索引的 CSV 文件格式 |
| 2 | CSV No Index (GZIP) | 50.8375 | 71.445 | 1 | 5.18191 | 0 | gzip 压缩格式的无索引 CSV |
| 3 | CSV No Index (BZ2) | 41.5492 | 62.0258 | 2 | 24.8727 | 0 | bz2 压缩格式的无索引 CSV |
| 4 | CSV No Index (ZIP) | 51.0893 | 48.492 | 1 | 5.39647 | 0 | zip 压缩格式的无索引 CSV |
| 5 | CSV No Index (XZ) | 45.2566 | 475.976 | 2 | 15.3339 | 0 | xz 压缩格式的无索引 CSV |
| 6 | JSON | 235.823 | 7.02122 | 0 | 45.8262 | 1 | json 序列化 |
| 7 | JSON(GZIP) | 66.8046 | 148.525 | 26 | 53.131 | 4 | gzip 压缩格式的 json 序列化 |
| 8 | JSON(BZ2) | 58.0655 | 70.432 | 5 | 87.0414 | 13 | bz2 压缩格式的 json 序列化 |
| 9 | JSON(ZIP) | 67.0171 | 80.8218 | 33 | 50.0922 | 1 | zip 压缩格式的 json 序列化 |
| 10 | JSON(XZ) | 39.0152 | 754.896 | 16 | 57.9088 | 1 | xz 压缩格式的 json 序列化 |
| 11 | Pickle | 96.6714 | 0.82614 | 0 | 0.50236 | 0 | 二进制序列化 Pickle |
| 12 | Pickle (GZIP) | 42.1024 | 102.536 | 4 | 1.55085 | 0 | gzip 压缩的序列化 Pickle |
| 13 | Pickle (BZ2) | 40.7265 | 38.1199 | 0 | 14.9511 | 0 | bz2 压缩的序列化 Pickle |
| 14 | Pickle (ZIP) | 42.7542 | 13.5322 | 0 | 2.16821 | 0 | zip 压缩的序列化 Pickle |
| 15 | Pickle (XZ) | 39.0732 | 170.84 | 15 | 9.66043 | 0 | xz 压缩的序列化 Pickle |
| 16 | HDF+不压缩 | 104.347 | 1.35462 | 0 | 0.94764 | 0 | 不压缩的 HDF5 格式 |
| 17 | HDF+浅压缩 | 57.1992 | 4.1234 | 0 | 1.47274 | 0 | 3 级压缩的 HDF5 格式 |
| 18 | HDF+深压缩 | 56.9294 | 4.86758 | 0 | 1.62728 | 0 | 6 级压缩的 HDF5 格式 |
| 19 | HDF+极限压缩 | 56.9287 | 4.77933 | 0 | 1.6117 | 0 | 9 级压缩的 HDF5 格式 |
| 20 | Parquet(snappy) | 49.9387 | 2.84817 | 0 | 1.51893 | 0 | snappy 压缩的 Parquet 格式 |
| 21 | Parquet(gzip) | 42.8362 | 17.0614 | 0 | 2.46068 | 0 | gzip 压缩的 Parquet 格式 |
| 22 | Parquet(brotli) | 39.5319 | 448.884 | 23 | 3.02525 | 0 | brotli 压缩的 Parquet 格式 |
结论
- 纯 CSV 文件在去除索引后,文件大小、读存速度均有改善,但不多
- JSON 序列化后的原始数据较大,压缩后的写入时间偏长(不推荐)
- 相比于 CSV 文件,Pickle 格式的原始文件大小会大一些,但是经过压缩后,最终的文反而更小
- XZ 算法的压缩率更高,相应的耗时略有增加
- BZ2 + Pickle 是所有方案中压缩率较高的一种方案,但相应的存储和读取耗时也都偏高,适合极致压缩的场景
- ZIP 虽然压缩率略低一些,但是存储耗时有显著优势
- Parquet 格式的存储,较好的压缩率,并且在存储和读取耗时有一定的优势(推荐)
最近更新
最新评论