Updated November 2026
Prebuilt analyses you can run on your own data. Find one the way you think about the problem: by the question you're asking, the shape of your data, or your industry. Below the list is one worked through end to end, with the file, the code and the numbers it printed.
See a worked example Try one on your file →
Commissioned builds live in the pipeline case studies.
Compare two groups? Find what drives an outcome? Spot a trend? The question decides which statistics fit, so it is the first thing to get right.
Browse by question →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.
Browse by data shape →Churn in SaaS and readmission in healthcare are both questions of how long until something happens, so the same survival methods often apply. The vocabulary and the traps differ.
Browse by industry →They answer different questions, and they deliberately cross. Cohort Retention
sits on the Trends over time shelf, its data is a panel, and it matters in both
SaaS and Retail. One analysis, three true answers. A single category would force you to
pick one and lose the other two, which is why browsing by method name alone is hard.
Prebuilt analyses link to a sample report run on a published sample file; commissioned ones link to the report the build pipeline delivered. The difference matters when you're deciding what to use.
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.
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.