lw_pls — Locally-Weighted PLS (LW-PLS)¶
Group: Nonlinear / local · Registry tolerance: 1e-08
Description¶
LW-PLS — Locally-weighted PLS (§17 Phase 4)
Registry note — In-tree
nirs4all.operators.models.sklearn.lwpls.LWPLSis the sanctioned external reference. pls4all defaults to the Gaussian-weighted local PLS that matches nirs4all bit-for-bit (max_abs < 1e-13); the legacy k-NN cutoff variant is opt-in via cfg.solver = SIMPLS.
Parameters¶
Name |
Type |
Default |
Notes |
|---|---|---|---|
|
|
|
registry benchmark cell value |
|
|
|
registry benchmark cell value |
Explanations¶
Bibliographic source¶
Centner, V. & Massart, D. L. (1998). Optimization in locally weighted regression. Analytical Chemistry 70(19), 4206–4211. DOI 10.1021/ac980208r.
Mathematical principle¶
Instead of fitting a single global PLS, LW-PLS refits a per-prediction-point local PLS using only the \(k\)-nearest calibration samples (in \(\mathbf{X}\)-space distance). This adapts the model to the local geometry around each query point and is effective on calibration sets that span heterogeneous regimes (e.g. a single instrument calibrated across several product classes).
The neighbourhood weight typically combines distance (Gaussian or tricube kernel on the Euclidean / Mahalanobis distance) with the inverse residual variance from a preliminary global fit. The local PLS uses few components (typically 2–4) because the neighbourhood is small.
Prediction cost is \(O(n)\) for the neighbour search plus \(O(k_{\mathrm{nn}} \cdot p \cdot k_{\mathrm{pls}})\) for the local fit, per query. KD-tree / ball-tree indices accelerate the neighbour search; pls4all uses an exhaustive scan because \(p \gg n\) defeats most spatial indices for NIR data anyway.
Appropriate uses¶
Local nonlinear calibration where each query is well represented by nearby calibration samples.
Limits and validation¶
A separate weighted model is fitted per query; distance scaling, bandwidth, and poor neighbourhood coverage can dominate predictions.
Implementation¶
n4m_estimators_lw_pls_fit. Reference: sanctioned git-pinned port nirs4all.operators.models.sklearn.lwpls.
Sources and provenance¶
Current implementation: cpp/src/core/extra_pls.cpp.
API and bindings¶
C ABI (ABI 2): n4m_estimators_lw_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): lw_pls_fit(X, Y, n_components, n_neighbors = 30L).
The source signature has additional required inputs, so no example call is fabricated.
MATLAB / Octave (source-verified): lw_pls(X, Y, n_components, n_neighbors).
The source signature has additional required inputs, so no example call is fabricated.
Registry parity references 📐
📐
nirs4all(python · python) —nirs4allin-tree · strict (rmse_rel ≤ 1e-08) — In-tree Python LW-PLS (sanctioned external reference). Locally-weighted PLS (Naes 1990 / Centner 1998). pls4all’s default solver (NIPALS) implements the same Gaussian-weighted local PLS as the nirs4all reference, deriving the kernel bandwidthlambda = max(1.0, 0.5 * n_neighbors). The legacy k-NN cutoff variant remains available via cfg.solver = SIMPLS.
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-08).
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.
| Backend | Parity | 200×40 (ms) |
|---|---|---|
| C++ native · libn4m | ||
pls4all.cpp.blas+omp | ✓ ref 7e-16 | 25.6 ms |
| Python · archived pls4all benchmark | ||
pls4all.python | ✓ bind | 37.2 ms |
pls4all.sklearn | ⇄ +1e+00 | 9.19 ms🏆 |
| R · archived pls4all benchmark | ||
pls4all.R | ⇄ +1e+00 | 20.3 ms |
pls4all.R.formula | ⇄ +1e+00 | 23.2 ms |
pls4all.R.mdatools | ⇄ +1e+00 | 24.6 ms |
pls4all.R.pls | ⇄ +1e+00 | 23.2 ms |
| Python · external | ||
📐nirs4all | source | 23.9 ms |
| Backend | Parity | 200×40 (ms) |
|---|---|---|
| C++ native · libn4m | ||
pls4all.cpp.blas+omp | ✓ ref 7e-16 | 10.8 ms |
| Python · archived pls4all benchmark | ||
pls4all.python | ✓ bind | 10.3 ms |
pls4all.sklearn | ⇄ +1e+00 | 4.44 ms🏆 |
| R · archived pls4all benchmark | ||
pls4all.R | ⇄ +1e+00 | 9.02 ms |
pls4all.R.formula | ⇄ +1e+00 | 10.0 ms |
pls4all.R.mdatools | ⇄ +1e+00 | 10.8 ms |
pls4all.R.pls | ⇄ +1e+00 | 11.1 ms |
| Python · external | ||
📐nirs4all | source | 23.7 ms |
| Backend | Parity | 200×40 (ms) |
|---|---|---|
| C++ native · libn4m | ||
pls4all.cpp.blas+omp | ✓ ref 7e-16 | 11.8 ms |
| Python · archived pls4all benchmark | ||
pls4all.python | ✓ bind | 12.9 ms |
pls4all.sklearn | ⇄ +1e+00 | 5.14 ms🏆 |
| R · archived pls4all benchmark | ||
pls4all.R | ⇄ +1e+00 | 9.85 ms |
pls4all.R.formula | ⇄ +1e+00 | 9.03 ms |
pls4all.R.mdatools | ⇄ +1e+00 | 11.2 ms |
pls4all.R.pls | ⇄ +1e+00 | 12.1 ms |
| Python · external | ||
📐nirs4all | source | 29.0 ms |
See also: benchmark overview · methods index · interactive dashboard