Skip to main content

polars_readstat

Polars plugin for SAS (.sas7bdat), Stata (.dta), and SPSS (.sav/.zsav) files.

The Python package wraps the Rust core in polars_readstat_rs and exposes a Polars-first API. The project includes cross-library parity tests and roundtrip checks to reduce regressions.

The Rust engine is generally faster for many workloads, but performance varies by file shape and options. If you need the legacy C/C++ engine, use version 0.11.1 (see the prior version).

Why use this?

  • In project benchmarks, the new Rust-backed engine is typically faster than pandas/pyreadstat on large SAS/Stata files, especially for subset/filter workloads.
  • It avoids the older C/C++ toolchain complexity and ships as standard Python wheels.
  • API is Polars-first (scan_readstat, read_readstat, write_readstat, write_sas_csv_import).
  • Because scan_readstat returns a Polars LazyFrame, column selection and row limits are pushed into the reader — only the data you actually need is read from disk.

Install

pip install polars-readstat

Core API

1) Lazy scan

import polars as pl
from polars_readstat import scan_readstat

lf = scan_readstat("/path/file.sas7bdat")
#   do something
df = lf.collect()

df = (
    scan_readstat("/path/file.sas7bdat")
    .select(["SERIALNO", "AGEP"])   # column pushdown — only these columns are read
    .head(1_000)                    # row limit is pushed down too
    .filter(pl.col("AGEP") >= 18)   # filters applied to streamed batches to avoid loading full file into memory
    .collect()
)

2) Getting metadata

from polars_readstat import ScanReadstat

reader = ScanReadstat(path="/path/file.sav")
schema = reader.schema           # polars.Schema
metadata = reader.metadata       # dict with file info and per-column details
lf = reader.df                   # LazyFrame — same as calling scan_readstat(path)

metadata is a dict with a variables (SPSS/Stata) or columns (SAS) list. Each entry includes:

  • "name" — column name
  • "label" — variable label (description), if present
  • "value_labels" — dict mapping coded values to label strings, if present

Polars lazy evaluation

scan_readstat returns a LazyFrame, so Polars can push operations into the reader before any data is loaded:

Read only specific columns — column selection is pushed into the reader; unselected columns are never read from disk:

lf = scan_readstat("file.sav")
df = lf.select(["id", "age", "income"]).collect()

Read the first N rows — head() / limit() stops the reader after N rows, so you never load the full file:

df = scan_readstat("file.sas7bdat").head(1000).collect()

Filter rows — filters are applied in Polars after reading, but still benefit from column pushdown if combined with .select():

df = scan_readstat("file.dta").select(["id", "age"]).filter(pl.col("age") >= 18).collect()

The benchmark numbers below reflect these optimizations — the large "Subset: True" speedups come from column pushdown.

3) Write (Experimental)

Writing support is experimental and compatibility varies across tools. Stata roundtrip tests are included; SPSS roundtrip coverage is limited. Please report issues.

from polars_readstat import write_readstat, write_sas_csv_import

write_readstat(df, "/path/out.dta")
write_readstat(df, "/path/out.sav")
write_sas_csv_import(df, "/path/out/sas_bundle", dataset_name="my_data")

write_readstat supports Stata (dta) and SPSS (sav).
Use write_sas_csv_import for SAS-ingestible output (.csv + .sas import script). Binary .sas7bdat writing is not currently supported.

Docs

View the docs at https://jrothbaum.github.io/polars_readstat/ for more information on the options you can pass to the scan and write functions.

Benchmark

Benchmarks compare four scenarios: 1) load the full file, 2) load a subset of columns (Subset:True), 3) filter to a subset of rows (Filter: True), 4) load a subset of columns and filter to a subset of rows (Subset:True, Filter: True).

Benchmark context:

  • Machine: AMD Ryzen 7 8845HS (16 cores), 14 GiB RAM, Linux Mint 22
  • Storage: external SSD
  • Last run: May 14, 2026 — polars-readstat v0.17.0 vs pandas and pyreadstat
  • Method: wall-clock timings via Python time.time()

Compared to Pandas and Pyreadstat (using read_file_multiprocessing for parallel processing in Pyreadstat)

SAS

all times in seconds (speedup relative to pandas in parenthesis below each)

Library Full File Subset: True Filter: True Subset: True, Filter: True
polars_readstat 0.55
(3.9×)
0.07
(28.4×)
1.46
(2.0×)
0.08
(39.4×)
pandas 2.16 1.99 2.93 3.15
pyreadstat 6.76
(0.3×)
1.64
(1.2×)
7.86
(0.4×)
2.18
(1.4×)

Stata

all times in seconds (speedup relative to pandas in parenthesis below each)

Library Full File Subset: True Filter: True Subset: True, Filter: True
polars_readstat 0.16
(7.3×)
0.10
(11.7×)
0.18
(7.3×)
0.09
(13.8×)
pandas 1.17 1.17 1.31 1.24
pyreadstat 5.48
(0.2×)
4.57
(0.3×)
5.67
(0.2×)
7.69
(0.2×)

SPSS

all times in seconds (speedup relative to pandas in parenthesis below each)

