Skip to main content

renew-glm

Streaming generalized linear models with bounded memory -- a Python port of the renewable-estimation algorithm of Luo & Song (2020).

GLM benchmark: cost, accuracy, scaling

from renew_glm import RenewGLM

# Streaming (recommended): one chunk at a time, never stores prior chunks.
# Peak RAM is O(p^2 + chunk_size * p), independent of n.
# chunk_fn is polled: return the next (X, y), or None when exhausted.
chunks = iter(source_iter())                 # your (X, y) iterator
def chunk_fn():
    return next(chunks, None)                # X must include intercept column

model = RenewGLM(family="binomial").fit_streaming(chunk_fn)
print(model.coef_, model.n_iter_)

# Or chunk-buffered (matches the original R API):
model = RenewGLM(family="poisson")
for X_chunk, y_chunk in chunks:
    model.partial_fit(X_chunk, y_chunk)
model.fit()
print(model.coef_, model.se_, model.pvalue_)

chunk_fn is a zero-argument callable that is polled repeatedly: each call returns the next (X, y) tuple, and None once the data is exhausted. This is the biglm::bigglm callback pattern, not a generator. fit_streaming releases each chunk before asking for the next, so peak RAM is O(p^2 + chunk_size * p); partial_fit + fit instead buffers every chunk in memory, which is what lets it compute se_ and pvalue_ like the R reference.

Supports gaussian, binomial, and poisson families. Coefficients converge to the maximum-likelihood point of the full data; agreement with statsmodels.GLM is verified to ~1e-3 on the test suite.

Why

Standard in-memory tools (statsmodels.GLM, R's glm()) load the entire design matrix before fitting. At n = 16 M rows, statsmodels.GLM allocates ~8 GB and OOMs above n ~ 20 M on a 16 GB laptop. This package fits the same model in bounded memory -- one chunk at a time, O(p^2) state regardless of n.

Other Python GLM options exist with different trade-offs:

  • glum (Quantco) -- fast in-memory; agrees with our estimates to ~1e-10 (see Correctness below), but caps out where the full design matrix fits in RAM, same as statsmodels. Recommended if your n fits.
  • dask-glm -- distributed; useful at multi-machine scale, has scheduler overhead at single-host scale.
  • pyglmnet -- gradient-based, regularization-focused; supports several families but the unregularized path is slower than IRLS.
  • scikit-learn SGD -- online SGD, approximate (not exact MLE).

This package targets the gap: exact-MLE streaming on a single host, no full-design-matrix RAM. It carries the same Wald inference the R reference (biglm, RenewGLM_pkg) exposes.

Install

pip install renew-glm

Requires only NumPy and SciPy. Pure Python -- no C extension, no compile step, no platform-specific wheels.

Correctness

Across independent implementations spanning Python (NumPy / Numba / JAX), an in-memory Python competitor (glum), a distributed Python competitor (dask-glm), and a cross-language reference (R's biglm), the coefficient estimates agree to floating-point machine epsilon (~1e-15) on the largest workload we test. The heatmap inset in the benchmark figure above shows pairwise log10(max|beta_i - beta_j|): renew-glm hits FP epsilon (-15) against the streaming-Cholesky cluster; in-memory references (glum, statsmodels, glm (R)) sit one order out at -10/-11 (algorithm-decomposition path, not convergence). The JAX implementation in that comparison sets jax_enable_x64=True; the silent-float32 default would land an order of magnitude looser. Note that the Numba and JAX implementations are benchmark comparators only. The released package ships the NumPy path alone, as renew_glm.__doc__ states.

Scaling

The right-side line panels in the benchmark figure show wall time and peak RAM as n grows from 1M to 128M rows (cold runs). The in-memory baselines (statsmodels, glm (R)) terminate at the OOM cliff (~9 GB); renew-glm stays flat at bounded RAM.

Algorithm

For each chunk:

  1. Compute Fisher information H_b = X' diag(W_b) X at the current coefficient.
  2. Inner Newton-Raphson against H_b + sum_of_prior_Fishers, with a penalty term that pulls toward the previous coefficient.
  3. Update sum_of_prior_Fishers += H_b and move to the next chunk.

One outer pass over the chunks suffices because the penalty term lets each chunk contribute meaningfully without revisiting prior data. The docstring in _irls.py matches the paper notation.

Differences from the original R package

  • No SE in the streaming path. fit_streaming(chunk_fn) returns only coef_ and n_iter_. The chunk-buffered partial_fit + fit() path computes se_ and pvalue_ like the R version.
  • Pure NumPy/SciPy. No C extension; portable and easy to install.
  • Convergence tolerance uses |g' d_beta| < tol (same as the R version's df_beta criterion).

Roadmap (post v0.1.0)

Deferred to keep the first release minimal; pull requests welcome.

  • Formula API (patsy / formulaic) -- a from_formula("y ~ x1 + C(category)", chunk_source=...) constructor so users coming from statsmodels.GLM.from_formula(...) or R's glm(y ~ ...) don't have to build the design matrix themselves. The streaming twist: category levels must be discovered before fitting, so the API will require either a first-pass discover_levels(source) step or an explicit levels={...} argument. First-chunk-lock-in (reject any chunk introducing a new level, with a clear error) is the most likely default. Workaround today: use patsy.dmatrices(...) per-chunk and feed the resulting arrays to partial_fit / fit_streaming.
  • Gamma + inverse-Gaussian families -- the algorithm generalises (any exponential-dispersion family with a known link works), but the test suite only covers gaussian / binomial / poisson. The weight and mu functions in _irls.py are a few lines each; the real work is dispersion, which is currently special-cased to gaussian, while the standard errors for every other family assume dispersion 1. Both need extending before either family is usable.
  • Optional Cholesky -> Givens-QR path -- the current code uses scipy.linalg.cho_factor on X' W X + sum_prior_Fisher. For ill-conditioned designs a Givens-QR path on [W^{1/2} X ; previous-R] would be more numerically stable; the bench's R reference (biglm) already does this and our coefficients agree to ~1e-6, suggesting the Cholesky path is sufficient for typical inputs. Track this if a real user hits a conditioning problem.

Credit

License

GPL-2.0-or-later, matching the license of the original R package.

Metadata

Release files for renew-glm 0.1.3

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

Source distribution (sdist)

Source distribution for renew-glm 0.1.3
File Size Uploaded Provenance
renew_glm-0.1.3.tar.gz 546.3 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for renew-glm 0.1.3
File Interpreter ABI Platform
renew_glm-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 562.3 kB

Release files / renew_glm-0.1.3.tar.gz

Download URL renew_glm-0.1.3.tar.gz
Size 546.3 kB
Tags Source
SHA-256 checksum
How to use checksums
862dd934fd590fdf04bba09daa701dfc351980925e2d443834de324b7f91eadc
BLAKE2b-256 checksum
How to use checksums
1379fb6ca65084e3f19bff825d330a40dbea4b8d42e9f7005faeca8e0152085e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.5

Release files / renew_glm-0.1.3-py3-none-any.whl

Download URL renew_glm-0.1.3-py3-none-any.whl
Size 16.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
980c9e4e5f5d9860cfb285f34fafde69c5bc9c16f2b6e3b501fc47f5a59f6f1e
BLAKE2b-256 checksum
How to use checksums
187d7e1232b8086ad5ed9c5960b200746123ce0a0d1fdcbb7b650256968b7217
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.5

Security for renew-glm 0.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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