AI & Machine Learning

Parquet vs CSV: Why Data Scientists Should Care

Python Docker RAG AWS Cloud Databases Pandas Data Science Local AI Feature Engineering
1,587 words Includes Code

Parquet vs CSV: Why Data Scientists Should Care

Key Takeaway: For analytical and data science workflows, Apache Parquet is usually superior to CSV in storage efficiency, read speed, schema preservation, and query performance. CSV remains valuable for human-readable interchange, but it is rarely the best choice for performance-critical data processing.

Every data scientist has opened a CSV file. It is the universal format — every tool reads it, every person can open it, and every database exports to it. But when performance matters, CSV is often the wrong choice.

This article compares CSV and Parquet using real benchmark measurements, explains why the differences exist, and shows when each format is appropriate.

Featured image: articles/080/featured-image.svg

What Is CSV?

CSV (Comma-Separated Values) is a plain-text format where each row is a line and values are separated by commas.

id,category,value_a,quantity,flag
0,alpha,345.67,42,true
1,beta,892.12,17,false
2,gamma,123.45,88,true

Advantages:

  • Human-readable
  • Universal tool support
  • No binary encoding — easy to inspect, diff, and email
  • Simple to generate

Disadvantages:

  • No schema — everything is text
  • No compression — repeats are stored in full
  • No column selection — the entire file must be read
  • Text parsing overhead for every numeric value
  • Data types are lost on reload

What Is Parquet?

Apache Parquet is a columnar binary format designed for analytical workloads. Instead of storing data row by row, it stores each column together, applies compression per-column, and embeds schema information.

┌──────────────────────────────────────┐
│           Parquet File               │
│  ┌─────────┐  ┌─────────┐  ┌──────┐ │
│  │ Column  │  │ Column  │  │  ... │ │
│  │  Store  │  │  Store  │  │      │ │
│  └─────────┘  └─────────┘  └──────┘ │
│         Schema + Metadata            │
│       Compression per column         │
│        Row groups for I/O            │
└──────────────────────────────────────┘

Advantages:

  • Columnar storage — reads only the columns you need
  • Built-in compression — Snappy, Zstd, Gzip, LZ4
  • Schema and data types preserved
  • Predicate pushdown — filters applied before reading
  • Optimized for analytical queries

Disadvantages:

  • Binary — not human-readable
  • Requires library support (PyArrow, FastParquet)
  • Slightly more complex for simple interchange

The Benchmark: Real Numbers

All numbers in this article come from a single reproducible benchmark run on August 2026 using a synthetic dataset of 500,000 rows × 8 columns.

Environment:

ComponentVersion
Python3.13.14
pandas3.0.5
pyarrow25.0.1
Dataset500,000 rows × 8 columns

Diagrams: articles/080/benchmark-results.svg

File Size

FormatSizeRatio
CSV36.78 MB1.0×
Parquet (Snappy)8.06 MB4.6× smaller
Parquet (Zstd)4.29 MB8.6× smaller

Parquet with Zstd compression produced a file 8.6× smaller than CSV. This is not just disk savings — smaller files mean faster I/O, less network transfer, and lower storage costs.

Write Speed

FormatTime
CSV1,202.8 ms
Parquet (Snappy)192.0 ms
Parquet (Zstd)156.1 ms

Parquet writing was significantly faster in this benchmark. PyArrow's columnar encoding avoids the per-row text formatting overhead that CSV requires.

Read Full Dataset

FormatTimeSpeedup
CSV528.0 ms1.0×
Parquet (Snappy)143.6 ms3.7×
Parquet (Zstd)30.3 ms17.4×

Reading the full dataset with Parquet (Snappy) was 3.7× faster than CSV. The Zstd-compressed Parquet was even faster at decompression due to better CPU efficiency in modern pyarrow.

Important: Benchmark results vary by hardware, dataset characteristics, Python version, library version, and OS. These numbers are representative of the comparison, not absolute performance guarantees.

Column Selection (2 of 8 Columns)

FormatTimeSpeedup
CSV209.8 ms1.0×
Parquet (Snappy)13.2 ms15.9×

This is where Parquet's columnar design shines brightest. When you only need 2 of 8 columns, Parquet skips the other 6 entirely — they are never read from disk. CSV must parse every line to extract the columns you want.

Row Filtering (Predicate Pushdown)

FormatTimeRows Returned
CSV (load + filter)541.7 ms99,881
Parquet (pushed down)38.5 ms99,881

Parquet's predicate pushdown applies the filter category == 'alpha' at the storage level, reading only matching row groups. The result: 14.1× faster filtering with identical output.

Group-By Aggregation

FormatTimeSpeedup
CSV523.4 ms1.0×
Parquet28.3 ms18.5×

Reading only the needed columns from Parquet and computing the group-by aggregation was 18.5× faster than loading the full CSV and then aggregating.

Schema Preservation

This difference is subtle but critical for production systems.

# Writing with optimized dtypes
df['category'] = df['category'].astype('category')
df['region']   = df['region'].astype('category')
df.to_parquet('data.parquet')

# Reading back — types preserved
df = pd.read_parquet('data.parquet')
print(df['category'].dtype)  # category ✓

# CSV loses this
df.to_csv('data.csv')
df = pd.read_csv('data.csv')
print(df['category'].dtype)  # object ✗

