大数据文件格式:Parquet 与 Feather
本教程共 54 篇 · 第 15 篇 · 更新于 2026-08-11 · 约 8 分钟阅读
本节目标:搞懂 Parquet、Feather、HDF5、Pickle 这几种高效存储格式的区别,学会用 pandas 读写它们,告别又大又慢的 CSV。
CSV 的痛点
前面几节我们一直在用 CSV 和 Excel。数据量小的时候没问题,但文件一大,CSV 的毛病就藏不住了:
- 纯文本存储,同样的数据占的空间大
- 每次读写都要做文本解析,速度慢
- 数据类型信息(某列是整数还是日期)不会跟着文件走,每次读进来都要重新推断
这时候就需要专门的存储格式。pandas 里最常用的有四种:Parquet、Feather、HDF5 和 Pickle。它们都是二进制格式,速度快、体积小,代价是记事本打开是乱码——它们是给程序读的,不是给人看的。
列式存储是怎么回事
先说个概念:CSV 是行式存储,一行数据挨着写在一起;Parquet 和 Feather 是列式存储,一列数据挨着写在一起。
假设有三行数据(id、姓名、年龄):
- 行式存储的磁盘顺序:第 1 行的三个值、第 2 行的三个值、第 3 行的三个值
- 列式存储的磁盘顺序:所有 id、所有姓名、所有年龄
这个区别带来两个好处:
- 压缩率高。同一列数据类型一样、数值往往接近,压缩算法发挥空间大
- 可以只读需要的列。50 列的宽表你只用 3 列,列式格式就只读那 3 列,省时间也省内存
查询”所有人的年龄”时,列式存储只需要读年龄那一列的数据块,行式存储要把整个文件从头扫到尾。数据越多,差距越明显。
Parquet:大数据生态的通用格式
Parquet 是 Apache 基金会的项目,Hadoop、Spark、DuckDB 都在用,是跨语言、跨工具交换数据的标准格式之一。如果你的数据以后要交给其他工具处理,选 Parquet 基本不会错。
读写 Parquet 需要安装 pyarrow(pandas 的默认引擎):
pip install pyarrow
import pandas as pd
import numpy as np
df = pd.DataFrame({
"姓名": ["张三", "李四", "王五"],
"年龄": [25, 30, 28],
"得分": [88.5, 92.0, 79.5],
})
# 写入 Parquet 文件
df.to_parquet("成绩.parquet", index=False)
# 读回来
df2 = pd.read_parquet("成绩.parquet")
print(df2)
几个常用参数:
engine:指定引擎,"pyarrow"或"fastparquet",默认自动选择columns:读取时只加载指定列,宽表场景能省大量内存index:写入时是否保存索引,默认非默认索引会被存成额外列compression:压缩算法,默认 snappy(快),可换 gzip(更小)
import pandas as pd
import numpy as np
# 只读两列,速度更快、内存更省
df3 = pd.read_parquet("成绩.parquet", columns=["姓名", "年龄"])
# 指定压缩方式再写一份
df = pd.DataFrame({"姓名": ["张三", "李四", "王五"], "年龄": [25, 30, 28]})
df.to_parquet("成绩_snappy.parquet", compression="snappy", index=False)
Tip
to_parquet还有partition_cols参数,可以按某列的值把数据拆到多个子目录(分区存储)。数据再大一个量级时再用,入门阶段了解即可。
Feather:追求极致的读写速度
Feather 是 Arrow 项目的原生格式,设计目标就一个:极致的读写速度。它在 Python 和 R 之间交换数据特别方便,同样由 pyarrow 实现。
import pandas as pd
import numpy as np
df = pd.DataFrame({"姓名": ["张三", "李四", "王五"], "年龄": [25, 30, 28]})
# 写入 Feather
df.to_feather("成绩.feather")
# 读回来
df4 = pd.read_feather("成绩.feather")
print(df4)
Feather 的压缩参数:默认 "lz4"(快),也可选 "zstd"(更小)或 "uncompressed"。写入时可用 version 参数指定文件版本(1 或 2),一般用默认即可。
两个限制要知道:
- 不保存索引,自定义索引会直接报错,需要先
reset_index() - 不支持重复的列名和非字符串列名
HDF5:一个文件装多张表
HDF5 格式的特点是文件内部有层级结构,一个 .h5 文件里可以放多份数据,每份用一个 key 区分,用起来像字典。读写依赖 PyTables 库:
pip install tables
import pandas as pd
import numpy as np
df = pd.DataFrame({"姓名": ["张三", "李四", "王五"], "年龄": [25, 30, 28]})
# 写入,key 相当于给这份数据起名字
df.to_hdf("成绩.h5", key="学生成绩", format="table")
# 读取时指定同一个 key
df5 = pd.read_hdf("成绩.h5", key="学生成绩")
print(df5)
format 参数有两种,取舍很明确:
| 格式 | 写入速度 | 追加 | 条件查询 |
|---|---|---|---|
| fixed(默认) | 最快 | 不支持 | 不支持 |
| table | 较慢 | 支持 | 支持 |
import pandas as pd
import numpy as np
df = pd.DataFrame({"姓名": ["张三", "李四", "王五"], "年龄": [25, 30, 28]})
# 往同一个 key 里追加新数据
df.to_hdf("成绩.h5", key="学生成绩", format="table", mode="a", append=True)
# table 格式支持按条件读取
result = pd.read_hdf("成绩.h5", key="学生成绩", where=["年龄 > 28"])
print(result)
WarningHDF5 默认的 fixed 格式写入极快,但写好就不能再改。要追加数据,必须用 format=“table”。
Pickle:Python 专用的一键打包
Pickle 是 Python 自带的序列化格式,任何 pandas 对象都能存,读取时类型原样保留。还支持 gzip、bz2、xz、zstd 压缩,按文件后缀自动判断:
import pandas as pd
import numpy as np
df = pd.DataFrame({"姓名": ["张三", "李四", "王五"], "年龄": [25, 30, 28]})
df.to_pickle("成绩.pkl")
df6 = pd.read_pickle("成绩.pkl")
print(df6)
适合做项目内部缓存:今天算完的结果存下来,明天直接读,不用重新算。要注意两点:read_pickle 只保证向后兼容几个小版本,长期存档别用它;加载不可信来源的 pickle 文件可能执行恶意代码。
Warning网上下载的 pickle 文件不要乱读。自己项目内部缓存随便用,但格式版本兼容性有限,需要长期保存的数据优先考虑 Parquet。
怎么选
| 场景 | 推荐格式 | 理由 |
|---|---|---|
| 大数据分析、跨工具交换 | Parquet | 压缩率高、生态广、可列裁剪 |
| Python 与 R 之间快速传数据 | Feather | 读写最快 |
| 一个文件存多张表 | HDF5 | 支持 key、追加和查询 |
| 自己项目内部临时缓存 | Pickle | 最省事,类型无损 |
| 给别人看、进 Excel | CSV | 通用,但只适合小数据 |
动手对比一下文件大小
光看表格不如自己跑一遍。同一份数据存成不同格式,用 os.path.getsize 看体积:
import pandas as pd
import numpy as np
import os
df = pd.DataFrame({"id": range(10000), "value": np.random.randn(10000)})
df.to_csv("对比.csv", index=False)
df.to_parquet("对比.parquet", index=False)
df.to_feather("对比.feather")
df.to_pickle("对比.pkl")
for name in ["对比.csv", "对比.parquet", "对比.feather", "对比.pkl"]:
print(name, os.path.getsize(name), "字节")
在自己机器上跑一遍,CSV 通常是其他格式的好几倍。感受过差距,选型就有数了。
一句话总结:跟别人交换数据用 Parquet,自己内部追求速度用 Feather,多表共存用 HDF5,临时缓存用 Pickle。
常见问题速答
读 Parquet 报 ImportError? 多半是没装 pyarrow。pip install pyarrow 装完再试。
写 Feather 报错? 大概率是 DataFrame 用了自定义索引。Feather 不保存索引,先 df.reset_index() 把索引导入普通列,或者 reset_index(drop=True) 丢掉索引。
CSV 还能用吗? 能。小文件、给别人看、要进 Excel 的场景,CSV 依然是最通用、最不容易出错的格式。这篇教的高效格式是给”数据量大、程序对程序”的场景用的。