mixle.inference.nonparametric module¶
Classical nonparametric (rank-based) hypothesis tests.
Distribution-free two-sample, k-sample, paired, repeated-measures, ordered-alternative, and
goodness-of-fit tests, each returning a small result object with the statistic, p-value, and – where
standard – an effect size. Statistics are computed here (mid-ranks for ties); tail probabilities use
exact nulls wherever they are computable at reasonable cost (the Wilcoxon signed-rank subset-sum
DP at n <= 300 without ties or zeros; the runs test’s closed-form pmf at n <= 5000; the
two-sample KS at small samples) and the asymptotic reference distributions (normal / chi-square /
Student-t / Kolmogorov) with tie corrections otherwise. Not every asymptotic branch carries a
continuity correction (the Page test does not), and the remaining small-sample normal
approximations are approximations – see each test’s docstring.
Two independent samples :mann_whitney_u()(Wilcoxon rank-sum),brunner_munzel(),cliffs_delta(),ks_2samp()k independent samples :kruskal_wallis(),mood_median_test(),dunn_test()(post-hoc) Paired / one sample :wilcoxon_signed_rank(),sign_test()Repeated measures :friedman_test()Ordered alternatives :jonckheere_terpstra()(independent),page_trend_test()(repeated) Goodness of fit / 1-samp:ks_1samp(),runs_test()
- class MannWhitneyResult(statistic, statistic2, zscore, pvalue, rank_biserial, alternative, null_hypothesis='exchangeability (F = G); use brunner_munzel for unequal shapes')[source]
Bases:
objectResult of a two-sample Mann-Whitney U test.
- class WilcoxonResult(statistic, zscore, pvalue, rank_biserial, alternative, method='normal')[source]
Bases:
objectResult of a paired or one-sample Wilcoxon signed-rank test.
methodnames the null actually used (STAT-RR17-15):"exact"(full enumeration, the n <= 300 no-ties/no-zeros regime) or"normal"(tie/zero-corrected approximation).zscoreis signed FOR THE STATED ALTERNATIVE – positive means the data lean toward it – so an all-positive sample underalternative='greater'reports a positive z next to its small exact p, where the old min(W+, W-)-based z reported -2.02 beside p = 0.03125 and a rank-biserial of +1.
- class DunnResult(comparisons, zscores, pvalues, p_adjust)[source]
Bases:
objectPost-hoc Dunn pairwise comparisons after Kruskal-Wallis.
- class TestResult(statistic, pvalue, extra=<factory>)[source]
Bases:
objectGeneric statistic + p-value result;
extracarries test-specific fields (effect size, df, …).
- mann_whitney_u(x, y, *, alternative='two-sided', use_continuity=True)[source]
Mann-Whitney U / Wilcoxon rank-sum test for two independent samples.
THE NULL IS FULL EXCHANGEABILITY (
F = G), not mere stochastic equality: the reference variance is derived under identical distributions, so with equalP(X > Y) = 1/2but UNEQUAL shapes/spreads and unbalanced sample sizes the level is not controlled – measured 12.5% rejection at nominal 5% one way and 1.5% with the sizes reversed (STAT-RR17-17). For the stochastic-equality null under unequal shapes usebrunner_munzel(), whose variance estimates each group separately. Uses mid-ranks for ties, the tie-corrected normal approximation, and (default) a continuity correction.alternativeis'two-sided','greater'(x > y), or'less'. The rank-biserial correlation2*U1/(n1 n2) - 1is reported as the effect size;null_hypothesison the result names the null in force.
- cliffs_delta(x, y)[source]
Cliff’s delta effect size in [-1, 1]:
P(x > y) - P(x < y)(rank-based, ties count as 0).
- brunner_munzel(x, y, *, alternative='two-sided', distribution='t')[source]
Brunner-Munzel test: the generalized Wilcoxon test that does not assume equal variances/shapes.
Tests the stochastic-equality null
P(x < y) + 0.5 P(x = y) = 1/2.alternativeis'two-sided','greater'(x > y), or'less'– the same direction convention asmann_whitney_u()(and scipy).distribution='t'uses a Satterthwaite t reference,'normal'the normal approximation. The t reference is the better of the two but is still LIBERAL in small samples – below roughly 10 observations per group its true level runs above nominal (this is documented behavior of the approximation, not an implementation defect), so treat sub-10-per-group p-values near the threshold as optimistic; the studentized-permutation version of the test is the small-sample fix and is not implemented here. Reports the estimated relative effectp_hat = P(x < y) + 0.5 P(x = y)inextra.Completely separated samples (all of one group beyond all of the other) make the variance estimate 0 and the studentized statistic undefined – and NO valid p-value exists under this test’s own null. The permutation tail
1/C(n1+n2, n1)an earlier revision reported is exact only under FULL exchangeability (F = G), a strictly stronger hypothesis than Brunner-Munzel’s stochastic equality: withX = +/-1equiprobable andY = 0,P(X < Y) = 0.5holds exactly, yet all-X-below-Y has probability2^(-n1)– atn1 = 4the old report rejected 12.5% of that null at nominal 5% while quotingp = 0.0002(STAT-RR19-04). The result therefore reportspvalue = nan,statistic = +/-inf,extra['method'] = 'separation-no-valid-p-under-stochastic-equality', the observedp_hat, and – for callers prepared to ASSERT the stronger F = G null –extra['p_exchangeability'], the exact permutation bound labeled as exactly that. Usemann_whitney_u()or a permutation test when exchangeability is the hypothesis you mean.
- ks_2samp(x, y, *, alternative='two-sided')[source]
Two-sample Kolmogorov-Smirnov test: max gap between the two empirical CDFs.
The p-value is exact at small samples and asymptotic otherwise (scipy
method='auto'). The null distribution is distribution-free for CONTINUOUS data; with ties (discrete or rounded data) the p-value is conservative.
- ks_1samp(x, cdf, *, alternative='two-sided')[source]
One-sample Kolmogorov-Smirnov goodness-of-fit test against a fully-specified
cdfcallable.cdfmay be vectorized (ndarray -> ndarray) or scalar-only, such as the.cdfmethod of a fitted univariate mixle distribution; a scalar-only callable is evaluated element-wise. Mixtures, categoricals, composites, and sequence models define nocdf: for those, pass the CDF as your own callable (for a univariate mixture, the weighted sum of the component CDFs).The p-value is ASYMPTOTIC in every mode:
two-sideduses the limiting Kolmogorov distribution (scipy’smethod='asymp') and the one-sided modes use the large-sample exponential boundexp(-2 n D^2). No small-sample (Marsaglia-Tsang-Wang exact) correction is applied, so at smallnthe reported p-value is LARGER than the exact one – it understates the evidence against the hypothesized cdf and overstates goodness-of-fit (e.g. ~26% relative near p=0.005 at n=50; the gap shrinks asngrows). For an exact small-sample p-value usescipy.stats.ks_1samp(x, cdf, method='exact'); thestatistichere matches scipy’s to machine precision either way.
- kruskal_wallis(*samples)[source]
Kruskal-Wallis H test: the rank-based k-sample generalization of Mann-Whitney (one-way ANOVA).
Tie-corrected H with a chi-square(k-1) reference.
extracarriesdfand theepsilon_squaredeffect size(H - k + 1)/(N - k).- Parameters:
samples (Any)
- Return type:
TestResult
- mood_median_test(*samples, ties='below')[source]
Mood’s median test: contingency test that k samples sit alike around the POOLED median.
Cross-tabulates each observation as above / (at-or-below) the pooled grand median and tests independence of the resulting 2xk table.
extracarries thegrand_median, the reference used (method), andmin_expected_count.What rejection means – precisely: the groups differ in their probability of exceeding the pooled median. That is implied by unequal medians under a shift model, but it is NOT “the medians differ” unconditionally: groups with identical medians and different shapes near that median can reject, and the test has famously low power besides. Reference: the median split fixes BOTH margins of the table, so for k = 2 the conditional exact (Fisher) p-value is the calibrated one and is used automatically whenever any expected cell count is below 5 (the uncorrected chi-square over-rejects there); for k > 2 the chi-square approximation is all that is implemented – check
min_expected_countand treat p-values from tables with expected counts below ~5 as approximate.
- dunn_test(*samples, p_adjust='holm')[source]
Dunn’s post-hoc test: all pairwise rank-mean comparisons after a Kruskal-Wallis rejection.
Uses the pooled-rank z statistic with the shared tie-corrected variance, and adjusts the pairwise p-values by
'holm','bonferroni', or'none'.Each pairwise z is calibrated under the GLOBAL null (all k groups exchangeable), because both the pooled ranks and the shared variance come from the full pooled sample. That is exactly the null a post-hoc test runs under after rejecting it, so read the p-values as screening under partial nulls, not as k(k-1)/2 self-contained two-sample tests: when one group genuinely differs, its observations shift the pooled ranks and the shared variance for every OTHER pair too – with two identical groups plus one concentrated third, the identical pair’s nominal-5% rejection rate is ~24%. For a confirmatory conclusion about a specific pair, test that pair directly (
brunner_munzel()uses only the two groups involved) with your own multiplicity adjustment; use Dunn to rank candidates, not to certify them.
- wilcoxon_signed_rank(x, y=None, *, alternative='two-sided', zero_method='wilcox', correction=False)[source]
Wilcoxon signed-rank test for paired samples (or one sample vs 0).
Ranks
|d|ford = x - y(mid-ranks for ties), splits into positive / negative rank sums, and uses the EXACT subset-sum null when it is available –n <= 300with no zero differences and no tied|d|– and the tie-corrected normal approximation otherwise (the same regime switch SciPy and R make; the normal approximation is level-violating at very smalln, where its smallest attainable p sits below the exact one).zero_method='wilcox'drops zero differences (and their ranks);'pratt'keeps them in the ranking but drops them from the sums, with the matching Pratt/Cureton zero corrections applied to the null mean and variance (as scipy does).correctionapplies only to the normal branch (exact tails need no continuity repair). The matched-pairs rank-biserial correlation is reported as the effect size.
- sign_test(x, y=None, *, alternative='two-sided')[source]
Sign test for paired samples (or one sample vs 0): exact binomial test on the signs of
x - y.Only the directions of the differences are used (ties dropped), so it is maximally robust but less powerful than the signed-rank test.
extracarriesn_positiveandn(non-zero pairs).
- friedman_test(*measurements)[source]
Friedman test for k related samples (repeated measures): the rank-based repeated-measures ANOVA.
Pass each treatment as a separate equal-length array (one value per block). Ranks within each block, tie-corrects, and uses a chi-square(k-1) reference.
extracarriesdfand Kendall’sWconcordance effect size.- Parameters:
measurements (Any)
- Return type:
TestResult
- jonckheere_terpstra(*samples, alternative='increasing')[source]
Jonckheere-Terpstra test for an ORDERED alternative across independent samples.
More powerful than Kruskal-Wallis when the groups are expected to shift monotonically in the given order.
alternative='increasing'/'decreasing'/'two-sided'. Uses the tie-corrected normal approximation of the J statistic (sum of pairwise Mann-Whitney counts over ordered pairs).The group ORDER is part of the hypothesis and must be chosen BEFORE looking at the data (the same pre-specification the sibling
page_trend_test()states): the level calculation assumes one fixed ordering, and picking the ordering that best matches the observed group means – k!/2 candidate orderings – turns a nominal 5% test into a data-dredged one. If the ordering came from the data, this test’s p-value does not mean what it says.The null variance is the published Jonckheere-Terpstra one (Lehmann 1975), whose leading term is
[n(n-1)(2n+5) - sum n_i(n_i-1)(2n_i+5)] / 72– algebraically the same as the equivalent[n^2(2n+3) - sum n_i^2(2n_i+3)] / 72form. This implementation previously usedn(n-1)(2n+3) - sum n_i(n_i-1)(2n_i+3), mixing the two (MXR-080-1599): a hybrid that matches neither published expression and, critically, does NOT reduce to the Mann-Whitney variance for two ordered groups. For two groups of five with complete separation it understated the variance as 21.5278 against the requiredn1*n2*(n+1)/12 = 22.9167, reportingz=2.69408, p=0.003529where the rank-sum test givesz=2.61116, p=0.004512. The tied branch inherited the same altered base terms, including in itssum t_j(t_j-1)(2t_j+5)tie correction.Reproducing that cross-check: the quoted rank-sum numbers use the normal approximation WITHOUT a continuity correction, because this J statistic’s normal reference carries none – call
mann_whitney_u()withuse_continuity=Falseto match (its DEFAULT isTrue, which reports a different, corrected p on the same data). The difference between the defaults is the correction convention, not a defect in either test.
- page_trend_test(*measurements, decreasing=False)[source]
Page’s trend test for an ORDERED alternative in repeated measures.
Like Friedman but for a pre-specified ordering of the k treatments (the columns, in order). Tests
L = sum_j j * R_jagainst the normal approximation. Setdecreasing=Trueto predict the reverse ordering.extracarries the z-score.Ties are handled exactly, not ignored: within-block midranks enter
L, and the null variance is the exact permutation variance of the observed (possibly tied) midranks – per block,Var = sum_j (w_j - w-bar)^2 * sum_i (r_i - r-bar)^2 / (k - 1)under uniform within-block permutation, summed over blocks. With no ties this reduces algebraically to the textbookn k^2 (k+1)(k^2-1) / 144; with ties the textbook constant overstates the variance (tied midranks vary less), which made the test conservative and its z biased toward 0.
- runs_test(x, *, cutoff='median')[source]
Wald-Wolfowitz runs test for randomness of a binary/dichotomized sequence.
Dichotomizes
xabout its median (or a supplied numericcutoff) and tests whether the run count departs from what independence predicts (too few runs => clustering/trend; too many => over-alternation). Two-sided. The null is EXACT (the closed-form run-count distribution given(n1, n2), big-integer arithmetic) for alln1 + n2 <= 5000– the uncorrected normal approximation is level-violating at small and sparse sizes (exhaustive enumeration atn1 = n2 = 5rejects 20/252 = 7.94%, and atn = 61, n1 = 39.83%, at nominal 5%; STAT-RR17-16/STAT-RR19-14). The normal approximation applies only above 5000 (STAT-RR22-16: this sentence previously still said 60 while execution switched at 5001).extracarries the run count, z-score, andmethod("exact"/"normal").