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.1

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.1
File
polars_readstat-0.21.1-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
polars_readstat-0.21.1-cp39-abi3-manylinux_2_28_x86_64.whl CPython 3.9 abi3 Linux glibc 2.28+ x86-64 Details
polars_readstat-0.21.1-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.1-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
polars_readstat-0.21.1-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.1-cp39-abi3-win_amd64.whl

Download URL polars_readstat-0.21.1-cp39-abi3-win_amd64.whl
Size 21.1 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
8af85fdf7dd2364982001f50b9dd01b544eeabfceaed6174526c2f09b555cb20
BLAKE2b-256 checksum
How to use checksums
5ad4c5baf3c8f833a94ac680dfa003ea09a223224bd22ecfa28236d7f75b1a5e
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.1-cp39-abi3-manylinux_2_28_x86_64.whl

Download URL polars_readstat-0.21.1-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
e395ae29054b247a46f29bed8bcb6444b7b1ea973726136ea08733e1cb1348bf
BLAKE2b-256 checksum
How to use checksums
d05ddf72bb026098904ad018efc96bec7a66b448e91f549fc6cb30649922448f
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.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL polars_readstat-0.21.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 19.4 MB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
e9e9a0edf360d712c7581d2b92a0dd8f02d87f890d76835d57ddcecb2d2319cd
BLAKE2b-256 checksum
How to use checksums
d5305232e53fdba183da45539d94685994a1d532e0f3b8456e0d535140609e2f
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.1-cp39-abi3-macosx_11_0_arm64.whl

Download URL polars_readstat-0.21.1-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
ce2a427aeb7ab5fbfcab00d1f5c8a3169f5817b39204d613c4858516b8c249d8
BLAKE2b-256 checksum
How to use checksums
19bfd57c5c034763ca7f2e9c2e2e74fd76510da70b07d86de53aac4a4667a03d
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.1-cp39-abi3-macosx_10_15_x86_64.whl

Download URL polars_readstat-0.21.1-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
cd80a00ad4cc9306923d0693d9bfdb86f115ed0da5683e6a45eca4900d3d361a
BLAKE2b-256 checksum
How to use checksums
85a055a8255cd78e986ebf0dea33cb414aa28e567e100e4eea5211f7ac9b70d9
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

This release

0.21.1 This release

5 release files

0.21.0

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