Library Full File Subset: True Filter: True Subset: True, Filter: True
polars_readstat 1.09
(62.5×)
0.15
(3.9×)
1.10
(62.4×)
0.15
(3.9×)
pandas 68.12 0.59 68.67 0.59
pyreadstat 3.06
(22.3×)
1.15
(0.5×)
7.09
(9.7×)
1.23
(0.5×)

zsav

all times in seconds (speedup relative to pandas in parenthesis below each)

Library Full File Subset: True Filter: True Subset: True, Filter: True
polars_readstat 3.97
(5.9×)
1.04
(2.1×)
4.77
(4.7×)
1.15
(2.0×)
pandas 23.47 2.20 22.40 2.29

Detailed benchmark notes and dataset descriptions are in BENCHMARKS.md.

Tests run

Test coverage includes:

  • Cross-library comparisons on the pyreadstat and pandas test data, checking results against polars-readstat==0.11.1, pyreadstat, and pandas.
  • Stata/SPSS read/write roundtrip tests.
  • Large-file read/write benchmark runs on real-world data (results below).

If you want to run the same checks locally, helper scripts and tests are in scripts/ and tests/.

Release files for polars-readstat 0.21.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for polars-readstat 0.21.0
File
polars_readstat-0.21.0-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
polars_readstat-0.21.0-cp39-abi3-manylinux_2_28_x86_64.whl CPython 3.9 abi3 Linux glibc 2.28+ x86-64 Details
polars_readstat-0.21.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
polars_readstat-0.21.0-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
polars_readstat-0.21.0-cp39-abi3-macosx_10_15_x86_64.whl CPython 3.9 abi3 macOS 10.15+ x86-64 Details

Total release size: 96.0 MB

Release files / polars_readstat-0.21.0-cp39-abi3-win_amd64.whl

Download URL polars_readstat-0.21.0-cp39-abi3-win_amd64.whl
Size 21.1 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
f8219b82c3ef429d8ecbeb286a012aace73bbfad8873ca6dbb6f90e2558d49b9
BLAKE2b-256 checksum
How to use checksums
769880513b54ab847cb9c9b5abe4c54ec3b1448182036f0cdfeff4dc152ffa92
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / polars_readstat-0.21.0-cp39-abi3-manylinux_2_28_x86_64.whl

Download URL polars_readstat-0.21.0-cp39-abi3-manylinux_2_28_x86_64.whl
Size 19.5 MB
Tags CPython 3.9 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
00fe275be4c682938b82b2e9fb759fb82dec0e6f2b981404bbf302e77c4ceacf
BLAKE2b-256 checksum
How to use checksums
11f0830c8d1bcccc1187d43259b905dabd38d03ee435e8b1ff0a1c2ef6b72b6f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / polars_readstat-0.21.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL polars_readstat-0.21.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 19.5 MB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
2398ba976d6888be963fa7b000584ebe68f57bbf9be3f3a1daa479a02464534f
BLAKE2b-256 checksum
How to use checksums
1af82d31f75d5bd441da07fd3c1f40218843be14ad96d8d0902de435984d15a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / polars_readstat-0.21.0-cp39-abi3-macosx_11_0_arm64.whl

Download URL polars_readstat-0.21.0-cp39-abi3-macosx_11_0_arm64.whl
Size 17.2 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
c2c58663fd303317e4a6d05e0c75569318642a2c910f69a3dcb3e24f32ff466a
BLAKE2b-256 checksum
How to use checksums
9c2b487756c1593bd4fb3576ba71496829185decd8da64ab192a0458f8b284b8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / polars_readstat-0.21.0-cp39-abi3-macosx_10_15_x86_64.whl

Download URL polars_readstat-0.21.0-cp39-abi3-macosx_10_15_x86_64.whl
Size 18.8 MB
Tags CPython 3.9 abi3 macOS 10.15+ x86-64
SHA-256 checksum
How to use checksums
2e451dd90b8a4d47ea6f74c11469e533864acf7df29518276d5db4fde01bf256
BLAKE2b-256 checksum
How to use checksums
47a9050582654ebb93808cf1fa29749f299bbc67867f17e9c4d0375e945f283c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.23.0

5 release files

0.21.1

5 release files

This release

0.21.0 This release

5 release files

0.20.2

5 release files

0.20.1

5 release files

0.19.4

5 release files

0.19.3

5 release files

0.19.2

5 release files

0.19.1

5 release files

0.19.0

5 release files

0.18.1

5 release files

0.17.0

5 release files

0.16.1

5 release files

0.15.0

5 release files

0.14.8

5 release files

0.14.7

5 release files

0.14.6

5 release files

0.14.5

5 release files

0.13.0

5 release files

0.12.4

5 release files

0.12.3

5 release files

0.12.2

5 release files

0.12.1

5 release files

0.12.0

5 release files

0.11.1

5 release files

0.11.0

5 release files

0.9.0

4 release files

0.8.2

4 release files

0.8.1

4 release files

0.7.2

4 release files

0.7.1

4 release files

0.7.0

4 release files

0.6.1

4 release files

0.6.0

4 release files

0.5.1

4 release files

0.4.2

4 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page