pylimma.normalize_cyclic_loess

pylimma.normalize_cyclic_loess(x, weights=None, span=0.7, adaptive_span=False, iterations=3, method='fast')[source]

Cyclic LOESS normalisation of columns of a matrix.

Faithful port of R limma’s normalizeCyclicLoess (limma/R/norm.R:535-580). All three R methods are implemented:

  • "fast" (default): each column vs the row mean.

  • "pairs": pairwise loess over every column pair.

  • "affy": like "pairs" but accumulates all pair-wise adjustments then divides by n per iteration.

Probe-vector weights (length = number of rows in x) are supported for all three methods and are threaded through to loess_fit() in the weighted path. The unweighted "fast" path keeps the legacy statsmodels lowess route (with it=3 and delta=0.01*range(x)) so existing pre-computed R-parity fixtures continue to pass bit-for-bit.

Per-observation (matrix-shaped) weights are accepted by R’s signature but fail inside R’s own loessFit call with "y and weights have different lengths" - this is a latent bug in R limma. pylimma does not attempt to fix it; pass a probe-vector instead, or collapse your (n_genes, n_samples) weight matrix with row_means = np.nanmean(w, axis=1) before calling.

The adaptive_span default of False matches the installed R limma (3.66.0) used to generate the parity fixtures. The current upstream limma source (modified 25 Feb 2026) flips this default to True; pylimma will follow that change once the bundled limma version is upgraded.

Return type:

ndarray

Parameters: