File Formats
Columnar formats (Parquet, Arrow) dominate analytics pipelines: compress well, embed schema, and let readers load only needed columns.
Search across all documentation pages
Columnar formats (Parquet, Arrow) dominate analytics pipelines: compress well, embed schema, and let readers load only needed columns.
Quick-reference recipe card - copy-paste ready.
import pandas as pd
df = pd.read_csv("orders.csv", parse_dates=["ordered_at"])
df.to_parquet(
"lake/orders/dt=2025-01-15/data.parquet",
index=False,
compression="zstd",
)
# Read back selected columns
subset = pd.read_parquet("lake/orders", columns=["order_id", "revenue"], filters=[("dt", ">=", "2025-01-01")]When to reach for this:
import pandas as pd
import pyarrow as pa
import pyarrow.parquet as pq
from pathlib import Path
df = pd.DataFrame(
{
"order_id": [1, 2, 3],
"region": pd.Categorical(["East", "West", "East"]),
"revenue": [120.0, 340.0, 150.0],
"ordered_at": pd.to_datetime(["2025-01-01", "2025-01-02", "2025-01-03"], utc=True),
}
)
# pandas -> Arrow Table (zero-copy where possible)
table = pa.Table.from_pandas(df, preserve_index=False)
out_dir = Path("lake/orders/dt=2025-01-15")
out_dir.mkdir(parents=True, exist_ok=True)
pq.write_table(
table,
out_dir / "data.parquet",
compression="zstd",
use_dictionary=True,
)
# Read metadata without loading data
meta = pq.read_metadata(out_dir / "data.parquet")
print("rows:", meta.num_rows, "columns:", meta.num_columns)
# Column pruning read
loaded = pq.read_table(out_dir / "data.parquet", columns=["order_id", "revenue"])
print(loaded.to_pandas())What this demonstrates:
dt=YYYY-MM-DDkey=value/) emulate warehouse partitioning on files.| Format | Strength | Weakness |
|---|---|---|
| CSV | Human readable | No schema, fat, slow |
| JSON lines | Semi-structured events | Verbose, slow analytics |
| Parquet | Analytics standard | Not human readable |
| Arrow IPC | Fast local IPC | Not long-term archive |
import polars as pl
# Polars scan with projection pushdown
lf = pl.scan_parquet("lake/orders/**/*.parquet").select("order_id", "revenue")index column in Parquet. Fix: index=False always in pipelines.mergeSchema hides breaking changes. Fix: explicit schema registry and validation.datetime64[ns, UTC].| Alternative | Use When | Don't Use When |
|---|---|---|
| Delta/Iceberg/Hudi | ACID upserts on lake | Simple daily overwrite partitions |
| Avro | Kafka schema evolution | Analytics column pruning |
| ORC | Hive legacy clusters | Greenfield Python lake |
| SQLite DuckDB file | Local embedded analytics | Multi-writer object storage |
import duckdb
duckdb.sql("SELECT region, SUM(revenue) FROM read_parquet('lake/orders/**') GROUP BY 1")pyarrow.parquet.read_schema on two paths and compare.to_parquet uses pyarrow/fastparquet under hood.pq.write_table when you already have Arrow Table.pl.from_pandas / to_pandas zero-copy when dtypes align.Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 16, 2026