# `pls_cox` — PLS-Cox (survival regression) _Group_: **Classification & GLM** · _Registry tolerance_: `1e-06` ## Description PLS-Cox (§5) — Cox PH on PLS scores From the `pls4all.sklearn.PLSCoxRegressor` docstring: > PLS + Cox proportional-hazards regression on PLS scores. > **Registry note** — Bastien 2008 deviance-residual PLS-Cox (NumPy port): scale X, deviance residuals from a null Cox PH, NIPALS PLS, Breslow Cox NR on the scores. pls4all's default wrapper calls the same routine, so the gate is bit-for-bit. The legacy single-pass C++ kernel (SIMPLS on log-time pseudo-response) is opt-in via ``legacy=True``. R `plsRcox::coxsplsDR` is the published counterpart; see ``_PlsCoxRReference`` for the archived adapter. ### Parameters | Name | Type | Default | Notes | |------|------|---------|-------| | `n_components` | `int` | `2` | Number of latent components extracted (k). | | `n_classes` | `int` | `2` | registry benchmark cell value | ## Explanations ### Bibliographic source Bastien, P., Bertrand, F., Meyer, N. & Maumy-Bertrand, M. (2015). *Deviance residuals-based sparse PLS and sparse kernel PLS regression for censored data*. Bioinformatics 31(3), 397–404. ### Mathematical principle Cox proportional-hazards regression with PLS-based dimensionality reduction. The Cox model $\lambda(t \mid \mathbf{x}) = \lambda_0(t)\exp(\mathbf{x}^{\top}\boldsymbol{\beta})$ is degenerate in $p \gg n$ because the partial likelihood loses identifiability. PLS-Cox replaces the $p$-dimensional $\boldsymbol{\beta}$ with a $k$-dimensional latent representation by extracting PLS scores from the **deviance residuals** of a null Cox model. Required inputs are survival times and event indicators (0 = censored, 1 = event observed). The output is a fitted Cox model on the latent scores; risk scores for new samples are computed by first projecting them into the latent space and then evaluating $\mathbf{t}^{\top}\boldsymbol{\beta}$. This is the canonical method in high-dimensional biomarker survival studies (RNA-seq, MALDI-TOF) where a direct Cox model is infeasible. ### Implementation `n4m_pls_cox_fit`. Reference: R `plsRcox 1.8.2`. MATLAB header (`bindings/matlab/+pls4all/pls_cox.m`): ```text pls4all.pls_cox PLS-Cox proportional hazards (Breslow baseline hazard). survival_times: numeric vector of length size(X, 1). event_indicators: 0/1 integer vector of length size(X, 1). ``` ### Usage 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** ::::{tab-set} :class: pls4all-bindings :::{tab-item} C ABI · libn4m :sync: c :class-label: lang-c ```c /* C ABI — libn4m */ n4m_context_t* ctx = n4m_context_create(); n4m_config_t* cfg = n4m_config_create(); n4m_method_result_t* res = NULL; n4m_pls_cox_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); ``` ::: :::{tab-item} Python · pls4all (raw) :sync: python-raw :class-label: lang-python ```python import pls4all from pls4all._methods import pls_cox_fit with pls4all.Context() as ctx, pls4all.Config() as cfg: res = pls_cox_fit(ctx, cfg, X, y, n_components=4, sample_weights=sample_w, y_labels=y_labels) # then: res.matrix("predictions"), res.matrix("coefficients"), # res.vector("mask"), res.scalar("intercept"), … ``` ::: :::{tab-item} Python · pls4all.sklearn :sync: python-sklearn :class-label: lang-python ```python from pls4all.sklearn import PLSCoxRegressor mdl = PLSCoxRegressor(n_components=2) mdl.fit(X, y, sample_weight=sample_w) y_hat = mdl.predict(X_test) ``` ::: :::{tab-item} R · pls4all_method() :sync: r-dispatcher :class-label: lang-r ```r library(pls4all) # Unified low-level dispatcher (May 2026 R cleanup): res <- pls4all_method("pls_cox", X, y, n_components = 4L, params = list(n_classes = 2L)) # res is a named list with MethodResult arrays/scalars. # selected_indices / top_k_intervals are 1-based. ``` ::: :::{tab-item} MATLAB · pls4all (MEX) :sync: matlab-mex :class-label: lang-matlab ```matlab res = pls4all.pls_cox(X, y, 4); % see header of bindings/matlab/+pls4all/pls_cox.m for full % parameter surface: % res = pls_cox(X, n_components, survival_times, event_indicators) yhat = predict(res, Xtest); ``` ::: :::{tab-item} MATLAB · pls4all (classdef) :sync: matlab-classdef :class-label: lang-matlab _No idiomatic classdef wrapper — invoke `pls4all.fit("pls_cox", X, y, …)` directly from the unified MEX factory._ ::: :::: **Registry parity references** 📐 :::{card} :class-card: external-refs - 📐 **`ref.python_numpy`** (python · python) — `numpy` in-tree · strict (rmse_rel ≤ 1e-06) — In-tree NumPy port of Bastien 2008 PLS-Cox (deviance residuals + NIPALS PLS + Breslow Cox PH). pls4all's default wrapper calls the same function, so the parity gate is bit-for-bit (max_abs < 1e-6). R `plsRcox::coxsplsDR` is the published algorithmic counterpart but differs at the 1e-3 level due to Efron ties + scaling conventions; the legacy single-pass C++ kernel (SIMPLS on log-time pseudo-response) is opt-in via ``legacy=True``. ::: ### Benchmarks Adaptive wall-clock per cell measured against [`full_matrix.csv`](../benchmarks/overview.md). 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  ·  ✗ 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`](../benchmarks/methodology.md)). 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. ::::{tab-set} :class: parity-tabs :::{tab-item} 1 thread :sync: threads-1
BackendParity50×250 (ms)100×50 (ms)100×500 (ms)100×2500 (ms)200×30 (ms)250×50 (ms)500×50 (ms)500×500 (ms)500×2500 (ms)2500×50 (ms)2500×500 (ms)2500×2500 (ms)10000×50 (ms)10000×500 (ms)
C++ native · libn4m
pls4all.cpp.blas6.26 ms3.27 ms11.7 ms🏆66.1 ms1.78 ms🏆4.08 ms7.45 ms60.9 ms334.0 ms🏆46.0 ms357.0 ms1.9 s🏆191.8 ms1.5 s
pls4all.cpp.blas+omp4.49 ms3.20 ms12.5 ms63.4 ms1.97 ms5.12 ms7.64 ms61.4 ms337.9 ms43.5 ms348.9 ms🏆1.9 s176.0 ms🏆1.5 s
pls4all.cpp.omp4.28 ms🏆1.69 ms🏆13.3 ms65.4 ms1.86 ms3.51 ms7.09 ms60.1 ms🏆339.8 ms42.0 ms🏆357.2 ms1.9 s178.1 ms1.5 s🏆
pls4all.cpp.ref4.83 ms2.60 ms12.8 ms61.9 ms🏆1.83 ms3.84 ms6.84 ms🏆63.9 ms334.3 ms43.8 ms362.6 ms1.9 s200.9 ms1.5 s
Python · pls4all
pls4all.python✓ bind6.37 ms1.87 ms3.64 ms
pls4all.sklearn✗ +7e+023.01 ms1.92 ms4.53 ms
R · pls4all
pls4all.R✗ +7e+0211.0 ms5.10 ms11.2 ms
pls4all.R.formula✗ +7e+0222.8 ms5.37 ms11.8 ms
pls4all.R.mdatools✗ +7e+0221.9 ms6.66 ms10.7 ms
pls4all.R.pls✗ +7e+0224.9 ms5.04 ms11.9 ms
MATLAB · pls4all
pls4all.matlab✗ +7e+024.41 ms2.40 ms5.03 ms
pls4all.matlab.classdef✗ +7e+025.19 ms2.63 ms5.42 ms
Python · external
📐ref.python_numpysource4.72 ms2.85 ms3.28 ms🏆
::: :::{tab-item} 3 threads :sync: threads-3
BackendParity50×250 (ms)100×50 (ms)100×500 (ms)100×2500 (ms)200×30 (ms)250×50 (ms)500×50 (ms)500×500 (ms)500×2500 (ms)2500×50 (ms)2500×500 (ms)2500×2500 (ms)10000×50 (ms)10000×500 (ms)
C++ native · libn4m
pls4all.cpp.blas✓ ref1.75 ms🏆
pls4all.cpp.blas+omp✓ ref1.83 ms
pls4all.cpp.omp✓ ref1.82 ms
pls4all.cpp.ref✓ ref2.55 ms
Python · pls4all
pls4all.python✓ bind2.84 ms
pls4all.sklearn✗ +2e+002.24 ms
R · pls4all
pls4all.R✗ +2e+005.22 ms
pls4all.R.formula✗ +2e+005.03 ms
pls4all.R.mdatools✗ +2e+004.74 ms
pls4all.R.pls✗ +2e+005.13 ms
MATLAB · pls4all
pls4all.matlab✗ +2e+002.14 ms
pls4all.matlab.classdef✗ +2e+002.61 ms
Python · external
📐ref.python_numpysource2.34 ms
::: :::{tab-item} 10 threads :sync: threads-10
BackendParity50×250 (ms)100×50 (ms)100×500 (ms)100×2500 (ms)200×30 (ms)250×50 (ms)500×50 (ms)500×500 (ms)500×2500 (ms)2500×50 (ms)2500×500 (ms)2500×2500 (ms)10000×50 (ms)10000×500 (ms)
C++ native · libn4m
pls4all.cpp.blas✓ ref2.81 ms
pls4all.cpp.blas+omp✓ ref2.61 ms
pls4all.cpp.omp✓ ref1.65 ms🏆
pls4all.cpp.ref✓ ref1.71 ms
Python · pls4all
pls4all.python✓ bind2.57 ms
pls4all.sklearn✗ +2e+001.38 ms
R · pls4all
pls4all.R✗ +2e+003.19 ms
pls4all.R.formula✗ +2e+003.92 ms
pls4all.R.mdatools✗ +2e+003.86 ms
pls4all.R.pls✗ +2e+003.83 ms
MATLAB · pls4all
pls4all.matlab✗ +2e+001.97 ms
pls4all.matlab.classdef✗ +2e+002.32 ms
Python · external
📐ref.python_numpysource1.66 ms
::: :::: --- _See also_: [benchmark overview](../benchmarks/overview.md) · [methods index](index.md) · [interactive dashboard](../landing/dashboard.md)