一、为什么使用 Parquet 和 Feather?
Parquet 和 Feather 是两种高效的列式数据存储格式,专为大数据分析和快速读写场景设计。相比 CSV,它们具有更好的压缩比和查询性能。
列式存储格式的主要优势:
| 特性 | CSV | Parquet | Feather |
|---|---|---|---|
| 存储格式 | 行式 | 列式 | 列式 |
| 读取速度 | 慢 | 很快 | 极快 |
| 写入速度 | 中 | 快 | 极快 |
| 压缩率 | 低 | 高 | 中 |
| 跨语言支持 | 通用 | Java/Python/R | Python/R |
定位说明:
-
Parquet 是 Apache 基金会的项目,被广泛用于大数据生态(Hadoop、Spark、DuckDB 等)。
-
Feather 是 Arrow 项目的原生实现,专注于极致的读写速度。
一句话选择: 长期存储、跨生态协作用 Parquet;临时缓存、进程间传递用 Feather。
二、Parquet 文件操作
1. 安装依赖
bash
pip install pyarrow fastparquet
PyArrow 和 FastParquet 都是 Parquet 的 Python 实现,PyArrow 是默认选项,FastParquet 在某些场景下更快。
两种引擎对比:
| 引擎 | 特点 | 推荐场景 |
|---|---|---|
pyarrow |
默认,生态完善 | 通用首选 |
fastparquet |
某些场景更快 | 性能敏感场景 |
2. 读取 Parquet 文件
python
import pandas as pd # 读取 Parquet 文件(默认使用 pyarrow) df = pd.read_parquet("data.parquet") # 指定使用特定的引擎 df = pd.read_parquet("data.parquet", engine="pyarrow") df = pd.read_parquet("data.parquet", engine="fastparquet") # 读取远程 Parquet 文件 df = pd.read_parquet("s3://bucket/data.parquet") # 读取文件的某些列(列裁剪,提升性能) df = pd.read_parquet("data.parquet", columns=["name", "age", "city"]) print(df.head())
列裁剪的优势: 列式存储的核心优势------只读取需要的列,不加载无关数据,大幅提升查询性能。
3. 写入 Parquet 文件
python
import pandas as pd # 准备测试数据 df = pd.DataFrame({ "id": range(1, 10001), "name": ["用户" + str(i) for i in range(1, 10001)], "age": [20, 25, 30, 35] * 2500, "city": ["北京", "上海", "广州", "深圳"] * 2500, "score": [round(i * 0.1, 2) for i in range(1, 10001)] }) # 写入 Parquet 文件(默认使用 pyarrow 引擎) df.to_parquet("data.parquet", index=False) # 指定压缩方式(snappy 速度快,gzip 压缩率高) df.to_parquet("data_snappy.parquet", compression="snappy", index=False) df.to_parquet("data_gzip.parquet", compression="gzip", index=False) df.to_parquet("data_none.parquet", compression=None, index=False) # 不压缩 # 查看文件大小 import os print("文件大小对比:") print(f"原始 CSV 预估: {len(df) * 50 / 1024 / 1024:.2f} MB") print(f"snappy 压缩: {os.path.getsize('data_snappy.parquet') / 1024 / 1024:.2f} MB") print(f"gzip 压缩: {os.path.getsize('data_gzip.parquet') / 1024 / 1024:.2f} MB") print(f"无压缩: {os.path.getsize('data_none.parquet') / 1024 / 1024:.2f} MB")
Parquet 压缩方式对比:
| 压缩方式 | 速度 | 压缩率 | 适用场景 |
|---|---|---|---|
snappy(默认) |
快 | 中 | 通用首选 |
gzip |
慢 | 高 | 存储优先 |
zstd |
中 | 高 | 平衡之选 |
None |
最快 | 无 | 临时文件 |
4. 测试不同引擎的写入性能
python
import pandas as pd import time # 测试不同引擎的写入性能 df = pd.DataFrame({ "id": range(1, 100001), "value": range(1, 100001) }) # pyarrow 引擎写入 start = time.time() df.to_parquet("test_pyarrow.parquet", engine="pyarrow", compression="snappy") print(f"pyarrow 写入时间: {time.time() - start:.3f}s") # fastparquet 引擎写入 start = time.time() df.to_parquet("test_fastparquet.parquet", engine="fastparquet", compression="snappy") print(f"fastparquet 写入时间: {time.time() - start:.3f}s")
建议: 先跑一遍测试,根据实际数据特征选择更快的引擎。
三、Feather 文件操作
Feather 是 Arrow 项目的 Python 实现,专注于极致的内存读写速度。
1. 安装依赖
bash
pip install pyarrow
2. 读取 Feather 文件
python
import pandas as pd # 读取 Feather 文件 df = pd.read_feather("data.feather") # 读取 v2 版本的 Feather 文件(更通用) df = pd.read_feather("data.feather", version="2.0") # 读取某些列 df = pd.read_feather("data.feather", columns=["name", "age"]) print(df.head())
Feather 版本说明:
| 版本 | 特点 |
|---|---|
| v1 | 早期版本,兼容性有限 |
| v2(推荐) | 基于 Arrow IPC 格式,更通用 |
3. 写入 Feather 文件
python
import pandas as pd # 准备测试数据 df = pd.DataFrame({ "id": range(1, 10001), "name": ["用户" + str(i) for i in range(1, 10001)], "value": [round(i * 0.1, 2) for i in range(1, 10001)] }) # 写入 Feather 文件 df.to_feather("data.feather") # LZ4 压缩(更快) df.to_feather("data_lz4.feather", compression="lz4") # ZSTD 压缩(压缩率更高) df.to_feather("data_zstd.feather", compression="zstd") # 查看文件大小 import os print(f"无压缩: {os.path.getsize('data.feather') / 1024:.2f} KB") print(f"LZ4: {os.path.getsize('data_lz4.feather') / 1024:.2f} KB") print(f"ZSTD: {os.path.getsize('data_zstd.feather') / 1024:.2f} KB")
Feather 压缩方式对比:
| 压缩方式 | 速度 | 压缩率 | 适用场景 |
|---|---|---|---|
| 无压缩(默认) | 最快 | 无 | 内存传递 |
lz4 |
快 | 中 | 平衡速度与体积 |
zstd |
中 | 高 | 存储优先 |
四、性能对比测试
下面用 100 万行数据对比 CSV、Parquet、Feather 三种格式的读写性能:
python
import pandas as pd import numpy as np import time import os import tempfile # 创建测试数据 np.random.seed(42) n_rows = 1000000 df = pd.DataFrame({ "id": range(n_rows), "category": np.random.choice(["A", "B", "C", "D"], n_rows), "value": np.random.randn(n_rows), "flag": np.random.choice([True, False], n_rows), "date": pd.date_range("2020-01-01", periods=n_rows, freq="1min") }) # 创建临时目录 with tempfile.TemporaryDirectory() as tmpdir: # CSV 写入 start = time.time() df.to_csv(f"{tmpdir}/data.csv", index=False) csv_write = time.time() - start start = time.time() df_csv = pd.read_csv(f"{tmpdir}/data.csv") csv_read = time.time() - start # Parquet 写入 start = time.time() df.to_parquet(f"{tmpdir}/data.parquet", index=False) pq_write = time.time() - start start = time.time() df_pq = pd.read_parquet(f"{tmpdir}/data.parquet") pq_read = time.time() - start # Feather 写入 start = time.time() df.to_feather(f"{tmpdir}/data.feather") feather_write = time.time() - start start = time.time() df_feather = pd.read_feather(f"{tmpdir}/data.feather") feather_read = time.time() - start # 输出结果 print(f"{'格式':<10} {'写入时间':<12} {'读取时间':<12} {'文件大小':<12}") print("-" * 50) print(f"{'CSV':<10} {csv_write:.3f}s{'':<5} {csv_read:.3f}s{'':<5} {os.path.getsize(f'{tmpdir}/data.csv')/1024/1024:.2f}MB") print(f"{'Parquet':<10} {pq_write:.3f}s{'':<5} {pq_read:.3f}s{'':<5} {os.path.getsize(f'{tmpdir}/data.parquet')/1024/1024:.2f}MB") print(f"{'Feather':<10} {feather_write:.3f}s{'':<5} {feather_read:.3f}s{'':<5} {os.path.getsize(f'{tmpdir}/data.feather')/1024/1024:.2f}MB")
典型测试结果(100 万行 × 5 列):
| 格式 | 写入时间 | 读取时间 | 文件大小 |
|---|---|---|---|
| CSV | 约 3-5s | 约 1-2s | 约 50-60 MB |
| Parquet | 约 0.3-0.5s | 约 0.1-0.2s | 约 10-15 MB |
| Feather | 约 0.1-0.2s | 约 0.05-0.1s | 约 20-25 MB |
测试说明: 具体数值因硬件和数据特征而异,但量级关系基本一致------Parquet 和 Feather 比 CSV 快一个数量级,文件体积小数倍。
性能差异原因:
| 原因 | 说明 |
|---|---|
| 列式存储 | 只读需要的列,减少 IO |
| 二进制格式 | 无需文本解析,直接映射内存 |
| 高效压缩 | 同列数据相似度高,压缩率高 |
| 类型信息 | 保留 dtype,无需推断 |
五、使用场景与选择建议
| 场景 | 推荐格式 | 原因 |
|---|---|---|
| 大数据分析 | Parquet | 高压缩比,列式查询快,生态广泛 |
| Python/R 数据传递 | Feather | 极快读写,Arrow 原生支持 |
| Spark/Hadoop 集成 | Parquet | 大数据生态标准格式 |
| 数据备份/归档 | Parquet | 压缩率高,支持 schema 演进 |
| 临时数据缓存 | Feather | 读写最快 |
| 与 Excel 用户交换 | CSV | 通用可读 |
选择决策流程:
六、格式对比速查表
| 对比项 | CSV | Parquet | Feather |
|---|---|---|---|
| 存储格式 | 行式文本 | 列式二进制 | 列式二进制 |
| 读取速度 | 慢 | 很快 | 极快 |
| 写入速度 | 中 | 快 | 极快 |
| 压缩率 | 低 | 高 | 中 |
| 文件大小 | 大 | 很小 | 中 |
| 跨语言 | 通用 | Java/Python/R | Python/R |
| 人工可读 | ✅ | ❌ | ❌ |
| 列裁剪 | ❌ | ✅ | ✅ |
| 依赖库 | 内置 | pyarrow | pyarrow |
| 推荐场景 | 交换 | 存储分析 | 临时缓存 |
七、读写流程图
八、常用参数速查
| 需求 | Parquet | Feather |
|---|---|---|
| 基础读取 | pd.read_parquet("f.parquet") |
pd.read_feather("f.feather") |
| 指定引擎 | engine="pyarrow" |
--- |
| 读取部分列 | columns=["a","b"] |
columns=["a","b"] |
| 基础写入 | df.to_parquet("f.parquet") |
df.to_feather("f.feather") |
| 不写索引 | index=False |
默认不写索引 |
| 高压缩 | compression="gzip" |
compression="zstd" |
| 快压缩 | compression="snappy" |
compression="lz4" |
| 不压缩 | compression=None |
默认无压缩 |
| 读取远程 | s3://bucket/f.parquet |
--- |
九、常见问题与注意事项
1. 读取 Parquet 报错
确保安装了 pyarrow 或 fastparquet:
bash
pip install pyarrow
2. 文件损坏
写入时确保数据完整写入磁盘,建议写入后验证文件可读性:
python
df.to_parquet("data.parquet", index=False) # 写入后验证 df_check = pd.read_parquet("data.parquet") assert len(df_check) == len(df), "数据行数不一致"
3. 版本兼容
不同版本的 Parquet 可能存在兼容性问题,建议在项目中使用固定版本。
4. Feather 版本选择
python
# 写入 v2 版本(推荐,更通用) df.to_feather("data.feather") # 读取时指定版本 df = pd.read_feather("data.feather", version="2.0")
十、常见问题排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
ImportError: pyarrow |
未安装引擎 | pip install pyarrow |
ArrowInvalid |
文件格式损坏 | 重新写入,检查磁盘 |
| 读取列名报错 | columns 拼写错误 |
检查列名是否存在于文件 |
| 文件比 CSV 还大 | 未启用压缩 | 设置 compression="snappy" |
| 写入速度慢 | 压缩率过高 | 改用 snappy 或 lz4 |
| S3 读取失败 | 未配置凭证 | 配置 AWS 凭证或改用本地 |
| 数据类型丢失 | 版本不兼容 | 固定 pyarrow 版本 |
十一、小结
本篇你掌握了 Parquet 与 Feather 两种高性能列式存储格式:
-
格式定位:Parquet 适合大数据生态与长期存储,Feather 适合极致速度与临时缓存。
-
Parquet 读写 :
read_parquet/to_parquet,支持pyarrow与fastparquet引擎。 -
Feather 读写 :
read_feather/to_feather,推荐 v2 版本。 -
压缩方式 :Parquet 用
snappy、gzip、zstd;Feather 用lz4、zstd。 -
列裁剪 :
columns参数只读取需要的列,提升性能。 -
性能对比:百万行数据下,Parquet 和 Feather 比 CSV 快一个数量级,文件小数倍。
-
选型建议:大数据分析用 Parquet,数据传递用 Feather,人工交换用 CSV。
数据量增长后,选择合适的存储格式能显著提升效率。下一篇我们将学习 Pandas 数据清洗,掌握缺失值、重复值、异常值的系统处理方法。