Skip to contents

Computes the exact randomization-distribution p-value and a probabilistic-index effect size for the two-group Jonckheere-Terpstra statistic — which, with exactly two groups (w in {0, 1}), coincides with the Wilcoxon-Mann-Whitney \(U\) statistic generalized to handle ties (repeated ordinal levels in y): $$U = \sum_{k} t_k \big(2 L_k + (n_k - t_k)\big) / 2,$$ summed over the \(K\) distinct observed levels of y (in increasing order), where \(n_k\) is the total count at level \(k\), \(t_k\) is the observed count of w == 1 subjects at level \(k\), and \(L_k\) is the number of subjects at strictly lower levels (this is the standard "number of favorable comparisons" Mann-Whitney statistic, adapted for tied/grouped ordinal data — a tie at the same level contributes \(1/2\) rather than 0 or 1). The exact (not asymptotic, not Monte Carlo) null/reference distribution of this statistic under the sharp null of no treatment effect is obtained by enumerating, via a dynamic-programming recursion over levels (recurse_jt_distribution()), every way to distribute n_treat "treated" labels among the \(n\) subjects consistent with the fixed per-level totals \(n_k\) — i.e. the exact multivariate hypergeometric randomization distribution of the statistic conditional on the observed level counts, with each configuration's probability computed in log-space from log-binomial-coefficient weights to avoid overflow for larger \(n\).

Usage

exact_jonckheere_terpstra_pval_cpp(y, w)

Arguments

y

Integer (or integer-coercible) vector of length \(n\) giving each subject's ordinal response value; ties (repeated values) are handled via the grouped Mann-Whitney formula above. Must not contain NA.

w

Integer (or integer-coercible) vector of length \(n\) with values in {0, 1} giving each subject's group membership; both groups must be non-empty and no NA is permitted.

Value

A list with components stat2 (twice the observed \(U\) statistic, an integer, used internally to keep the enumeration in integer arithmetic), n_treat, n_control (the two group sizes), superiority (the probabilistic-index effect size described above), p_lower, p_upper (the exact one-sided randomization-distribution tail probabilities), and p_exact (the exact two-sided p-value).

Details

Randomization test, not a model-based test. This is a randomization (permutation) test in the Fisherian sense: it conditions on the observed marginal level counts \(n_k\) and the group sizes n_treat/n_control, and asks how extreme the observed statistic is relative to every other way those same labels could have been randomly assigned, so its validity does not depend on any distributional assumption about y beyond exchangeability under the null. The two-sided p-value is \(p_{\mathrm{exact}} = \min(1, 2 \min(p_{\mathrm{lower}}, p_{\mathrm{upper}}))\), where \(p_{\mathrm{lower}}\)/\(p_{\mathrm{upper}}\) are the exact one-sided tail probabilities of the randomization distribution at or below / at or above the observed statistic.

Effect size (superiority). superiority is the probabilistic index \(\Pr(Y_T > Y_C) + \tfrac{1}{2}\Pr(Y_T = Y_C)\) (equivalently \(U\) rescaled to \([0, 1]\) by dividing by \(n_{\mathrm{treat}} \cdot n_{\mathrm{control}}\)), the probability a randomly chosen treated subject's ordinal outcome exceeds a randomly chosen control subject's, counting ties as half a win; 0.5 indicates no stochastic ordering between groups, and 1/0 indicate the treated group's outcomes are uniformly higher/lower.

Input conventions. y is coerced to integer and treated as an ordinal (or any orderable-by-integer-value) response with an arbitrary number of tied levels; w must be an integer/coercible-to-integer vector of {0, 1} values with both groups non-empty. NA in either y or w is not permitted and raises an error, as does a non-{0,1} value in w or an empty input.

Complexity. The recursion's state space scales with the number of distinct possible statistic values (\(O(n_{\mathrm{treat}} \cdot n_{\mathrm{control}})\) many), and thread-local buffers are reused (not reallocated) across repeated calls within the same thread for the same or smaller problem sizes; this exact enumeration is exponential in the number of distinct levels/group sizes in the worst case (unlike an asymptotic normal-approximation JT test), so it is intended for small-to- moderate \(n\) where exactness matters more than raw speed.

See also

Mann-Whitney U test and Jonckheere's trend test for background; analogous Python API: SciPy mannwhitneyu (method="exact" for the same exact-enumeration approach, though SciPy's exact path does not handle ties the same way).