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]]

Online Calculator