Preprocessing knnimputer transform - 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 › Encoding and imputation
Fills every missing value from its nearest donors among the fitted rows.
public double[] Transform(ReadOnlySpan<double> samples)Parameters — samples is the matrix to fill, row-major,
FeatureCount values per row, where a NaN is a missing value.
Returns — a new matrix, OutputFeatureCount values per row; the input is
never written to.
Exceptions — ArgumentException when samples holds a partial row or an infinity.
ArgumentOutOfRangeException when the number of distances needed exceeds the ceiling below.
Example — the same two gaps, weighted two ways.
using Lodestar.Preprocessing;
double[] rows =
[
1.0, 2.0, double.NaN,
3.0, 4.0, 3.0,
double.NaN, 6.0, 5.0,
8.0, 8.0, 7.0,
];
KnnImputer uniform = KnnImputer.Fit(
rows, 3, new KnnImputerOptions { NeighbourCount = 2 });
KnnImputer weighted = KnnImputer.Fit(
rows, 3, new KnnImputerOptions { NeighbourCount = 2, Weights = NeighbourWeights.Distance });
double byMean = uniform.Transform(rows)[2]; // => 4
double byDistance = Math.Round(weighted.Transform(rows)[2], 4); // => 3.6667Ties between donors go to the lower row. The reference breaks them by numpy.argpartition,
whose pick varies with the CPU's SIMD tier, so it has no single order to match; the nearest are kept
in a bounded heap rather than by sorting every donor per missing cell (#1230). The distances
themselves are summed directly, where the reference expands them through BLAS, so two donors a few
ulps apart can rank the other way round.
Remarks — the call is refused past 100 million distance terms. The cost is
rows × fitted rows × features, and on a Ryzen 7 8700G a hundred million terms over one feature
take about 0.35 s and the same count over ten features about 1.6 s (measured 2026-09-23). Past
that the call throws rather than running for however long it would take — the same stance
MannWhitney takes on its exact table. Split the receiving rows into batches to go further; the
fitted donors are the expensive half and they are shared.
A donor is a fitted row that has the missing feature, not simply a near row. The nearest rows
are ranked by nan_euclidean distance, and the first NeighbourCount of them that actually carry
the feature being filled are the ones averaged — so a gap in a rare feature can draw on donors
further away than the nominal neighbours.
A value with no donor at all falls back to the feature's mean over the fitted rows, which is
the reference's behaviour. A feature with no value anywhere in the fitted matrix was already
dropped at Fit.
Applies to — net10.0, netstandard2.0.
See also — KnnImputer.Fit,
NeighbourWeights, KnnImputer.