By MCP Analytics Team | Published , updated
One row per customer is a different problem from one row per customer per month. The shape of the file narrows which methods can apply to it.
The analyses filed under this data shape. Each card opens the analysis page, where you can run it on a file. Cards marked Coming soon are still being built.
Can I stop this experiment early? Sequential testing with approximately always-valid inference (asymptotic), so peeking does not inflate false…
Did any variant beat the control, and by how much?
Do your groups differ once a baseline is adjusted for?
Posterior probability of winning, expected loss; no peeking problem.
Are these two things practically the SAME within a margin?
Which results survive correction for multiple testing?
Did the treatment work, or were the treated already different?
Did the same subjects change across three or more conditions?
What range does the true value plausibly lie in? Bayesian posterior estimates and credible intervals for means, rates, differences.
The data. standard_ab_test_v2.csv, the published sample file for A/B test: 4,795 rows; columns User ID, Assigned Group, Converted, Order Value, Signup Date, Device. Sample data, not a customer's.
The calculation. Python, standard library only. This exact code ran against the file when this page was built, and printed the output below it.
import csv
rows = list(csv.DictReader(open("standard_ab_test_v2.csv")))
n, won = {}, {}
for r in rows:
g, c = r["Assigned Group"], r["Converted"]
if not g or c not in ("Yes", "No"):
continue # no group or no outcome recorded
n[g] = n.get(g, 0) + 1
won[g] = won.get(g, 0) + (c == "Yes")
rate = {g: won[g] / n[g] for g in n}
for g in sorted(n):
print(g, n[g], "users,", won[g], "converted,", f"{rate[g]:.2%}")
best = max((g for g in n if g != "Control"), key=rate.get)
d = rate[best] - rate["Control"]
se = (rate[best] * (1 - rate[best]) / n[best]
+ rate["Control"] * (1 - rate["Control"]) / n["Control"]) ** 0.5
print(best, "minus Control:", f"{100 * d:+.2f}", "points, 95% interval",
f"{100 * (d - 1.96 * se):+.2f} to {100 * (d + 1.96 * se):+.2f}")
print("skipped", len(rows) - sum(n.values()), "incomplete rows")
Control 1601 users, 78 converted, 4.87%
Variant B 1584 users, 116 converted, 7.32%
Variant C 1595 users, 85 converted, 5.33%
Variant B minus Control: +2.45 points, 95% interval +0.79 to +4.11
skipped 15 incomplete rows
What it says. Variant B converted 7.32% of users against 4.87% for Control, a difference of 2.45 percentage points. The 95% interval (0.79 to 4.11) stays above zero, so in this sample the lift is unlikely to be noise alone.
What it does not say. 15 rows had no group or no outcome and were skipped, not guessed. This is the simple two-proportion interval for the better of two variants, picked after looking, so it is a little optimistic; the library analysis adjusts every comparison with the Holm method and also checks that traffic was split as planned.
Run A/B test on this file or your own, or open its stored sample report.
Further reading on the method in the worked example. Each reference was looked up and its authors, title, year and venue confirmed between 27 October 2026 and 30 October 2026.
The stored sample report for Sequential A/B Test (Peek With an Approximate Guarantee). Each analysis has its own report layout; open its page to see what it returns.
Tell us what went wrong, in your own words. We capture the page you're on automatically, so no need to describe where you are.