Delta Method for Ratio Metrics in A/B Testing with Python

Computes the confidence interval for the difference between two ratio metrics using the delta method, with mock A/B test data.

Medium Python 3.9+ Aug 9, 2026 A/B testing & experimentation 15 views 0 copies

Requires third-party packages — install first
pip install numpy scipy

Python code

51 lines
Python 3.9+
import numpy as np
from scipy.stats import norm


def delta_method_ratio_delta(control: np.ndarray, treatment: np.ndarray, confidence: float = 0.95):
    """Estimate confidence interval for ratio metric using delta method.

    Args:
        control: numerator/denominator pairs from control group (n x 2 array)
        treatment: numerator/denominator pairs from treatment group (m x 2 array)
        confidence: confidence level (default 0.95)

    Returns:
        (control_ratio, treatment_ratio, delta, ci_lower, ci_upper)
    """
    alpha = 1 - confidence
    z = norm.ppf(1 - alpha / 2)

    def ratio_stats(data):
        num = data[:, 0]
        den = data[:, 1]
        r = num.sum() / den.sum()
        n = len(data)
        var_num = np.var(num)
        var_den = np.var(den)
        cov = np.cov(num, den)[0, 1]
        mean_den = den.mean()
        # Delta method variance: var(ratio) ~ (var_num - 2*r*cov + r^2*var_den) / mean_den^2
        var_ratio = (var_num - 2 * r * cov + r**2 * var_den) / mean_den**2 / n
        return r, var_ratio

    r_control, var_control = ratio_stats(control)
    r_treatment, var_treatment = ratio_stats(treatment)
    delta = r_treatment - r_control
    se_delta = np.sqrt(var_control + var_treatment)
    ci_lower = delta - z * se_delta
    ci_upper = delta + z * se_delta
    return r_control, r_treatment, delta, ci_lower, ci_upper


if __name__ == "__main__":
    # Mock data: columns are [numerator, denominator]
    np.random.seed(42)
    control_data = np.array([[50, 100], [45, 95], [55, 110], [48, 102], [52, 98]])
    treatment_data = np.array([[60, 100], [58, 105], [62, 110], [55, 95], [59, 103]])

    result = delta_method_ratio_delta(control_data, treatment_data)
    print(f"Control ratio: {result[0]:.4f}")
    print(f"Treatment ratio: {result[1]:.4f}")
    print(f"Delta: {result[2]:.4f}")
    print(f"95% CI: ({result[3]:.4f}, {result[4]:.4f})")

Output

stdout
Control ratio: 0.5000
Treatment ratio: 0.5796
Delta: 0.0796
95% CI: (-0.0061, 0.1653)

How it works

The delta method approximates the variance of a ratio of two correlated random variables by taking a first-order Taylor expansion. Here, we propagate the variance of the numerator and denominator (and their covariance) through the ratio formula, scaling by the squared mean denominator. The standard error of the delta (difference between treatment and control ratios) is the square root of the sum of both group variances, assuming independence. The final confidence interval uses the normal quantile from scipy.stats.norm.ppf. This approach is standard for ratio metrics like conversion rates or revenue per user where the denominator is not fixed.

Common mistakes

  • Forgetting to account for the covariance between numerator and denominator in the variance formula.
  • Using `np.var` with default ddof=0 instead of sample variance (ddof=1) when data is a sample.
  • Assuming independent groups when the control and treatment are correlated (e.g., paired data).
  • Not normalizing the variance by the sample size when computing the standard error.

Variations

  1. Use bootstrap resampling to estimate the CI without the normality assumption.
  2. Use a log transformation and then back-transform to keep the interval positive for ratio metrics like revenue per user.

Real-world use cases

  • Measuring the lift in conversion rate (clicks per impression) between two web page variants in a growth experiment.
  • Estimating the confidence interval for revenue per user difference when evaluating a new checkout flow in e-commerce.
  • Assessing the impact on task success ratio (tasks completed per hour) when a support automation tool is rolled out to a test team.

Sponsored

Run locally

This sample needs third-party packages, so it cannot run in the browser IDE. Copy the code above, install the packages shown at the top, then run it in your own Python environment.

More from A/B testing & experimentation

Related tutorials and quizzes for this topic.