Preprocessing powertransformer - CyrilB1531/lodestar GitHub Wiki

Development build. This page describes main, not a released package. The latest published Lodestar.Preprocessing is 0.2.0 — read its documentation.

Home › Preprocessing › Feature transforming

PowerTransformer

Raises each feature to the power that makes it most nearly normal, at sklearn.preprocessing.PowerTransformer parity.

public sealed class PowerTransformer

Properties — FeatureCount and SampleCount are the shape it was fitted on. Lambdas is each feature's fitted exponent — the reference's lambdas_.

Example — a right-skewed income column.

using Lodestar.Preprocessing;

double[] income = [22.0, 25.0, 28.0, 31.0, 35.0, 42.0, 55.0, 78.0, 120.0, 260.0];

PowerTransformer transformer = PowerTransformer.Fit(income, featureCount: 1);

double lambda = Math.Round(transformer.Lambdas[0], 4);   // => -0.8072

double[] symmetric = transformer.Transform(income);

double smallest = Math.Round(symmetric[0], 4);   // => -1.4543
double largest = Math.Round(symmetric[9], 4);    // => 1.7177

Remarks — this is the gentle counterpart to QuantileTransformer. Both answer "make this column look normal"; this one does it with a single exponent fitted by maximum likelihood, so the order and the relative spacing survive — two values close together stay close together, and a new value outside the fitted range is transformed by the same formula rather than clamped. The cost is that one exponent may not be enough: a bimodal column has no power that makes it normal, and the transformer will still return the best one.

Conformance here is 1e-5, not the 1e-9 the rest of this repository meets. The exponent is fitted by maximising a log-likelihood whose curvature at the optimum is about 176 against a value around 443; a double carries that value to roughly 3e-11, so the data itself pins the exponent only to about 6e-7, and moving it that far moves the transformed values by 9.1e-7 relative. The reference's own optimiser stops at 1.48e-8 on the argument, well inside what the objective can distinguish. The Python equivalence table carries the arithmetic; it is the one family in this package held to a stated wider tolerance.

On a likelihood flat to rounding the exponent is not reproducible. A column whose spread is tiny against its offset — large values with a little noise — carries almost nothing about its exponent, and there numpy's vectorised exp, which parts from .NET's by an ulp on some inputs and some processors, and the log1p and expm1 this package writes, an ulp from the C library's on others, move where either optimiser stops. Measured against scikit-learn 1.9.1 on 100 columns of 1e10 plus noise, 66 Yeo-Johnson and 29 Box-Cox exponents differed by more than 1e-5 relative, and their transformed values with them.

Two rows are the extreme of it. Their optimum sits at λ ≈ 0, scikit-learn's exponents ranging from 1e-7 to 1e-4, so each optimiser stops on its rounding noise: on 150 random two-row columns, 72 Yeo-Johnson and 101 Box-Cox transforms part from scikit-learn's by more than 1e-5, where three to ten rows part on at most five in 150 (#1680).

Applies to — net10.0, netstandard2.0.

See also — PowerTransformerOptions, PowerMethod, QuantileTransformer, the feature transforming index, the Python equivalence table.

Members

Member What it does
PowerTransformer.Fit Fits one exponent per feature by maximum likelihood.
PowerTransformer.InverseTransform Undoes Transform.
PowerTransformer.Transform Raises each feature to its fitted power.