Stats kolmogorovsmirnov twosample - CyrilB1531/lodestar GitHub Wiki

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

HomeStatsHypothesis tests

KolmogorovSmirnov.TwoSample

Compares two samples by the largest gap between their empirical distributions.

public static KsResult TwoSample(ReadOnlySpan<double> a, ReadOnlySpan<double> b, Alternative alternative = Alternative.TwoSided, ExactMethod method = ExactMethod.Auto, NanPolicy nanPolicy = NanPolicy.Propagate)

Parametersa and b are the two samples, each at least one value; both spans are read, never modified. alternative says which direction of gap counts: Alternative.TwoSided takes the largest gap in either direction, the one-sided values take the largest gap in one. method chooses the exact null distribution, its asymptotic approximation, or a choice between them by the sample sizes. nanPolicy says what to do with a NaN; scipy's nan_policy, defaulting to NanPolicy.Propagate.

ReturnsKsResult: the distance, the p-value, where that supremum is attained, and its sign.

ExceptionsArgumentException when either sample is empty, or nanPolicy is NanPolicy.Raise and either sample holds a NaN. ArgumentOutOfRangeException when method is ExactMethod.Exact, a.Length * b.Length exceeds 1,000,000, and the samples differ in size or the alternative is one-sided.

Example — two samples of the same size, shifted apart.

using Lodestar.Stats;

double[] left = [1.0, 2.0, 3.0, 4.0, 5.0];
double[] right = [3.0, 4.0, 5.0, 6.0, 7.0];

KsResult result = KolmogorovSmirnov.TwoSample(left, right);

double d = Math.Round(result.Statistic, 4);        // => 0.4
double p = Math.Round(result.PValue, 6);           // => 0.873016
double location = result.StatisticLocation;        // => 3
int sign = result.StatisticSign;                   // => 1

Remarks — a sign of +1 means left's empirical distribution exceeds right's at location; every value in left reaches 3 before right does, which is the point the largest gap is measured at here.

method chooses between an exact route and an asymptotic one, the same shape as MannWhitney.Test's and Wilcoxon.Paired's. For two samples of the same size, two-sided, Auto is exact while each holds at most 10,000 values, as scipy's is: that case has a closed form with no table. Otherwise Auto switches to the asymptotic route once a.Length * b.Length passes 10,000, purely because the exact answer stops being worth its cost there, not because it would be wrong.

The table route has a size bound Auto cannot cross; the equal-size two-sided closed form has none. Past a.Length * b.Length = 1,000,000, the lattice-path recurrence walks one row per step through two buffers, so its memory stays at two rows while its time grows with the product — 2.17 ms at 999 × 1,001, just under the bound. Passing ExactMethod.Exact past the bound throws; ExactMethod.Auto never does, falling back to the asymptotic answer instead, because nothing the caller wrote asked for an exact result — and Auto's own 10,000 threshold keeps it two orders of magnitude clear of the bound regardless.

Under NanPolicy.Propagate, a NaN reaches the statistic, the p-value and StatisticLocation. All three become NaN; StatisticSign becomes 0, the closest an int comes to carrying scipy's own nan there. Before this guard existed, a NaN anywhere in either sample hung Walk forever instead: sorted[index] == value is false for a NaN value, so neither sample's cursor ever advances.

Applies to — net10.0, netstandard2.0.

See alsoKsResult, Alternative, ExactMethod, the Python equivalence table.

⚠️ **GitHub.com Fallback** ⚠️