continuum_regression — Continuum Regression (Stone & Brooks 1990)¶
Group: Nonlinear / local · Registry tolerance: 1e-06
Description¶
Continuum regression (interpolates PLS / OLS)
From the pls4all.sklearn.ContinuumRegression docstring:
Continuum regression τ ∈ [0, 1] interpolates PLS (1) / OLS (0).
Registry note — Canonical Stone & Brooks (1990) continuum regression. Python
ContinuumPyReferenceis a paper-faithful NumPy implementation (no widely installable Python port exists); the pls4all C++ kernel uses the same algorithm and matches bit-for-bit. The optional RJICO::continuumadapter uses a different (lambda, gamma, om) parameterization and is kept as a qualitative cross-check.
Parameters¶
Name |
Type |
Default |
Notes |
|---|---|---|---|
|
|
|
Number of latent components extracted (k). |
|
|
|
Continuum mixing parameter in [0, 1]; 0 ≈ PLS, 1 ≈ whitened OLS / PCR-like. |
Explanations¶
Bibliographic source¶
Stone, M. & Brooks, R. J. (1990). Continuum regression: cross-validated sequentially constructed prediction embracing ordinary least squares, partial least squares and principal components regression. JRSS B 52(2), 237–269.
Mathematical principle¶
Continuum regression introduces a single shape parameter \(\tau \in [0, 1]\) that selects the loading-weight criterion: \(\mathbf{w} \propto \operatorname{Cov}(\mathbf{X}\mathbf{w}, \mathbf{y})^{\tau} \cdot \operatorname{Var}(\mathbf{X}\mathbf{w})^{1-\tau}\). Special cases: \(\tau = 0\) gives PCR (variance-maximising), \(\tau = 1/2\) gives PLS (covariance-maximising), \(\tau = 1\) gives OLS (correlation-maximising, in the appropriate limit).
Cross-validating \(\tau\) on a fine grid often improves RMSE over the discrete PLS / PCR choices — the optimum is rarely exactly at \(\tau = 0.5\). Stone & Brooks’ original treatment also cross-validates the number of components \(k\) jointly with \(\tau\), producing a 2-D grid.
Implementation note: numerically stable continuum regression uses the parameterised power method on the matrix \(\mathbf{X}^{\top}\mathbf{y}\mathbf{y}^{\top}\mathbf{X} / (\mathbf{X}^{\top}\mathbf{X})^{1-\tau}\), which avoids forming the rank-1 outer product explicitly and is what pls4all uses.
Implementation¶
n4m_continuum_regression_fit (in-sample only).
MATLAB header (bindings/matlab/+pls4all/ContinuumRegression.m):
pls4all.ContinuumRegression Continuum regression (tau ∈ [0, 1]).
Usage¶
Direct n4m Python helper:
import n4m
res = n4m.continuum_regression(X, y, n_components=4, tau=0.25)
y_hat = res["predictions"]
coef = res["coefficients"]
Reusable sklearn-style wrapper:
from n4m.sklearn import NativeContinuumRegressionRegressor
model = NativeContinuumRegressionRegressor(
n_components=4,
tau=0.25,
).fit(X, y)
y_hat = model.predict(X_test)
Every pls4all binding tab dispatches into the same C kernel; the external libraries listed at the bottom of the page are the parity references registered in benchmarks.parity_timing.registry. Switch tabs to read the same fit in your language. The R package now ships drop-in-compatible facades for the CRAN pls package (plsr, pcr, mvr) and for the mdatools::pls(x, y, ...) matrix idiom — those tabs appear only on the methods that have a meaningful equivalence.
pls4all bindings
/* C ABI — libn4m */
n4m_context_t* ctx = n4m_context_create();
n4m_config_t* cfg = n4m_config_create();
n4m_method_result_t* res = NULL;
n4m_continuum_regression_fit(ctx, cfg, &x_view, &y_view, /* hyperparams */, &res);
/* … read coefficients / mask / scores via */
/* n4m_method_result_get_double_matrix / vector / scalar … */
n4m_method_result_destroy(res);
n4m_config_destroy(cfg);
n4m_context_destroy(ctx);
import pls4all
from pls4all._methods import continuum_regression_fit
with pls4all.Context() as ctx, pls4all.Config() as cfg:
res = continuum_regression_fit(ctx, cfg, X, y, n_components=4)
# then: res.matrix("predictions"), res.matrix("coefficients"),
# res.vector("mask"), res.scalar("intercept"), …
from pls4all.sklearn import ContinuumRegression
mdl = ContinuumRegression(n_components=2, tau=0.5)
mdl.fit(X, y)
y_hat = mdl.predict(X_test)
library(pls4all)
# Unified low-level dispatcher (May 2026 R cleanup):
res <- pls4all_method("continuum_regression", X, y,
n_components = 4L, params = list(tau = 0.5))
# res is a named list with MethodResult arrays/scalars.
# selected_indices / top_k_intervals are 1-based.
res = pls4all.continuum_regression(X, y, 4);
% see header of bindings/matlab/+pls4all/continuum_regression.m for full
% parameter surface:
% res = continuum_regression(X, Y, n_components, tau)
yhat = predict(res, Xtest);
mdl = pls4all.fit("continuum_regression", X, y, "NumComponents", 4);
yhat = predict(mdl, Xtest);
Registry parity references 📐
📐
ref.python_stone_brooks_1990_py(python · python) —stone-brooks-1990-py1.0 · strict (rmse_rel ≤ 1e-06) — NumPy reference for Stone & Brooks (1990) continuum regression. First-component weight is (X’X)^{-tau} X’y, computed via the centered-X SVD; subsequent components use SIMPLS basis-v deflation of the modified cross-product matrix.📐
ref.r_jico(R · r) —JICO0.1 · strict (rmse_rel ≤ 1e-06) — RJICO::continuum(Stone & Brooks 1990). Different parameterization than pls4all — JICO uses (lambda, gamma, om) while pls4all maps a single τ. Predictions are reconstructed by regressing Y on JICO’s latent scores.
Benchmarks¶
Adaptive wall-clock per cell measured against full_matrix.csv. Only backends that implement this method are listed; libraries without the method are omitted.
Verdict · ✓ ref / ≈ ref / ~ shape mark a reference-gate pass at strict / relaxed / qualitative tolerance · ✓ bind = pls4all binding agrees with the C++ baseline · ⇄ cross-check = documented by-design selector/RNG/model, noncanonical API/facade convention, or secondary oracle · ✗ divergent · ⚠ error · — not run. The fastest backend per column is marked 🏆.
Reference gate: strict — numeric equivalence (rmse_rel_tol ≤ 1e-06).
Rows tagged with 📐 are the canonical parity references for this method (declared in parity_timing.registry). C++ and external rows show reference parity; pls4all language bindings show binding parity against the C++ backend. Hover the icon for role and tolerance band.
| Backend | Parity | 200×50 (ms) |
|---|---|---|
| C++ native · libn4m | ||
pls4all.cpp.blas+omp | ✓ ref 1e-14 | 2.73 ms |
| Python · pls4all | ||
pls4all.python | ✓ bind | 2.63 ms |
pls4all.sklearn | ✓ bind | 2.77 ms |
| R · pls4all | ||
pls4all.R | ✓ bind | 5.55 ms |
pls4all.R.formula | ✓ bind | 6.02 ms |
pls4all.R.mdatools | ✓ bind | 6.62 ms |
pls4all.R.pls | ✓ bind | 6.62 ms |
| Python · external | ||
📐ref.python_stone_brooks_1990_py | source | 2.27 ms🏆 |
| R · external | ||
📐ref.r_jico | ⇄ +8e-03 | 31.6 ms |
| Backend | Parity | 200×50 (ms) |
|---|---|---|
| C++ native · libn4m | ||
pls4all.cpp.blas+omp | ✓ ref 1e-14 | 2.70 ms |
| Python · pls4all | ||
pls4all.python | ✓ bind | 2.65 ms |
pls4all.sklearn | ✓ bind | 2.83 ms |
| R · pls4all | ||
pls4all.R | ✓ bind | 5.33 ms |
pls4all.R.formula | ✓ bind | 6.41 ms |
pls4all.R.mdatools | ✓ bind | 6.49 ms |
pls4all.R.pls | ✓ bind | 6.57 ms |
| Python · external | ||
📐ref.python_stone_brooks_1990_py | source | 2.39 ms🏆 |
| R · external | ||
📐ref.r_jico | ⇄ +8e-03 | 31.6 ms |
| Backend | Parity | 200×50 (ms) |
|---|---|---|
| C++ native · libn4m | ||
pls4all.cpp.blas+omp | ✓ ref 1e-14 | 2.70 ms🏆 |
| Python · pls4all | ||
pls4all.python | ✓ bind | 2.76 ms |
pls4all.sklearn | ✓ bind | 2.93 ms |
| R · pls4all | ||
pls4all.R | ✓ bind | 6.21 ms |
pls4all.R.formula | ✓ bind | 6.41 ms |
pls4all.R.mdatools | ✓ bind | 7.10 ms |
pls4all.R.pls | ✓ bind | 6.57 ms |
| Python · external | ||
📐ref.python_stone_brooks_1990_py | source | 4.06 ms |
| R · external | ||
📐ref.r_jico | ⇄ +8e-03 | 49.0 ms |
See also: benchmark overview · methods index · interactive dashboard