Test Design & Avoiding Confounds Questions
Learn common experiment pitfalls: time-of-week biases (weekend vs. weekday users behave differently), seasonal effects (holiday periods skew conversion), learning effects (users adapt to new features over time), and network effects (one user's action influences another). Practice identifying these confounds in scenarios and designing tests to avoid them. Understand random assignment and why it matters.
MediumTechnical
101 practiced
When the primary metric is heavily skewed (e.g., purchase amounts with many zeros and a heavy right tail), what robust metrics and analysis strategies would you recommend to estimate treatment effect reliably and avoid misleading significance? Discuss median, trimmed means, log-transformations, bootstrap, and two-part models.
Sample Answer
When purchase amounts are highly skewed with many zeros, a single mean-based comparison can be misleading. Use a suite of robust metrics and complementary analyses:- Median: compares typical user spending; robust to outliers. Report median difference and a confidence interval via percentile bootstrap because asymptotic normality may not hold.- Trimmed/Winsorized means: remove or cap extreme tails (e.g., 5–10%) to get a “central” average that balances sensitivity and robustness. Good when you care about mean-like quantities but want less tail influence.- Log-transformations: apply log(x+ε) (ε small, e.g., 1¢) to stabilize variance; compare geometric means. Interpret back-transformed differences carefully—log changes approximate percent change.- Bootstrap: use nonparametric bootstrap (resample users, preserve zero mass) to estimate CIs and p-values for medians, trimmed means, or transformed statistics. Bootstrapping handles unknown sampling distributions and heavy tails.- Two-part (hurdle) models: explicitly model P(purchase>0) with logistic regression and conditional purchase amount (e.g., GLM with Gamma or log-normal) for positives. This separates treatment effects on incidence vs. intensity and yields interpretable decomposed lift.Practical strategy: pre-specify primary metric (e.g., two-part expected value or median + incidence) aligned with business goal, run both median and two-part analyses, use bootstrap CIs, and report multiple metrics (incidence, median positive, mean-positive) to avoid overclaiming significance driven by a few high spenders.
HardSystem Design
82 practiced
You want to test a change aimed at improving 30-day retention in a mobile app that shows strong weekly and seasonal retention patterns. Propose experiment duration, cohort and sample-size strategy, ramp plan, and detailed analyses (cohort survival curves, Cox models, and steady-state detection) to distinguish short-term engagement bumps from durable retention improvements.
Sample Answer
Requirements & constraints:- Goal: detect durable improvement in 30-day retention (not transient engagement spike).- Observed strong weekly and seasonal patterns → experiments must span multiple cycles.- Want statistical power to detect a practically meaningful lift (MDE) while controlling for covariates (acquisition source, device, geography).Experiment duration:- Minimum 8–12 weeks. Rationale: covers 8–12 weekly cycles and at least one seasonal period (e.g., month boundary, holiday effects). This helps separate short-term bumps (days 0–7) from sustained effects through day 30+ and lets retention curves converge.Cohort & randomization strategy:- Unit: new users (or reactivated users) at first exposure. Create weekly cohorts (users bucketed by exposure week) so calendar effects are visible.- Blocked randomization within cohort by key strata: acquisition channel, region, platform, first-session channel. This reduces imbalance from seasonality and source differences.- Holdout groups: keep a contemporaneous control and an untouched long-term holdout (e.g., 10% of eligible users not exposed to experiment for rollback/seasonal baseline).Sample size & power:- Define primary metric: survival at day 30 or AUC of survival curve 0–30 days. Choose MDE (e.g., relative +5% absolute increase in D30 retention).- Use baseline D30 retention p0 and desired power (80–90%), alpha (0.05) to compute N per arm via two-proportion test adjusted for clustering (if any). For survival analysis prefer sample-size for log-rank test: - Required events ≈ ( (Z1-α/2 + Z1-β)^2 ) / ( (log(HR))^2 ), convert to users by expected event rate over 30 days.- Example: baseline D30 = 20%, target HR≈1.05 => many users; if infeasible, raise MDE or run longer.- Use sequential monitoring adjustments (alpha spending) if interim looks planned.Ramp plan:- Phased rollout to reduce risk and collect early signals: 1. Canary (1–2% of traffic) for 3–7 days — sanity & instrumentation. 2. Small ramp (10%) for 1 week — safety and initial effect. 3. Medium ramp (50%) for 2 weeks — build sample. 4. Full ramp (100% of test-eligible) until experiment end.- Always keep the designated holdout untouched.- Record exact timestamps and cohort week assignment; avoid moving users between arms.Analytical plan — distinguishing bump vs durable change1) Descriptive & QA- Confirm randomization balance across strata.- Check exposure timing, event logging, censoring patterns.- Visualize daily new users and baseline weekly cycles.2) Cohort survival curves (Kaplan-Meier)- Compute KM survival curves for each arm per weekly cohort and pooled.- Plot survival S(t) to 30+ days with 95% CIs. Also plot difference S_treatment(t) - S_control(t) over time.- Interpretation: - Immediate early divergence (days 0–7) then convergence → short-term bump. - Divergence that persists or widens through day 30 → durable effect.- Perform stratified KM by acquisition channel to check heterogeneity.- Statistical test: log-rank test (global). But because of nonproportional hazards, supplement with time-windowed comparisons (e.g., D7, D14, D30).3) Cox proportional hazards models (and time-varying effects)- Fit Cox model with treatment indicator + covariates (channel, platform, region, cohort week) to estimate hazard ratio (HR) for churn.- Check proportional hazards (PH) assumption with Schoenfeld residuals and plot scaled residuals.- If PH violated (likely if early bump only), fit time-varying coefficients: - Add interaction terms treatment * g(t) where g(t) are piecewise step functions (0–7, 8–30, 31+), or use splines on time. - Alternative: stratified Cox or Aalen’s additive model for nonproportional effects.- Interpret: - HR <1 that is sustained across windows → durable retention improvement. - HR <1 only in early window then ~1 later → transient bump.4) Steady-state / convergence detection- For each arm compute cumulative retention rate at successive days and cumulative lift.- Use change-point detection (CUSUM or Bayesian online change-point) on difference series to detect when incremental daily retention stabilizes.- Compute rolling-window slope of survival difference; declare steady-state when slope ≈ 0 within tolerance for pre-specified consecutive days (e.g., 7 days).- Also model survival AUC over 0–30 days and evaluate its change across additional weeks; plateau indicates steady-state.5) Robustness & heterogeneity- Intention-to-treat (ITT) as primary; per-protocol as sensitivity.- Adjust for seasonality via calendar-week fixed effects or include week dummy variables in Cox.- Bootstrap confidence intervals for survival differences and AUC differences; use cluster-robust SE if correlated.- Correct for multiple comparisons when inspecting many cohorts/windows.6) Decision rules- Define thresholds ahead: e.g., statistically significant improvement in D30 (two-sided p<0.05) + sustained survival advantage in last 7 days of observation + HR averaged over days 8–30 <1 by X%.- If early spike but no D30 gain and time-varying HR returns to 1 → reject as transient.Tools & implementation notes- Libraries: Python lifelines (KM, Cox), statsmodels, scipy; R survival/survminer for richer plotting.- Instrument events precisely (install, session, retention ping), track censoring and lost-to-follow-up.- Automate dashboards showing cohort KM plots, time-varying HR, steady-state detector output.Summary: run experiment across multiple weekly cohorts for 8–12 weeks with blocked randomization and phased ramp. Use KM curves + log-rank for visual/global tests; use Cox with time-varying terms to quantify early vs sustained effects and test PH assumptions; implement change-point/steady-state detection on survival differences. Predefine power, MDE, decision criteria, and use stratification and calendar controls to separate seasonality and short-term engagement bumps from durable retention improvements.
HardTechnical
90 practiced
Implement a block-wise permutation test in Python for an experiment randomized within daily blocks. Input is a pandas DataFrame with columns ['user_id', 'day', 'variant', 'metric']. Permute variants only within each 'day' block N times, compute the distribution of mean(metric_treatment) - mean(metric_control) under the null, and return a two-sided p-value. Outline complexity and memory considerations.
Sample Answer
Approach (brief)- Compute observed ATE = mean(metric | variant=treatment) - mean(metric | variant=control).- To simulate the null of no treatment effect while respecting daily blocking, for each day randomly reassign which users are “treatment” vs “control” while keeping the same counts per day. Repeat N times and collect the permuted ATEs. Compute two-sided p-value as fraction of permuted |ATE| >= |observed ATE|.Implementation (efficient, minimal memory):- For each day, extract metrics array and number of treatment slots.- For each permutation, for each day sample treatment indices without replacement (numpy.choice) and accumulate treatment sums; compute per-perm ATE using global totals.Key points and reasoning- Sampling treatment indices per day preserves block sizes (constrained randomization) and avoids physically shuffling strings or DataFrame rows repeatedly.- We accumulate sums so we never build large temporary DataFrames; only store per-day metric arrays and permuted ATEs.- Add +1 in numerator and denominator (permutation test +1 rule) for a valid p-value even when observed is extreme.Complexity and memory- Time: O(N * M) where N = n_perms and M = total number of rows (each perm visits each row once on average via sampling). If days are large, sampling cost per day is O(k) for k = day size.- Memory: O(M) to store all metrics once (split by day) plus O(N) for permuted_ates. This scales to large data if you stream per-day arrays from disk or implement batching across permutations.- Possible optimizations: vectorized sampling using generating combinatorial indices, or precomputing cumulative sums and using reservoir-style approaches for extremely large datasets; parallelize permutations across cores.
python
import numpy as np
import pandas as pd
def block_permutation_test(df, day_col='day', variant_col='variant',
metric_col='metric', treat_label='treatment',
control_label='control', n_perms=1000, seed=None):
"""
Block-wise permutation test: permute variant within each day block.
Returns: observed_ate, p_value, permuted_ates (numpy array length n_perms)
"""
rng = np.random.default_rng(seed)
# Basic validation
if {day_col, variant_col, metric_col} - set(df.columns):
raise ValueError("Missing required columns")
df = df[[day_col, variant_col, metric_col]].dropna()
# Observed ATE
mask_t = df[variant_col] == treat_label
obs_mean_t = df.loc[mask_t, metric_col].mean()
obs_mean_c = df.loc[~mask_t, metric_col].mean()
observed_ate = obs_mean_t - obs_mean_c
# Precompute per-day arrays: metrics, n_treat_in_day
groups = df.groupby(day_col)
day_info = []
total_n_treat = mask_t.sum()
total_n = len(df)
total_n_control = total_n - total_n_treat
if total_n_treat == 0 or total_n_control == 0:
raise ValueError("Both treatment and control must be present")
for _, g in groups:
metrics = g[metric_col].to_numpy()
n_treat = (g[variant_col] == treat_label).sum()
# store metrics and number of treatment slots for that day
day_info.append((metrics, int(n_treat)))
perm_ates = np.empty(n_perms, dtype=float)
# For each permutation, assign treatment indices per day and compute ATE
for i in range(n_perms):
sum_treat = 0.0
for metrics, n_treat in day_info:
if n_treat == 0:
continue
# sample indices for treatment slots without replacement
idx = rng.choice(len(metrics), size=n_treat, replace=False)
sum_treat += metrics[idx].sum()
mean_treat = sum_treat / total_n_treat
# total sum of metrics:
# compute once per perm? we can precompute global sum outside loop to save time
# but here we compute control mean via global sum - sum_treat
# Precompute global_sum before loop:
# (moved below)
perm_ates[i] = mean_treat
# improve by computing global sum once:
global_sum = df[metric_col].sum()
# recalc using better loop (to ensure correctness with global_sum)
for i in range(n_perms):
# recompute sums using RNG with same seed handling
# simpler: redo deterministic approach: regenerate per-perm treatment sums
sum_treat = 0.0
for metrics, n_treat in day_info:
if n_treat == 0:
continue
idx = rng.choice(len(metrics), size=n_treat, replace=False)
sum_treat += metrics[idx].sum()
mean_t = sum_treat / total_n_treat
mean_c = (global_sum - sum_treat) / total_n_control
perm_ates[i] = mean_t - mean_c
# two-sided p-value
abs_obs = abs(observed_ate)
p_value = (np.count_nonzero(np.abs(perm_ates) >= abs_obs) + 1) / (n_perms + 1)
return observed_ate, p_value, perm_atesMediumTechnical
161 practiced
You want to test a new 'share' button on a social platform where acceptance by one user can cause friends to adopt features (spillover). Design an experiment to measure both direct treatment effects and indirect spillover. Discuss randomization unit (user vs cluster), metrics to capture spillover, identification strategy, and handling of incomplete network visibility.
Sample Answer
Approach summary: use a randomized experiment that explicitly accounts for network spillovers — either cluster (graph-based) randomization or a two-stage/encouragement design — together with exposure mapping and estimators that separate direct and indirect effects.Randomization unit- Cluster randomization: partition the social graph into non-overlapping clusters (e.g., via community detection or graph clustering) and randomize clusters to treatment or control. Pros: clean isolation of spillovers within cluster; cons: lower power, cluster-defining choices matter.- Two-stage / ego-randomization (recommended when clusters are noisy): randomly assign a sample of “seed” users to receive the share button (first stage). Then for other users, randomly assign them to be eligible or not for direct treatment in a second stage. This enables estimation of direct effects and spillovers from treated seeds (encouragement design).Metrics to capture spillover- Direct treatment metric: probability a treated user clicks/uses the share button (adoption rate), engagement time.- Indirect metrics (for untreated but exposed users): friend-adoption rate (fraction of friends who adopt), adoption conditional on k friends treated, time-to-adopt after friend adoption.- Network-level metrics: cascade size, average cascade depth, secondary adoption rate (R_t), and aggregate engagement lift.- Heterogeneous metrics: stratify by degree, activity decile, or community.Identification strategy- Define exposure mappings (e.g., Ei = number/proportion of i’s friends treated). Estimate potential outcomes under different exposure levels.- Use randomized assignment as instrument: for two-stage design, use Intention-to-Treat (ITT) for direct effects and Instrumental Variables (IV) to estimate Local Average Treatment Effects (LATE) of exposure.- Estimate spillover by comparing untreated users with different exposure levels while conditioning on assignment probabilities; use Horvitz-Thompson or inverse-probability weighting to correct for unequal exposure probabilities.- Use permutation/randomization inference to get valid p-values that respect network dependence.Handling incomplete network visibility- Build analysis around observed exposure; report that estimates are conditional on observed edges.- Use sensitivity analyses and bounds: e.g., worst/best-case bounds for unobserved ties, and bias-correction methods assuming missing-at-random or degree distributions.- Leverage ego-network sampling: collect additional friend lists for a subsample to estimate how much missing ties would alter exposure mapping, then re-weight.- Use robustness checks: estimate effects restricting to users with high observed-degree coverage, and compare to the full sample.Practical notes- Pre-register exposure definitions and estimators.- Power: simulate using observed graph to compute detectable effect sizes (clustered or exposure-based variance).- Monitor interference windows (time lags) and possible contamination (cross-cluster edges) and report external validity limitations.
EasyTechnical
78 practiced
You ran an A/A test for two identical UI variants and see a 2.5% absolute difference in conversion between groups with p < 0.05. List possible causes (both statistical and engineering), describe diagnostics you'd run to root-cause the issue, and propose short-term and long-term remediations.
Sample Answer
Possible causes- Statistical: - Type I error from chance (alpha 0.05 → ~5% false positives) - Multiple comparisons / peeking / sequential testing inflating false positives - Sample bias: unequal pre-period baselines or segmentation imbalance - Temporal effects: seasonality, time-of-day, rollout windows - Non-independence (clustered users, repeated measures)- Engineering/instrumentation: - Faulty randomization (hash bug, cookie/cookie-ttl, sticky sessions) - Event loss/duplication (tracking pixels, queue drops, retried events) - Variant-specific caching/CDN or A/B routing differences - Experiment config mismatch (feature flag targeting wrong audience) - Bot/automation traffic uneven across groupsDiagnostics (what I'd run and why)- Sanity checks: - Compare pre-experiment baselines (conversion, traffic source, geography, user agent) across groups. - Verify randomization: histogram of user IDs → group assignment frequencies; check hash function and seed.- Instrumentation audit: - Reconcile client-side vs server-side events; compare raw logs to analytics events to detect loss/duplication. - Inspect network/cdn logs, feature-flag configs, load balancer sticky sessions.- Statistical tests: - Permutation test / bootstrap for conversion difference (non-parametric reassurance). - Sequential analysis: examine p-value over time for peeking patterns. - Check multiple testing family-wise error if many metrics were inspected.- Traffic quality: - Segment by bot/ua, new vs returning users, mobile/desktop, referrer; see if difference concentrates in subgroups.- Reproduce: - Replay events for a sample of user IDs to validate deterministic assignment. - Run A/A on a held-back small sample or simulate traffic with known properties.Short-term remediations- Pause new rollouts of decisions based on this test.- If instrumentation bug found: fix and re-run the A/A (do not "patch" past data).- If randomization bug: stop experiment, patch assignment logic, and re-randomize or start a fresh experiment with corrected assignment.- Use conservative inference: adjust alpha for multiple testing; report uncertainty and avoid business actions.Long-term remediations- Harden experiment platform: - Strong deterministic hashing, stable seeds, idempotent assignment, and versioned configs. - End-to-end monitoring: experiment health dashboard (assignment balance, event loss rates, p-value drift). - Automated alerts for imbalances, sudden metric shifts, or tracking gaps.- Instrumentation best practices: - Server-side event logging as ground truth; reconciliations between client/server. - Unit/integration tests for experiment hooks; synthetic traffic tests.- Statistical safeguards: - Pre-registration of metrics/analysis, use sequential-corrected methods (alpha-spending), and account for multiple comparisons. - Routine A/A validations and periodic calibration of false-positive rates.Outcome communication- Report findings transparently: what was detected, diagnostics run, confidence in root cause, recommended next steps (fix + re-run).- Provide timeline for remediation and re-evaluation plan.
Unlock Full Question Bank
Get access to hundreds of Test Design & Avoiding Confounds interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.