BOSCHLOO_EXACT

Overview

The BOSCHLOO_EXACT function performs Boschloo’s exact test on a 2×2 contingency table to examine the association between two categorical variables. Introduced by R.D. Boschloo in 1970, this test is a uniformly more powerful alternative to Fisher’s exact test when analyzing 2×2 tables. For more information, see the SciPy documentation and the Wikipedia article on Boschloo’s test.

Boschloo’s test uses the p-value from Fisher’s exact test as its test statistic. The Boschloo p-value represents the probability under the null hypothesis of observing a Fisher’s exact p-value at least as extreme as the one computed from the observed data. This two-stage approach provides increased statistical power while maintaining exact validity.

The test evaluates whether two binomial proportions p_1 and p_2 (representing success rates in each column of the contingency table) are equal. Three alternative hypotheses are supported:

  • Two-sided (H_1: p_1 \neq p_2): Tests whether the proportions differ in either direction
  • Less (H_1: p_1 < p_2): Tests whether the first proportion is smaller
  • Greater (H_1: p_1 > p_2): Tests whether the first proportion is larger

The function returns two values: the statistic (the p-value from Fisher’s exact test) and the p-value (Boschloo’s test p-value). A small p-value (typically < 0.05) suggests evidence to reject the null hypothesis of equal proportions. This implementation uses SciPy’s boschloo_exact function from the scipy.stats module.

This example function is provided as-is without any representation of accuracy.

Excel Usage

=BOSCHLOO_EXACT(table, bex_alternative)
  • table (list[list], required): 2x2 contingency table with non-negative integer entries.
  • bex_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: Two-sided test with moderate counts

Inputs:

table bex_alternative
12 5 two-sided
7 9

Excel formula:

=BOSCHLOO_EXACT({12,5;7,9}, "two-sided")

Expected output:

Result
0.1137 0.1333

Example 2: Greater alternative with larger sample

Inputs:

table bex_alternative
74 31 greater
43 32

Excel formula:

=BOSCHLOO_EXACT({74,31;43,32}, "greater")

Expected output:

Result
0.0483 0.0356

Example 3: Less alternative hypothesis test

Inputs:

table bex_alternative
10 20 less
15 25

Excel formula:

=BOSCHLOO_EXACT({10,20;15,25}, "less")

Expected output:

Result
0.4585 0.3719

Example 4: Two-sided test with small counts

Inputs:

table bex_alternative
8 2 two-sided
1 5

Excel formula:

=BOSCHLOO_EXACT({8,2;1,5}, "two-sided")

Expected output:

Result
0.0245 0.0244

Python Code

from scipy.stats import boschloo_exact as scipy_boschloo_exact
import math

def boschloo_exact(table, bex_alternative='two-sided'):
    """
    Perform Boschloo's exact test on a 2x2 contingency table.

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.boschloo_exact.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        table (list[list]): 2x2 contingency table with non-negative integer entries.
        bex_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.
    """
    def to2d(x):
        return [[x]] if not isinstance(x, list) else x

    table = to2d(table)

    # Validate table structure
    if not isinstance(table, list) or len(table) != 2 or not all(isinstance(row, list) and len(row) == 2 for row in table):
        return "Invalid input: table must be a 2x2 list of non-negative integers."

    # Validate table values are integers
    try:
        arr = [[int(x) for x in row] for row in table]
    except (TypeError, ValueError):
        return "Invalid input: table must contain integers."

    # Validate non-negative values
    if any(x < 0 for row in arr for x in row):
        return "Invalid input: table must contain non-negative integers."

    # Validate alternative parameter
    if bex_alternative not in ['two-sided', 'less', 'greater']:
        return "Invalid input: bex_alternative must be 'two-sided', 'less', or 'greater'."

    try:
        res = scipy_boschloo_exact(arr, alternative=bex_alternative)
        stat = float(res.statistic)
        pval = float(res.pvalue)

        # Check for nan or inf values
        if math.isnan(stat) or math.isnan(pval) or math.isinf(stat) or math.isinf(pval):
            return "Invalid result: nan or inf encountered."

        return [[stat, pval]]
    except Exception as e:
        return f"scipy.stats.boschloo_exact error: {e}"

Online Calculator