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.
Home › Stats › Hypothesis tests
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)Parameters — a 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.
Returns — KsResult: the distance, the p-value, where that supremum is attained, and its
sign.
Exceptions — ArgumentException 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; // => 1Remarks — 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 also — KsResult, Alternative,
ExactMethod, the Python equivalence table.