Stats mannwhitney test - 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

MannWhitney.Test

Compares two independent samples by their ranks.

public static TestResult Test(ReadOnlySpan<double> x, ReadOnlySpan<double> y, Alternative alternative = Alternative.TwoSided, Continuity continuity = Continuity.Applied, ExactMethod method = ExactMethod.Auto, NanPolicy nanPolicy = NanPolicy.Propagate)

Parameters โ€” x and y are the two samples, each at least one value; both spans are read, never modified. alternative says which tail the p-value covers. continuity says whether the normal approximation gets the half-unit correction; it is ignored on the exact branch, where there is nothing to approximate. method chooses the exact null distribution, its normal approximation, or a choice between them by sample size and ties. nanPolicy says what to do with a NaN; scipy's nan_policy, defaulting to NanPolicy.Propagate.

Returns โ€” TestResult: U for x, and the p-value.

Exceptions โ€” ArgumentException when either sample is empty, or nanPolicy is NanPolicy.Raise and either sample holds a NaN. ArgumentOutOfRangeException when method is ExactMethod.Exact and x.Length * y.Length exceeds 20,000.

Example โ€” a control group and a treated group, one value tied across them.

using Lodestar.Stats;

double[] control = [7.0, 3.0, 6.0, 2.0, 8.0, 5.0];
double[] treated = [9.0, 12.0, 8.0, 11.0, 15.0, 10.0];

TestResult result = MannWhitney.Test(control, treated);

double u = result.Statistic;                    // => 0.5
double p = Math.Round(result.PValue, 6);         // => 0.006392

Remarks โ€” control and treated share the value 8, so the pooled sample holds a tie and ExactMethod.Auto falls straight to the normal approximation โ€” untied, both samples here are small enough (six values each, at or under the eight-value bound Auto checks) that it would have taken the exact route instead. Asking for ExactMethod.Exact explicitly still answers, just not the same number: on this data it gives 0.004329 rather than 0.006392, because scipy computes an exact p-value on tied data too instead of refusing, and this package matches that rather than raising on a case scipy accepts.

Under NanPolicy.Propagate, a NaN reaches the statistic and the p-value. The check runs before either sample is ranked โ€” unguarded, a NaN would sort to one end of its sample and take a finite rank like any other value.

The exact route has a size bound Auto cannot cross. x.Length * y.Length above 20,000 costs tens of seconds to enumerate โ€” the table is (m + 1) ร— (nยทm + 1) and grows with the square of that product. 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. The bound on the smaller sample alone is eight, not both: x.Length = 8, y.Length = 10_000 still qualifies for Auto's exact route by that rule and would build a multi-gigabyte table if the product bound did not also apply.

Applies to โ€” net10.0, netstandard2.0.

See also โ€” TTest.Independent for the parametric counterpart, Wilcoxon.Paired for paired measurements, ExactMethod, the Python equivalence table.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