so_pls — Sequential and Orthogonalised PLS (SO-PLS)

Group: Multi-block / cross-modal · Registry tolerance: 1e-06

Description

SO-PLS — Sequential & Orthogonalized multi-block PLS (§17)

Registry note — R multiblock::sopls 0.8.10 (Næs et al. 2011) canonical SO-PLS via fit$fitted at the full (k1,..,kB) slice. pls4all’s NIPALS-based SO-PLS matches to ~1e-13.

No tunable parameters declared at the binding level.

Explanations

Bibliographic source

Næs, T., Tomic, O., Mevik, B.-H. & Martens, H. (2011). Path modelling by sequential PLS regression. Journal of Chemometrics 25(1), 28–40. Verified primary link: https://doi.org/10.1002/cem.1357.

Mathematical principle

SO-PLS extends MB-PLS by sequentially processing blocks in a user-specified order, orthogonalising each subsequent block against the scores extracted from the previous ones. Concretely: fit PLS on block 1, extract scores \(\mathbf{T}_1\); orthogonalise block 2 to \(\mathbf{T}_1\), fit PLS on the residual; and so on.

This makes each block’s contribution additive and interpretable — the unique variance in block \(b\) that is predictive of \(y\) given everything in blocks \(1, \ldots, b-1\). Compared to MB-PLS (which fits all blocks simultaneously), SO-PLS encodes a domain hypothesis about which block is causally upstream of which.

Tuning: a per-block \(k_b\) (number of components) plus the block order. The order matters; permuting blocks changes the attribution. Cross-validating the per-block \(k_b\) is the standard procedure.

Appropriate uses

Sequential modelling of ordered data blocks after orthogonalizing each new block against previous block scores.

Limits and validation

Results depend on block order and component allocation; validation must repeat the complete sequential procedure.

Implementation

n4m_estimators_so_pls_fit — requires n_components_per_block and block_sizes. Reference: CRAN multiblock 0.8.10.

Sources and provenance

Current implementation: cpp/src/core/extra_pls.cpp.

API and bindings

C ABI (ABI 2): n4m_estimators_so_pls_fit. Use the linked public header for the exact signature, configuration, and result handles.

Python: no current AST-verified public n4m re-export was found for this method. The linked C ABI above is the documented surface in this checkout.

R (source-verified): so_pls_fit(X, Y, block_sizes, n_components_per_block).

The source signature has additional required inputs, so no example call is fabricated.

MATLAB / Octave (source-verified): so_pls(X, Y, n_components_per_block, block_sizes).

The source signature has additional required inputs, so no example call is fabricated.

Registry parity references 📐

  • 📐 ref.r_multiblock (R · r) — multiblock 0.8.10 · strict (rmse_rel ≤ 1e-06) — R multiblock::sopls 0.8.10 (Næs et al. 2011) canonical SO-PLS — in-sample fitted values via fit$fitted at the full (k1,..,kB) slice match pls4all’s canonical NIPALS SO-PLS to ~1e-15 in centered space.

Benchmarks

Archived measurement identity. Backend labels in this table are the raw IDs recorded when the benchmark ran (including historical pls4all.* IDs). They preserve measurement provenance and do not describe a current public Python, R, or MATLAB binding; use the source-verified API and bindings section above for current entry points.

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 = archived binding-harness result 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; archived language-harness rows show binding parity against the C++ backend. Hover the icon for role and tolerance band.

BackendParity200×30 (ms)
C++ native · libn4m
pls4all.cpp.blas+omp✓ ref 7e-101.62 ms🏆
Python · archived pls4all benchmark
pls4all.python✓ bind1.67 ms
pls4all.sklearn✓ bind1.77 ms
R · archived pls4all benchmark
pls4all.R✓ bind3.26 ms
pls4all.R.formula✓ bind3.99 ms
pls4all.R.mdatools✓ bind4.00 ms
pls4all.R.pls✓ bind4.11 ms
R · external
📐ref.r_multiblocksource981.7 ms
BackendParity200×30 (ms)
C++ native · libn4m
pls4all.cpp.blas+omp✓ ref 7e-101.66 ms🏆
Python · archived pls4all benchmark
pls4all.python✓ bind1.69 ms
pls4all.sklearn✓ bind2.44 ms
R · archived pls4all benchmark
pls4all.R✓ bind22.4 ms
pls4all.R.formula✓ bind31.5 ms
pls4all.R.mdatools✓ bind31.4 ms
pls4all.R.pls✓ bind34.4 ms
R · external
📐ref.r_multiblocksource1.5 s
BackendParity200×30 (ms)
C++ native · libn4m
pls4all.cpp.blas+omp✓ ref 7e-107.16 ms🏆
Python · archived pls4all benchmark
pls4all.python✓ bind11.3 ms
pls4all.sklearn✓ bind11.9 ms
R · archived pls4all benchmark
pls4all.R✓ bind11.3 ms
pls4all.R.formula✓ bind25.9 ms
pls4all.R.mdatools✓ bind10.3 ms
pls4all.R.pls✓ bind9.15 ms
R · external
📐ref.r_multiblocksource4.0 s

See also: benchmark overview · methods index · interactive dashboard