CUPED Variance Reduction
Background
CUPED (Controlled-experiment Using Pre-Experiment Data, Microsoft, 2013) is a one-line trick that buys 30-50% variance reduction in most online A/B tests. The idea: subtract from every user's experiment-period metric a scaled version of their pre-experiment baseline. Per-user variance that's common to both periods cancels; what remains is the actual treatment effect.
Problem statement
Implement cuped_adjust(y, x, x_bar=None) returning the CUPED-adjusted outcome:
where is the experiment-period metric and is the same metric measured for the same user before the experiment. The pre-experiment mean is taken across the supplied unless the caller passes a fixed x_bar (used when the global pre-experiment mean is known from a separate source).
Input
y- array-like of floats, experiment-period outcomes (one per user).x- array-like of floats, pre-experiment covariate, same length asy.x_bar- optionalfloat; ifNone, usemean(x).
Output
np.ndarrayof shape(n,)with the adjusted outcomes. Same length and order asy.
Examples
Example 1 - strong correlation: variance drops sharply
Input: y = pre + experiment-period noise (cor with x ~ 0.9)
Output: y_adj has variance ~= 0.19 * var(y) (1 - rho^2 = 1 - 0.81)
Example 2 - independent x and y: no variance change
Input: y and x uncorrelated samples
Output: y_adj has variance ~= var(y) (theta ~ 0)
Constraints
- Use the sample covariance and variance (Bessel-corrected, divisor ).
- If , return
yunchanged (theta is undefined; no adjustment possible). - Output is a numpy array; do not mutate
yin place.
Notes
- Why it works. Subtracting removes the user-baseline component of variance. The estimator is unbiased for the treatment effect: is determined pre-treatment so it can't carry the treatment signal.
- Variance reduction. With correlation between and , . For watch-time-style metrics where , that's 50% off.
- Pre-experiment mean. Passing a fixed
x_bar(the population pre-experiment mean) is the convention when sub-experiment slices are evaluated — it keeps the estimator unbiased across slices.
▶ Run executes the 3 visible sample tests below in your browser. Submit runs the full suite — including hidden tests — on the server for an official verdict.
- •Example: perfectly correlated input collapses to constant
- •Reference: var(x)=0 returns y unchanged
- •Sample: external x_bar=0