PLSRegression#

class chemotools.regression.PLSRegression(n_components: int = 2, *, scale: bool = True, algorithm: int = 1, copy: bool = True, dtype: type = <class 'numpy.float64'>)[source]

Bases: DocLinkMixin, PLS

PLS regression via Improved Kernel PLS with automatic explained variance.

This estimator wraps the fast, exact Improved Kernel PLS algorithms [1] from the ikpls package [2] in a scikit-learn-conformant regressor + transformer, and automatically calculates explained variance ratios for both X-space and Y-space after fitting, making it easy to use with diagnostic plots and following the same API as PCA.

Compared to sklearn.cross_decomposition.PLSRegression (NIPALS) [3] and [4], the Improved Kernel PLS algorithms are faster [5] while still being numerically stable [6]. Predictions and regression coefficients agree with NIPALS; individual weight/score/loading vectors are identical up to a per-component sign, which is arbitrary in PLS.

Additional capabilities inherited from ikpls:

  • predict_all_components() returns predictions for every number of components 1..n_components in a single call (shape (n_components, n_samples, n_targets)), making component selection via (cross-)validation cheap.

  • Fine-grained preprocessing on the backend: the ikpls model supports independent center_X / center_Y / scale_X / scale_Y and a configurable ddof. This wrapper exposes only a single scale flag (X and Y are always mean-centered) and fixes ddof = 1, to mirror the previous scikit-learn-backed PLSRegression. A maintainer can enable the independent flags or a different ddof on the inner model, but they change the fitted model and the explained-variance computation.

  • Sample weights: the backend’s fit accepts sample_weight (when given, the inner X / Y means and standard deviations become their weighted variants). This wrapper does not expose sample_weight; whether to enable it is left to the maintainer.

After fitting, two additional attributes are computed:

  • explained_x_variance_ratio_: Variance explained in X-space (predictors)

  • explained_y_variance_ratio_: Variance explained in Y-space (response)

Following the PLSRegression implemented in scikit-learn [3], the explained variance calculation uses the x_scores_ (t) to asymmetrically deflate the Y matrix.

In PLS, the latent score vector t (from X) is used to model Y via its loading vector c:

Y_hat = t @ c.T

Deflation removes the part of Y explained by the current component:

Y_new = Y - Y_hat

This process is repeated for each component, using the corresponding t and c vectors. Note: Unlike PCA, deflation in PLS is asymmetric—Y is deflated using t-scores derived from X.

Parameters:
  • n_components (int, default=2) – Number of components to keep. Should be in [1, min(n_samples, n_features)].

  • scale (bool, default=True) – Whether to scale X and Y to unit standard deviation before fitting. X and Y are always mean-centered, matching the previous scikit-learn-backed PLSRegression. Internally this maps onto the ikpls backend as center_X = center_Y = True and scale_X = scale_Y = scale.

  • algorithm (int, default=1) – Improved Kernel PLS algorithm to use, either 1 or 2. Algorithm 1 uses X directly, while algorithm 2 builds X.T @ X and is typically faster for tall matrices (many more samples than features). Both algorithms give the same results.

  • copy (bool, default=True) – Whether to copy X and Y in fit before applying centering and potentially scaling.

  • dtype (type, default=numpy.float64) – Floating point dtype used for the computations.

