BWS_TEST
Overview
The BWS_TEST function performs the Baumgartner-Weiss-Schindler (BWS) test, a nonparametric statistical test used to determine whether two independent samples are drawn from the same underlying distribution. Originally proposed by Baumgartner, Weiß, and Schindler in 1998, this test offers advantages over traditional alternatives in detecting distributional differences, particularly in the tails of distributions.
Unlike the Kolmogorov-Smirnov test, Wilcoxon-Mann-Whitney test, and Cramér-von Mises test, the BWS test weights the integral of the squared difference between empirical cumulative distribution functions (CDFs) by the variance of that difference. This weighting scheme places greater emphasis on the tails of the distributions, which increases the statistical power of the test in many practical applications where differences occur at the extremes.
The test statistic B is computed by comparing the ranks of observations from both samples. For two-sided tests, the statistic measures the overall difference between distributions. For one-sided alternatives, a signed version of the statistic indicates whether one distribution is stochastically greater or less than the other. When the distribution of the first sample is stochastically greater than the second, the statistic tends to be positive.
The p-value is computed using a permutation approach, which provides exact inference under the null hypothesis of equal distributions. The function supports three alternative hypotheses:
- two-sided: the distributions are not equal (F(u) ≠ G(u) for at least one u)
- less: the first distribution is stochastically less than the second (F(u) ≥ G(u) for all u)
- greater: the first distribution is stochastically greater than the second (F(u) ≤ G(u) for all u)
This implementation uses SciPy’s bws_test function. For theoretical background, see Neuhäuser, M. (2005), “Exact Tests Based on the Baumgartner-Weiss-Schindler Statistic: A Survey,” Statistical Papers, 46(1), 1-29.
This example function is provided as-is without any representation of accuracy.
Excel Usage
=BWS_TEST(x, y, bws_alternative)
x(list[list], required): First sample data as a 2D list (column vector)y(list[list], required): Second sample data as a 2D list (column vector)bws_alternative(str, optional, default: “two-sided”): Defines the alternative hypothesis for the test
Returns (list[list]): 2D list [[statistic, p_value]], or error message string.
Examples
Example 1: Demo case 1
Inputs:
| x | y |
|---|---|
| 1.2 | 2.1 |
| 2.3 | 2.9 |
| 3.1 | 3.7 |
| 4 | 4.5 |
Excel formula:
=BWS_TEST({1.2;2.3;3.1;4}, {2.1;2.9;3.7;4.5})
Expected output:
| Result | |
|---|---|
| 0.3255 | 1 |
Example 2: Demo case 2
Inputs:
| x | y | bws_alternative |
|---|---|---|
| 1.2 | 2.1 | less |
| 2.3 | 2.9 | |
| 3.1 | 3.7 | |
| 4 | 4.5 |
Excel formula:
=BWS_TEST({1.2;2.3;3.1;4}, {2.1;2.9;3.7;4.5}, "less")
Expected output:
| Result | |
|---|---|
| -0.3255 | 0.3571 |
Example 3: Demo case 3
Inputs:
| x | y | bws_alternative |
|---|---|---|
| 1.2 | 2.1 | greater |
| 2.3 | 2.9 | |
| 3.1 | 3.7 | |
| 4 | 4.5 |
Excel formula:
=BWS_TEST({1.2;2.3;3.1;4}, {2.1;2.9;3.7;4.5}, "greater")
Expected output:
| Result | |
|---|---|
| -0.3255 | 0.6571 |
Example 4: Demo case 4
Inputs:
| x | y |
|---|---|
| 10 | 2 |
| 12 | 3 |
| 13 | 4 |
| 15 | 5 |
Excel formula:
=BWS_TEST({10;12;13;15}, {2;3;4;5})
Expected output:
| Result | |
|---|---|
| 3.7109 | 0.0286 |
Python Code
import math
from scipy.stats import bws_test as scipy_bws_test
def bws_test(x, y, bws_alternative='two-sided'):
"""
Performs the Baumgartner-Weiss-Schindler test on two independent samples.
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.bws_test.html
This example function is provided as-is without any representation of accuracy.
Args:
x (list[list]): First sample data as a 2D list (column vector)
y (list[list]): Second sample data as a 2D list (column vector)
bws_alternative (str, optional): Defines the alternative hypothesis for the test Valid options: Two-sided, Less, Greater. Default is 'two-sided'.
Returns:
list[list]: 2D list [[statistic, p_value]], or error message string.
"""
# Validate x structure and content
if not isinstance(x, list):
return "Invalid input: x must be a 2D list."
if not x or not all(isinstance(row, list) for row in x):
return "Invalid input: x must be a 2D list."
# Validate y structure and content
if not isinstance(y, list):
return "Invalid input: y must be a 2D list."
if not y or not all(isinstance(row, list) for row in y):
return "Invalid input: y must be a 2D list."
# Flatten and convert to float
try:
x_flat = [float(item) for row in x for item in row]
y_flat = [float(item) for row in y for item in row]
except (TypeError, ValueError):
return "Invalid input: x and y must contain only numeric values."
# Check minimum sample size
if len(x_flat) < 2:
return "Invalid input: x must contain at least two values."
if len(y_flat) < 2:
return "Invalid input: y must contain at least two values."
# Validate alternative parameter
if bws_alternative not in ['two-sided', 'less', 'greater']:
return "Invalid input: bws_alternative must be 'two-sided', 'less', or 'greater'."
# Perform the test
try:
result = scipy_bws_test(x_flat, y_flat, alternative=bws_alternative)
except ValueError as e:
return f"Invalid input: {str(e)}"
except Exception as e:
return f"Error performing BWS test: {str(e)}"
# Extract and validate results
try:
stat = float(result.statistic)
pvalue = float(result.pvalue)
except (TypeError, ValueError):
return "Error: could not convert test results to float."
# Check for invalid numeric results
if math.isnan(stat) or math.isinf(stat):
return "Error: test statistic is NaN or infinite."
if math.isnan(pvalue) or math.isinf(pvalue):
return "Error: p-value is NaN or infinite."
return [[stat, pvalue]]