Parquet embeds schema metadata. When you save a column as category, it loads as category. CSV always reloads as text — you must manually re-apply type conversions every time.

When to Use CSV

CSV is still the right choice when:

  • Human readability matters — debugging, auditing, data sharing with non-technical users
  • Simple interchange — moving data between tools that may not share Parquet support
  • Small datasets — where the performance difference is negligible
  • Log files and exports — append-friendly, easy to inspect
  • APIs and data feeds — many systems default to CSV for simplicity

When to Use Parquet

Parquet is the better choice when:

  • Analytical queries — aggregation, filtering, grouping over large datasets
  • Selective column access — reading a subset of columns from wide datasets
  • Repeated reads — the one-time write cost pays off across many reads
  • Pipeline storage — intermediate files between ETL steps
  • Data lakes and warehouses — Parquet is the standard format in Spark, DuckDB, BigQuery, and S3-based data lakes
  • Type-sensitive workflows — when preserving dtypes matters
  • Cost-sensitive cloud storage — 8.6× less storage means 8.6× less cost per GB

How Parquet Achieves These Gains

The performance differences are not magic. They come from specific design decisions:

FeatureCSVParquet
StorageRow-based, plain textColumn-based, binary
CompressionNone (or gzip on whole file)Per-column (Snappy, Zstd, Gzip)
SchemaNoneEmbedded in file metadata
Column selectionRead all columnsRead only selected columns
Row filteringRead all rows, filter in PythonPredicate pushdown at storage level
Data typesEverything is textNative int, float, bool, category, string
MetadataNoneRow counts, column stats, encoding info

The Conversion Workflow

If you have CSV files and want to switch to Parquet, the conversion is straightforward:

import pandas as pd

# Read CSV
df = pd.read_csv('large_dataset.csv')

# Optimize dtypes where helpful
df['category'] = df['category'].astype('category')
df['region']   = df['region'].astype('category')

# Write Parquet
df.to_parquet('large_dataset.parquet', engine='pyarrow', compression='zstd')

# Verify
df_check = pd.read_parquet('large_dataset.parquet')
print(f'CSV:     {df.memory_usage(deep=True).sum() / 1e6:.1f} MB in memory')
print(f'Parquet: {os.path.getsize("large_dataset.parquet") / 1e6:.1f} MB on disk')

For very large files, use chunked reading:

import pandas as pd
import os

chunks = pd.read_csv('huge.csv', chunksize=100_000)
for i, chunk in enumerate(chunks):
    chunk.to_parquet(f'part_{i:04d}.parquet', engine='pyarrow')

The Parquet files can later be read individually or together with a glob pattern.

Parquet in the Data Science Ecosystem

Parquet is not a niche format. It is the default or preferred format for:

  • Apache Spark — native Parquet support for distributed processing
  • DuckDB — direct Parquet querying without loading into memory
  • Polars — optimized Parquet reader/writer
  • BigQuery, Snowflake, Redshift — all support Parquet ingestion
  • AWS S3, Azure Blob, GCS — standard format for data lakes
  • Hugging Face Datasets — Parquet is the default storage format
  • Dask — parallel Parquet reading and writing

The In-Memory Difference

Once data is loaded into a pandas DataFrame, both formats produce similar memory usage — the DataFrame lives in RAM regardless of its source format. In our benchmark:

SourceDataFrame Memory
CSV reload48.4 MB
Parquet reload46.5 MB

The small difference comes from Parquet preserving category dtype, which is more memory-efficient than object columns. The bigger advantage of Parquet is on disk and in I/O speed — not in RAM after loading.

Common Questions

Is Parquet always faster than CSV?

No. For very small files (under a few MB), the difference is negligible and CSV may be faster due to simpler parsing. Parquet's advantages grow with file size, column count, and analytical query complexity.

Can I still use CSV alongside Parquet?

Absolutely. Many pipelines use CSV for ingestion and export, and Parquet for internal storage and analytics. Convert once, benefit many times.

What about JSON?

JSON is even less efficient than CSV for tabular data because of repeated key names and nested structures. For tabular analytics, Parquet is almost always better. JSON excels for semi-structured or document-oriented data.

Does Parquet work with streaming data?

Parquet files are designed for batch writes. For streaming, you can write Parquet files in regular intervals (e.g., every 5 minutes or every N rows) or use other formats like Avro for true streaming.

Best Practices

Parquet Best Practices:
  • Use zstd compression for best size/speed ratio
  • Optimize dtypes before writing — category columns compress better
  • Choose row group size based on your query patterns (default is usually fine)
  • Use predicate filters when reading: pd.read_parquet('f.pq', filters=[...])
  • Store metadata columns (timestamps, versions) alongside your data

Further Reading

Conclusion

CSV is simple, universal, and human-readable. It remains the best choice for quick data interchange and debugging.

But for analytical workloads — filtering, aggregation, column selection, repeated reads — Parquet is demonstrably superior. Our benchmark showed 8.6× smaller files, 3.7× faster full reads, and 18.5× faster aggregation on a 500K-row dataset.

The best practice is simple: use CSV for sharing and human inspection. Use Parquet for everything else.

Try it yourself: Convert one of your CSV files to Parquet with df.to_parquet('data.parquet', compression='zstd') and compare the file sizes and read times. The difference speaks for itself.

💬 Discuss on BestWordz Community

Join the conversation about Python, Docker, RAG on the BestWordz Community forum.

Visit Forum →