Topics
A/B testing is a randomized experiment comparing treatment policies on a prespecified estimand. The statistical method should follow the randomization unit, outcome type, effect size of interest, and stopping rule. However, traditional fixed-sample A/B testing can be inefficient, especially for organizations with limited user traffic or when swift decision-making is crucial. Sequential methods can support repeated looks or continuous monitoring while controlling specified operating characteristics, but only when the stopping rule and test are designed together.
The useful distinction is between a fixed-horizon experiment, in which the stopping time is determined in advance, and a sequential design, in which the stopping rule is part of the inferential procedure. The Sequential Probability Ratio Test provides a clean mathematical example because its likelihood-ratio boundaries are derived from prespecified Type I and Type II error targets. The implementation examples below illustrate that mechanism, but they should be read as demonstrations of a simple Bernoulli SPRT rather than as a drop-in replacement for a two-arm randomized experiment.
The Foundations of A/B Testing: Benefits and Limitations
Understanding Traditional A/B Testing
A/B testing, or split testing, involves comparing two versions of a variable—such as a webpage, advertisement, or product feature—to determine which performs better according to a specific metric (e.g., conversion rate, click-through rate). The process typically includes:
- Hypothesis Formulation: Define the null hypothesis (H₀) that there is no difference between versions, and the alternative hypothesis (H₁) that there is a significant difference.
- Sample Size Determination: Calculate the required sample size to detect a statistically significant effect, based on desired power and significance level.
- Data Collection: Randomly assign users to either version A or B and collect data until the sample size is reached.
- Statistical Analysis: Use appropriate statistical tests (e.g., t-tests, chi-squared tests) to determine if observed differences are significant.
Example Scenario
Consider testing two pricing strategies:
- Version A: The product is priced at $19.99.
- Version B: The product is priced at $24.99 with a 20% discount, effectively reducing it to $19.99.
Despite the same final price, psychological pricing suggests that consumers might perceive greater value in receiving a discount, potentially influencing conversion rates.
Advantages of Traditional A/B Testing
- Empirical Decision-Making: Relies on data rather than intuition.
- Controlled Experiments: Allows for isolating variables and testing specific hypotheses.
- Statistical Rigor: Provides a framework for controlling Type I and Type II errors.
Limitations in Low-Traffic Environments
- Extended Timeframes: Reaching the required sample size can be time-consuming for low-traffic sites.
- Inflexibility: The predetermined sample size cannot be adjusted mid-experiment without affecting validity.
- Ethical Concerns: Exposing users to potentially inferior versions for extended periods.
- Peeking Problem: Monitoring results before the experiment concludes can inflate false-positive rates.
Sequential Testing: A Theoretical Exploration
Introduction to Sequential Analysis
Sequential analysis permits repeated evaluation because the probability of stopping is incorporated into the design. This is fundamentally different from repeatedly applying an ordinary fixed-sample test until a desirable p-value appears. In a valid sequential procedure, the evidence boundary, the hypotheses, and the monitoring rule are defined together, so the nominal error guarantees refer to the entire stopping procedure rather than to one isolated interim look.
The Sequential Probability Ratio Test (SPRT)
Developed by Abraham Wald, the classical SPRT compares two simple hypotheses by accumulating the log-likelihood ratio as observations arrive. Because both hypotheses specify complete probability models, the statistic has a direct interpretation: every new observation adds evidence in favor of one model or the other, and sampling stops only when that accumulated evidence crosses a prespecified boundary.
Likelihood Ratio (LR)
The likelihood ratio at any point $n$ is defined as:
- $P(\text{Data} \mid H_1)$: Probability of observing the data under the alternative hypothesis.
- $P(\text{Data} \mid H_0)$: Probability of observing the data under the null hypothesis.
Decision Boundaries
Two thresholds are established to decide when to stop the test:
- Upper Boundary (A): If $LR_n \geq A$, reject H₀ in favor of H₁.
- Lower Boundary (B): If $LR_n \leq B$, accept H₀ and reject H₁.
These boundaries are calculated based on the desired error rates:
- $\alpha$: Probability of Type I error (false positive).
- $\beta$: Probability of Type II error (false negative).
Updating the Likelihood Ratio
For Bernoulli trials (e.g., conversions), the likelihood ratio after each observation is updated as:
-
Conversion (Success):
$$ LR_n = LR_{n-1} \times \frac{p_1}{p_0} $$ -
No Conversion (Failure):
$$ LR_n = LR_{n-1} \times \frac{1 - p_1}{1 - p_0} $$
where:
- $p_0$: Conversion rate under H₀.
- $p_1$: Conversion rate under H₁.
What the SPRT buys, and what it does not
The main attraction of the SPRT is expected sample efficiency when the data-generating parameter is sufficiently close to one of the two simple hypotheses. It also provides a principled stopping mechanism and controls the specified decision errors for that model. Those advantages do not mean that every online experiment should use an SPRT. Composite alternatives, heterogeneous users, delayed outcomes, ratio metrics, novelty effects, multiple guardrails, and treatment-control comparisons all require extensions beyond the one-stream Bernoulli example.
Implementing Sequential Testing in Practice
Step-by-Step Procedure
-
Define Hypotheses:
- H₀: The conversion rate is $p_0$.
- H₁: The conversion rate is $p_1$.
-
Set Error Rates:
- Choose acceptable levels for $\alpha$ and $\beta$.
-
Calculate Decision Boundaries:
- Compute $A$ and $B$ using the formulas provided.
-
Collect Data Sequentially:
- After each observation, update the likelihood ratio $LR_n$.
-
Apply Decision Rules:
- If $LR_n \geq A$, stop and reject H₀.
- If $LR_n \leq B$, stop and accept H₀.
- Otherwise, continue collecting data.
Practical Considerations
- Design alternatives: $p_0$ and $p_1$ are hypotheses, not estimates produced after looking at the experiment. The alternative should correspond to a minimum effect worth detecting.
- Sample Size Limit: Although SPRT doesn't require a fixed sample size, setting a maximum limit can prevent indefinite testing.
- Data Quality: Ensure data is collected and recorded accurately in real-time.
One-rate Bernoulli SPRT example
Suppose a single Bernoulli stream is tested against $p_0=0.05$ versus $p_1=0.07$. This illustrates the mechanics of the SPRT, not the full treatment-control A/B problem.
- Set $\alpha = 0.05$ and $\beta = 0.20$.
-
Calculate Boundaries:
$$ A = \frac{1 - 0.20}{0.05} = 16, \quad B = \frac{0.20}{1 - 0.05} \approx 0.211 $$ -
Update LR After Each Observation:
- For a conversion: Multiply $LR_n$ by $\frac{0.07}{0.05} = 1.4$.
- For no conversion: Multiply $LR_n$ by $\frac{0.93}{0.95} \approx 0.9789$.
Continue this process until $LR_n$ crosses $A$ or $B$.
Advanced Statistical Considerations
Controlling Type I Error with Alpha Spending Functions
In sequential testing, repeatedly analyzing data increases the risk of Type I errors. Alpha spending functions allocate the overall $\alpha$ across interim analyses to control the cumulative error rate.
- Lan-DeMets Approach: Allows flexibility in the timing and number of interim looks.
- Implementation: Adjust decision boundaries at each analysis based on the amount of $\alpha$ "spent" so far.
Group Sequential Designs
An alternative to continuous monitoring is evaluating data at predetermined points.
- Benefits: Simplifies analysis and decision-making.
- Methods: Use of statistical boundaries like O'Brien-Fleming or Pocock boundaries to adjust significance levels.
Bayesian Sequential Analysis
- Framework: Incorporates prior beliefs and updates them with observed data.
- Stopping Rules: Based on posterior probabilities exceeding certain thresholds.
- Advantages: Offers intuitive interpretations and can handle complex models.
Practical Implementation: Code Examples
Below are enhanced code examples demonstrating how to implement SPRT in R, JavaScript, and Python, including advanced features like visualization and simulations.
R Implementation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# Load necessary packages
if (!require("ggplot2")) install.packages("ggplot2")
library(ggplot2)
# Parameters for the test
p0 <- 0.05 # Null hypothesis conversion rate
p1 <- 0.07 # Alternative hypothesis conversion rate
alpha <- 0.05
beta <- 0.20
# Decision boundaries
A <- (1 - beta) / alpha
B <- beta / (1 - alpha)
# Simulate experiment
set.seed(123)
n_users <- 500
conversions <- rbinom(n_users, 1, p1)
# Initialize variables
LR <- numeric(n_users + 1)
LR[1] <- 1
decision <- NULL
# Sequential test
for (i in 1:n_users) {
if (conversions[i] == 1) {
LR[i + 1] <- LR[i] * (p1 / p0)
} else {
LR[i + 1] <- LR[i] * ((1 - p1) / (1 - p0))
}
if (LR[i + 1] >= A) {
decision <- "Reject H0 (Accept H1)"
break
} else if (LR[i + 1] <= B) {
decision <- "Accept H0 (Reject H1)"
break
}
}
# Output decision
cat("Decision:", decision, "after", i, "observations.\n")
# Plot LR
df <- data.frame(Observation = 0:i, LR = LR[1:(i + 1)])
ggplot(df, aes(x = Observation, y = LR)) +
geom_line() +
geom_hline(yintercept = c(A, B), linetype = "dashed", color = c("red", "green")) +
scale_y_log10() +
labs(title = "SPRT Likelihood Ratio Over Time", y = "Likelihood Ratio (log scale)") +
theme_minimal()
Explanation
- Visualization: The plot provides a visual representation of how the likelihood ratio evolves.
- Termination: The loop exits once a boundary is crossed, indicating a decision.
- Reproducibility: Setting a seed ensures consistent results.
JavaScript Implementation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Parameters
const p0 = 0.05;
const p1 = 0.07;
const alpha = 0.05;
const beta = 0.20;
// Decision boundaries
const A = (1 - beta) / alpha;
const B = beta / (1 - alpha); // Simulate experiment
const n_users = 500;
const conversions = [];
for (let i = 0; i < n_users; i++) {
conversions.push(Math.random() < p1 ? 1 : 0);
} // Initialize variables
let LR = [1];
let decision = null;
// Sequential test
for (let i = 0; i < n_users; i++) {
if (conversions[i] === 1) {
LR.push(LR[i] * (p1 / p0));
} else {
LR.push(LR[i] * ((1 - p1) / (1 - p0)));
} if (LR[i + 1] >= A) {
decision = "Reject H0 (Accept H1)";
console.log(`Decision: ${decision} after ${i + 1} observations.`);
break;
} else if (LR[i + 1] <= B) {
decision = "Accept H0 (Reject H1)";
console.log(`Decision: ${decision} after ${i + 1} observations.`);
break;
}
} // Visualization can be added using charting libraries like Chart.js or D3.js
Explanation
- Loop Termination: The loop breaks once a decision is reached.
- Scalability: The code can be extended to handle real-time data streams.
- Visualization: Implementing a chart using JavaScript libraries can provide real-time monitoring in web applications.
Python Implementation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import numpy as np
import matplotlib.pyplot as plt
# Parameters
p0 = 0.05
p1 = 0.07
alpha = 0.05
beta = 0.20
# Decision boundaries
A = (1 - beta) / alpha
B = beta / (1 - alpha)
# Simulate experiment
np.random.seed(42)
n_users = 500
conversions = np.random.binomial(1, p1, n_users)
# Initialize variables
LR = [1]
decision = None
# Sequential test
for i in range(n_users):
if conversions[i] == 1:
LR.append(LR[i] * (p1 / p0))
else:
LR.append(LR[i] * ((1 - p1) / (1 - p0)))
if LR[i + 1] >= A:
decision = "Reject H0 (Accept H1)"
print(f"Decision: {decision} after {i + 1} observations.")
break
elif LR[i + 1] <= B:
decision = "Accept H0 (Reject H1)"
print(f"Decision: {decision} after {i + 1} observations.")
break
# Plot LR
plt.figure(figsize=(10, 6))
plt.plot(range(len(LR)), LR, label='Likelihood Ratio')
plt.axhline(y=A, color='r', linestyle='--', label='Upper Boundary (A)')
plt.axhline(y=B, color='g', linestyle='--', label='Lower Boundary (B)')
plt.yscale('log')
plt.xlabel('Number of Observations')
plt.ylabel('Likelihood Ratio (log scale)')
plt.title('SPRT Likelihood Ratio Over Time')
plt.legend()
plt.show()
Explanation
- Matplotlib Visualization: Provides a clear graph of the likelihood ratio progression.
- Error Handling: The code assumes ideal conditions; in practice, include checks for data integrity.
- Extensions: The code can be modified to simulate multiple tests to study the distribution of stopping times.
Advantages of Sequential Testing
Efficiency Gains
- Reduced Sample Sizes: Often requires fewer observations to reach a conclusion.
- Cost Savings: Lower data collection costs and faster decision cycles.
Flexibility
- Planned repeated monitoring: valid stopping can be built into the procedure.
- Adaptive designs: adaptations require methods whose error guarantees explicitly allow the adaptation; arbitrary mid-test changes invalidate the original calibration.
Ethical Considerations
- User Experience: Minimizes exposure to less effective variants.
- Resource Allocation: Redirect efforts to more promising initiatives sooner.
Potential Pitfalls and Limitations
Statistical Complexity
- Technical Expertise Required: Misapplication can lead to incorrect conclusions.
- Software Limitations: Not all statistical packages readily support sequential methods.
Risk of Bias
- Early Stopping Bias: Estimates of effect size may be inflated.
- Data Dependency: Assumes independence of observations, which may not hold in all contexts.
Operational Challenges
- Infrastructure Needs: Requires systems capable of real-time data processing.
- Stakeholder Buy-In: May need to educate team members on the methodology.
Conclusion
Sequential testing offers a sophisticated approach to experimentation, particularly beneficial in environments where data is scarce or rapid decisions are necessary. By allowing continuous data evaluation and maintaining control over error rates, it strikes a balance between efficiency and statistical rigor. However, the method's complexity necessitates a solid understanding of statistical principles to implement correctly. Organizations should weigh the benefits against the potential challenges, considering factors like team expertise, infrastructure capabilities, and the specific context of their experiments. When applied thoughtfully, sequential testing can significantly enhance the decision-making process, leading to faster insights and more effective strategies in product development and beyond.
References
- Wald, A. (1947). Sequential Analysis. Wiley.
- Jennison, C., & Turnbull, B. W. (2000). Group Sequential Methods with Applications to Clinical Trials. Chapman & Hall/CRC.
- Lan, K. K., & DeMets, D. L. (1983). "Discrete sequential boundaries for clinical trials". Biometrika, 70(3), 659-663.
- Whitehead, J. (1997). The Design and Analysis of Sequential Clinical Trials. Wiley.
The two-arm estimand comes first
For conversion rates
a common estimand is the absolute lift
The scientific null might be
while a business decision may care about
for a minimum worthwhile lift $delta$. Testing one rate against a historical benchmark is not equivalent to randomizing users between A and B. The latter protects the comparison from time trends and other concurrent changes under the randomization assumptions.
Ratio metrics and clustered users
Many product metrics are not IID Bernoulli observations. Examples include:
- revenue per user;
- sessions nested within users;
- multiple conversions by one user;
- ratio metrics such as revenue / active user.
The randomization unit should usually be the unit used for inference. Treating repeated sessions as independent observations can make uncertainty far too small. Cluster-robust, delta-method, bootstrap, or randomization-based procedures may be required depending on the metric.
Early stopping biases the point estimate
A sequentially valid test can control Type I error and still produce a biased effect estimate conditional on stopping early. Experiments tend to stop when the observed effect is unusually large. Therefore report confidence sequences or sequentially adjusted intervals where appropriate, and avoid interpreting the stopping estimate as an unbiased estimate of long-run lift.
Guardrails and novelty effects
Conversion lift can coexist with worse retention, latency, complaints, or revenue quality. Define guardrail metrics and follow-up horizons before launch. A short experiment may also capture novelty or learning effects rather than steady-state behavior. Sequential efficiency does not remove the need for a meaningful minimum exposure duration.
Implementation note
The R, JavaScript, and Python snippets in this article demonstrate a single-stream simple-hypothesis SPRT. They should not be copied as a two-arm A/B implementation without replacing the likelihood with one that models both randomized groups.
Embed interactive plots, widgets, and demos using <figure>, <iframe>, or <div class="interactive-embed"> containers. Ensure each embed includes descriptive captions for accessibility.
How to cite
Use the quick export buttons to save citations for reference managers or copy the formatted text directly.
Diogo Ribeiro (2023). Advanced Statistical Methods for Efficient A/B Testing. Faculty of Media Arts and Design, Technical University of Porto. https://diogoribeiro7.github.io/data-science/ab_testing/.


