Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ those changes.

## [Unreleased]

- Docstring corrections across PCA/PLS/TPLS/limits/preprocessing/experiments
modules to bring documented behaviour into line with the code (no runtime
changes).

## [1.54.0] - 2026-07-13

### Changed
Expand Down
4 changes: 2 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ authors:
repository-code: "https://github.com/kgdunn/process-improve"
url: "https://kgdunn.github.io/process-improve/"
license: MIT
version: 1.54.0
date-released: "2026-07-13"
version: 1.54.1
date-released: "2026-07-17"
keywords:
- chemometrics
- multivariate analysis
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "process-improve"
version = "1.54.0"
version = "1.54.1"
description = 'Designed Experiments; Latent Variables (PCA, PLS, multivariate methods with missing data); Process Monitoring; Batch data analysis.'
readme = "README.md"
license = "MIT"
Expand Down
4 changes: 3 additions & 1 deletion src/process_improve/experiments/designs_response_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ def dispatch_ccd( # noqa: PLR0913
alpha : str, float, or None
Axial distance. Accepted string values: ``"rotatable"``,
``"face_centered"``, ``"orthogonal"``. A numeric value sets
alpha directly. Defaults to ``"orthogonal"``.
alpha directly **only when ``cube='fractional'``**; for
``cube='full'`` the numeric value is ignored and the orthogonal
alpha is used. Defaults to ``"orthogonal"``.
cube : str
How to build the cube (factorial) portion: ``"full"`` (default) uses
the complete 2^k factorial; ``"fractional"`` uses a resolution-V (or
Expand Down
14 changes: 10 additions & 4 deletions src/process_improve/multivariate/_limits.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,11 @@ def spe_calculation(spe_values: np.ndarray, conf_level: float = 0.95) -> float:
Returns
-------
float
The limit, above which we judge observations in the model to have a different correlation
structure than those values which were used to build the model.
The SPE limit at the requested confidence level, returned on the
sqrt-of-sum-of-squared-residuals scale (directly comparable to
entries of ``model.spe_``, which are stored on the same scale).
Values above this limit indicate observations whose correlation
structure differs from the training data's.
"""
if not 0.0 < conf_level < 1.0:
raise ValueError(f"conf_level must lie in (0, 1); got {conf_level}.")
Expand Down Expand Up @@ -181,8 +184,11 @@ def ellipse_coordinates( # noqa: PLR0913
Number of components `A` in the fitted model. Required to look up the
Hotelling's T^2 limit and to bound `score_horiz`/`score_vert`.
scaling_factor_for_scores : pd.Series
Per-component standard deviations of the scores (``model.scaling_factor_for_scores_``).
Used to scale the ellipse axes.
Per-component standard deviations of the scores
(``model.scaling_factor_for_scores_``). Used to scale the ellipse
axes. Required: the signature defaults to ``None`` for backward
compatibility, but passing ``None`` (or omitting the argument)
raises :class:`AssertionError` inside the function.
n_rows : int
Number of rows `N` in the data used to fit the model. Required to compute the
Hotelling's T^2 limit; must be strictly positive.
Expand Down
27 changes: 21 additions & 6 deletions src/process_improve/multivariate/_pca.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,9 @@ def _pca_ekf_press( # noqa: PLR0913, PLR0915, PLR0912, C901
Returns
-------
press : np.ndarray of shape (max_components,)
Per-cell PRESS per component count, averaged over ``n_repeats``
passes so the scale is comparable to a single-pass run.
Total PRESS per component count (sum of squared cell-residuals
across all folds, averaged over ``n_repeats`` passes so the scale
is comparable to a single-pass run).
per_fold_press : np.ndarray of shape (max_components, n_folds * n_repeats)
Per-fold PRESS contributions across every fold of every repeat;
drives the 1-SE rule's standard error.
Expand Down Expand Up @@ -220,8 +221,11 @@ class PCA(_LatentVariableModel, TransformerMixin, BaseEstimator):

Parameters
----------
n_components : int
Number of principal components to extract.
n_components : int or None, default=None
Number of principal components to extract. If ``None``, defaults to
``min(n_samples, n_features)`` when :meth:`fit` runs; if the requested
value exceeds that maximum, it is clamped to ``min(n_samples,
n_features)`` and a :class:`SpecificationWarning` is issued.

algorithm : str, default="auto"
Algorithm to use for fitting the model.
Expand Down Expand Up @@ -920,8 +924,10 @@ def parallel_analysis(
the more conservative 95th-percentile threshold is the
modern recommendation.
scale : bool, default True
Mean-centre and unit-variance scale ``X`` before estimation
(matches :meth:`minka_mle`).
Mean-centre and unit-variance scale ``X`` before estimation.
Note that :meth:`minka_mle`, by contrast, only centres ``X``
(no unit-variance scaling); the two routines do not share the
same preprocessing when ``scale=True`` here.
random_state : int, optional
Seed for the null-matrix simulations.

Expand Down Expand Up @@ -1069,6 +1075,15 @@ def select_n_components( # noqa: PLR0913, PLR0915, C901
step. Ignored under ``cv_scheme="row_wise"``.
random_state : int, optional
Seed for the ekf element-fold permutation.
return_consensus : bool, default False
If ``True``, also run :meth:`minka_mle` and
:meth:`parallel_analysis` on ``X`` and add their recommendations
plus a consensus vote to the returned :class:`~sklearn.utils.Bunch`
(extra keys: ``minka_n_components``,
``parallel_analysis_n_components``, ``consensus``,
``consensus_counts``). The primary ``n_components`` value is still
the cross-validation recommendation; the consensus fields are
informational.
threshold : float, optional
Deprecated. The original Wold PRESS-ratio cutoff. Passing it
emits a :class:`DeprecationWarning`; the value is ignored. Use
Expand Down
7 changes: 5 additions & 2 deletions src/process_improve/multivariate/_pls.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,11 @@ class PLS(_LatentVariableModel, RegressorMixin, TransformerMixin, BaseEstimator)

Parameters
----------
n_components : int
Number of latent components to extract.
n_components : int or None, default=None
Number of latent components to extract. If ``None``, defaults to
``min(n_samples, n_features)`` when :meth:`fit` runs; if the requested
value exceeds that maximum, it is clamped and a
:class:`SpecificationWarning` is issued.
scale : bool, default=True
Mean-center and unit-variance-scale both the X and Y blocks internally
before fitting (``ddof=1``, done with :class:`MCUVScaler`). This mirrors
Expand Down
13 changes: 7 additions & 6 deletions src/process_improve/multivariate/_preprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,10 @@ def center(
This specifies the axis along which the centering vector will be calculated if not provided.
The function is applied along the `axis`: 0=down the columns; 1 = across the rows.

*Missing values*: The sample mean is computed by taking the sum along the `axis`, skipping
any missing data, and dividing by N = number of values which are present. Values which were
missing before, are left as missing after.
*Missing values*: The default ``func=np.mean`` does not skip NaN reliably; a column
containing any NaN propagates NaN into the returned centring vector. Pass
``func=np.nanmean`` (or a custom NaN-aware reducer) for explicit NaN-aware centring.
Values which were missing before are left as missing after.
"""
# pandas-stubs types apply()'s axis as a Literal, so a plain ``int`` axis does
# not match any overload; the call is valid at runtime.
Expand All @@ -185,9 +186,9 @@ def scale(


`func` [optional; default=np.std] {a function}
The default (np.std) uses NumPy to calculate the standard deviation of
the data along the required `axis`, skipping over any missing data, and
uses that as `scale`.
The default (``np.std``) does not skip NaN reliably; a column containing any NaN
propagates NaN into the returned scaling vector. Pass ``func=np.nanstd`` (or a
custom NaN-aware reducer) for explicit NaN-aware scaling.

`axis` [optional; default=0] {integer}
Transformations are applied on slices of data. This specifies the
Expand Down
9 changes: 7 additions & 2 deletions src/process_improve/multivariate/_tpls.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,13 @@ def fit(self, X: DataFrameDict, y: None = None) -> TPLS: # noqa: ARG002, PLR091

Parameters
----------
X : {dictionary of dataframes}, keys that must be present: "F", "Z", and "Y"
The training input samples. See documentation in the class definition for more information on each matrix.
X : DataFrameDict
The training input samples, provided as a
:class:`DataFrameDict` (a plain :class:`dict` is not accepted;
the method raises :class:`TypeError`). Keys that must be
present: ``"F"``, ``"Z"``, and ``"Y"``. See the class-level
:class:`TPLS` docstring (and its example) for the required
shape of each block.

Returns
-------
Expand Down
Loading