Libraries, file formats and data types
| Library | Language | Streaming | Parallel | Windows / Pivots | SQL |
|---|---|---|---|---|---|
| pandas 🐼 | Python | ❌ | ❌ | ✅ | |
| dask | Python | ✅ | distributed | ✅ | |
| polars 🐻❄️ | Python | ✅ | in-process | ✅ | (✅) |
| duckdb 🦆 | Python | ✅ | in-process | ✅ | ✅ |
| pyarrow 🏹 | Python | ✅ | in-process | ❌ | |
| data.frame | R | ❌ | ❌ | ✅ | |
| duckdb 🦆 | R | ✅ | in-process | ✅ | ✅ |
| arrow 🏹 | R | ✅ | in-process | ❌ |
polars
dask
| Format | Col select | Peek | Pushdown | Nested | Metadata | Typing | Python | R |
|---|---|---|---|---|---|---|---|---|
| CSV | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ |
| SAS | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ |
| HDF5 | ✅ | ✅ | ❌ | ✅ | ✅ | (✅) | ✅ | ✅ |
| SQLite | ✅ | ✅ | ✅ | ❌ | (✅) | (✅) | ✅ | ✅ |
| .rds | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ |
| qs2 | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ |
| fst | ✅ | ✅ | ❌ | ❌ | ❌ | (✅) | ❌ | ✅ |
| feather | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | (✅) | ✅ |
| parquet | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
( ) = partial. Typing: primitives kept, factors + dates coerced. Metadata: limited. Python: via pyarrow.
polars’ flat bar is a known gap on float columns – reported upstream as pola-rs/polars#27860 (accepted), with a nan_count-gated fix verified locally. It skips fine on integer and date columns.
| Type | Min size | NaN? | Memory | Fast ops | Parquet |
|---|---|---|---|---|---|
| bool | 1 bit | ❌ | ✅✅ | ✅✅ | ✅ |
| int8/16/32/64 | 1 / 2 / 4 / 8 B | ❌ | ✅ | ✅ | ✅ |
| float32/64 | 4 / 8 B | ✅ | ✅ | ✅ | ✅ |
| datetime64 | 8 B | ✅ | ✅ | ✅ | ✅ |
| str / object | ~50 B | ✅ | ❌ | ❌ | ✅ |
| category | 1 B | ✅ | ✅✅ | ✅✅ | ✅ |
Categorical is deliberately off this chart: the engines order it differently – pandas sorts by the integer codes (fast), polars sorts lexically since 1.32 (string speed), duckdb decodes on read, and pyarrow sorts a dictionary array but not a dictionary column of a table (ArrowNotImplementedError, verified on pyarrow 25). For a key you sort on, store an integer code; keep categorical for group-by and RAM.
On one large extract, the levers stack:
800 million rows grouped in under 0.5 GB of peak RAM. No high-RAM server, no cloud rental.
Streaming taken all the way to model fitting: exact Cox and GLM coefficients at flat RAM, in two small open-source packages.
pip install coxstream on CRAN:
install.packages("coxstream")
pip install renew-glm Gaussian / binomial / Poisson
All data is synthetic, shaped like registry / EHR extracts – no real patient data. RAM is the peak true footprint (macOS phys_footprint, Linux RSS+swap, so compressed pages are counted), not resident RSS, which under-reports the peak by 2-3x under memory pressure. Python and R figures are not directly comparable: R carries ~150 MB of interpreter overhead.