Tutorials

Mann-Whitney U Test with SciPy

The Mann-Whitney U test is a nonparametric alternative to the independent samples t-test. It is useful when the groups are independent but the normality assumption is questionable or when you want a rank-based comparison.

### Basic Mann-Whitney U Test

import numpy as np
from scipy import stats

np.random.seed(44)

group_a = np.random.exponential(scale=1.0, size=40)
group_b = np.random.exponential(scale=1.9, size=40)

result = stats.mannwhitneyu(group_a, group_b, alternative="two-sided")

print(f"Median of group A: {np.median(group_a):.3f}")
print(f"Median of group B: {np.median(group_b):.3f}")
print(f"U statistic: {result.statistic:.3f}")
print(f"P-value: {result.pvalue:.6f}")
Median of group A: 0.612
Median of group B: 1.654
U statistic: 521.000
P-value: 0.007365
### Interpreting the Result

import numpy as np
from scipy import stats

np.random.seed(44)

group_a = np.random.exponential(scale=1.0, size=40)
group_b = np.random.exponential(scale=1.9, size=40)

result = stats.mannwhitneyu(group_a, group_b, alternative="two-sided")

if result.pvalue < 0.05:
    print("Reject the null hypothesis: the groups differ in distribution or central tendency.")
else:
    print("Fail to reject the null hypothesis: no strong difference was detected.")
Reject the null hypothesis: the groups differ in distribution or central tendency.
### Visualizing the Two Groups

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(44)

group_a = np.random.exponential(scale=1.0, size=40)
group_b = np.random.exponential(scale=1.9, size=40)

plt.figure(figsize=(9, 5))
plt.boxplot([group_a, group_b], tick_labels=["Group A", "Group B"])
plt.ylabel("Value")
plt.title("Independent Groups for Mann-Whitney U Test")
plt.grid(axis="y", linestyle="--", alpha=0.4)
plt.show()
### Practical Example: Response Times for Two Interfaces

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

np.random.seed(61)

interface_a = np.random.gamma(shape=2.5, scale=180, size=50)
interface_b = np.random.gamma(shape=2.5, scale=300, size=50)

result = stats.mannwhitneyu(interface_a, interface_b, alternative="two-sided")

print(f"Median response time A: {np.median(interface_a):.1f} ms")
print(f"Median response time B: {np.median(interface_b):.1f} ms")
print(f"P-value: {result.pvalue:.6f}")
print("Conclusion: the interfaces differ significantly." if result.pvalue < 0.05 else "Conclusion: no significant difference detected.")

plt.figure(figsize=(9, 5))
plt.hist(interface_a, bins=12, alpha=0.6, label="Interface A")
plt.hist(interface_b, bins=12, alpha=0.6, label="Interface B")
plt.xlabel("Response time (ms)")
plt.ylabel("Count")
plt.title("Response Time Distributions")
plt.legend()
plt.show()
Median response time A: 336.4 ms
Median response time B: 562.8 ms
P-value: 0.000307
Conclusion: the interfaces differ significantly.
### Conclusion

The Mann-Whitney U test is a strong choice when you want a robust comparison between two independent groups without relying on normality. A chart helps explain what the rank-based result is capturing.