Variables:
  • explained_x_variance_ratio (ndarray of shape (n_components,)) – Explained variance ratio in X-space (predictors) for each component. This measures how much variance in the predictor variables each latent variable captures. Automatically calculated after fitting.

  • explained_y_variance_ratio (ndarray of shape (n_components,)) –

    Explained variance ratio in Y-space (response) for each component. This measures the prediction quality - how much variance in the response each latent variable explains. Automatically calculated after fitting.

    Both ratios are computed by sequential deflation in the centered (optionally scaled) space, which the public API always uses. For inputs with nonzero variance they are valid: non-negative, with the X ratios summing to 1 at full rank. Components beyond the numerical rank of X carry no variance and are assigned zero.

    Degenerate inputs: if X (all features) or y is fully constant – i.e. has zero total variance – the corresponding ratios are NaN (a 0/0 result), since there is no variance to apportion.

  • x_scores (ndarray of shape (n_samples, n_components)) – The training X-scores T (the projection of the preprocessed training X onto x_rotations_), equal to transform(X) on the training data. (There is no y_scores_ attribute; the Y-scores are available on demand via transform(X, y) – see transform() for the caveat on how they relate to scikit-learn.)

  • y_weights_, (All other fitted attributes (x_weights_,)

  • y_rotations_, (x_loadings_, y_loadings_, x_rotations_,)

  • are (coef_, intercept_, n_features_in_, feature_names_in_))

  • the (inherited unchanged from the ikpls backend (ikpls.sklearn.PLS); see)

  • (https (ikpls documentation)

  • definitions.

References

Examples

Basic usage with automatic variance calculation

>>> from chemotools.regression import PLSRegression
>>> import numpy as np
>>>
>>> # Generate sample data
>>> X = np.random.randn(100, 50)
>>> y = X[:, 0] + 2*X[:, 1] + np.random.randn(100)*0.1
>>>
>>> # Fit model
>>> pls = PLSRegression(n_components=5)
>>> pls.fit(X, y)
>>>
>>> # Variance ratios are automatically available!
>>> print(
...     f"LV1 explains {pls.explained_y_variance_ratio_[0]*100:.1f}%"
... )
>>> print(f"Total Y variance: {pls.explained_y_variance_ratio_.sum()*100:.1f}%")
>>>
>>> # Predictions for ALL component counts 1..5 in a single call
>>> all_predictions = pls.predict_all_components(X)
>>>
>>> # Use with plotting
>>> from chemotools.plotting import ExplainedVariancePlot
>>> plot = ExplainedVariancePlot(pls.explained_y_variance_ratio_)
>>> plot.show()

Notes

Variance Calculation:

  • X-space variance is calculated using sequential deflation and sums to 1.0 (100%) when n_components equals the rank of the (centered) X

  • Y-space variance is calculated using sequential deflation but may not sum to 1.0 due to asymmetric deflation (Y deflated with X-scores). The sum depends on X-Y correlation.

  • For each component, variance explained = variance reduction after deflation

  • This follows the standard PLS variance decomposition methodology (Wegelin, 2000)

  • Components beyond the numerical rank of X carry no variance and are assigned zero explained variance, so the ratios stay non-negative and the X ratios sum to 1 at full rank even when n_components exceeds that rank (and are identical for algorithm=1 and algorithm=2).

Differences from the previous scikit-learn (NIPALS) backend:

  • The NIPALS-specific max_iter and tol parameters do not exist: Improved Kernel PLS is an exact, non-iterative solver.

  • The single scale parameter is retained with the same meaning (X and Y are always mean-centered, and scale toggles unit-variance scaling of both). The ikpls backend’s independent center_X / center_Y / scale_X / scale_Y are not exposed here.

  • Score/weight/loading vectors may differ from NIPALS by a per-component sign; predictions, coefficients, and explained variances are unaffected.

See also

sklearn.cross_decomposition.PLSRegression

scikit-learn’s NIPALS-based PLS.

chemotools.plotting.ExplainedVariancePlot

Visualization for explained variance.

Attributes

center_X

center_Y

ddof

scale_X

scale_Y

y_rotations_

The rotations mapping Y directly to its scores.

property center_X: bool
property center_Y: bool
property scale_X: bool
property scale_Y: bool
property ddof: int
fit(X: ndarray, y: ndarray) → PLSRegression[source]

Fit model to data and compute explained variance ratios.

This method extends ikpls.sklearn.PLS.fit by storing the training scores and automatically calculating explained variance ratios after fitting.

Parameters:
  • X (array-like of shape (n_samples, n_features)) – Training vectors. Accepts numpy arrays, pandas DataFrames.

  • y (array-like of shape (n_samples,) or (n_samples, n_targets)) – Target vectors. Accepts 1D (univariate) or 2D (multivariate) targets.

Returns:

self – Fitted estimator with populated variance attributes: explained_x_variance_ratio_ and explained_y_variance_ratio_.

Return type:

PLSRegression

fit_transform(X: ndarray, y: ndarray) → Tuple[ndarray, ndarray][source]

Learn and apply the dimension reduction on the training data.

Fits and returns the (x_scores, y_scores) tuple, matching sklearn.cross_decomposition.PLSRegression.fit_transform. Unlike the ikpls backend’s fit_transform, this wrapper does not accept sample_weight (it is intentionally not exposed; see the class docstring).

Parameters:
  • X (array-like of shape (n_samples, n_features)) – Training vectors.

  • y (array-like of shape (n_samples,) or (n_samples, n_targets)) – Target vectors.

Returns:

(x_scores, y_scores) – The training X-scores and Y-scores.

Return type:

tuple of ndarray

transform(X, y=None)[source]

Project X (and optionally Y) onto the latent components.

Returns the X-scores; when y is given, also returns the Y-scores as an (x_scores, y_scores) tuple, matching sklearn.cross_decomposition.PLSRegression.transform.

Note on the Y-scores: the returned Y-scores are the projection of the preprocessed Y onto y_rotations_ – the same quantity scikit-learn’s transform(X, y) returns, but not the classic NIPALS u vectors (which scikit-learn stores in its y_scores_ attribute). In regression-mode PLS, Y is deflated by the X-scores, so u depends on X and is not recoverable as any linear projection of Y; the rotation projection and u coincide only under canonical deflation (PLSCanonical). This class therefore does not expose a y_scores_ attribute.

Parameters:
  • X (array-like of shape (n_samples, n_features)) – Predictor variables to project.

  • y (array-like of shape (n_samples,) or (n_samples, n_targets), optional) – Response variables to project. If given, Y-scores are also returned.

Returns:

  • x_scores (ndarray of shape (n_samples, n_components)) – Returned when y is None.

  • (x_scores, y_scores) (tuple of ndarray) – Returned when y is given.

set_fit_request() → PLSRegression

No-op.

Calling this method has no effect.

Returns:

self – The updated object.

Return type:

object

set_score_request(*, sample_weight: bool | None | str = '$UNCHANGED$') → PLSRegression

Configure whether metadata should be requested to be passed to the score method.

Note that this method is only relevant when this estimator is used as a sub-estimator within a meta-estimator and metadata routing is enabled with enable_metadata_routing=True (see sklearn.set_config()). Please check the User Guide on how the routing mechanism works.

The options for each parameter are:

  • True: metadata is requested, and passed to score if provided. The request is ignored if metadata is not provided.

  • False: metadata is not requested and the meta-estimator will not pass it to score.

  • None: metadata is not requested, and the meta-estimator will raise an error if the user provides it.

  • str: metadata should be passed to the meta-estimator with this given alias instead of the original name.

The default (sklearn.utils.metadata_routing.UNCHANGED) retains the existing request. This allows you to change the request for some parameters and not others.

Added in version 1.3.

Parameters:

sample_weight (str, True, False, or None, default=sklearn.utils.metadata_routing.UNCHANGED) – Metadata routing for sample_weight parameter in score.

Returns:

self – The updated object.

Return type:

object