Evidence for ML engineers
Your first question: Will a model trained on Ground's rows work on real data, including on the rare class I care about?
Short answer, from one benchmark run: on 4 public classification tables a model trained only on Ground's rows scored within 0.007 AUC of the same model trained on the real rows, tested on real rows neither had seen. On 2 regression tables it lost 0.058–0.060 R², a larger gap you should check on your own target. With the rare-cases option on, a rare class shows up in every preview and exact counts per combination hold to the row; adding rows where your model fails did not help.
Train on synthetic, test on real
Classification: AUC on the real holdout
Each model is a random forest tested on the same 20% of real rows. Trained on real = the ceiling. Higher is better; the axis starts at 0.7.
| Dataset | Trained on real | Trained on Ground | Trained on Ground (DP ε=3) | Trained on MOSTLY AI |
|---|---|---|---|---|
| Adult | 0.904 | 0.897 | 0.874 | 0.897 |
| Bank | 0.919 | 0.913 | 0.869 | 0.896 |
| Credit | 0.833 | 0.827 | 0.755 | 0.823 |
| Telco | 0.833 | 0.829 | 0.804 | 0.821 |
Regression: R² on the real holdout
Same setup for the two numeric targets (house value, insurance charges). Higher is better.
| Dataset | Trained on real | Trained on Ground | Trained on Ground (DP ε=3) | Trained on MOSTLY AI |
|---|---|---|---|---|
| Housing | 0.688 | 0.628 | 0.533 | 0.607 |
| Insurance | 0.871 | 0.813 | 0.643 | 0.019 |
| Dataset | Trained on real | Ground | Ground (DP ε=3) | Ground (DP ε=3, MST) | MOSTLY AI (TabularARGN, local) | SDV CTGAN (50 epochs) | SDV GaussianCopula |
|---|---|---|---|---|---|---|---|
| Adult (AUC) | 0.904 | 0.897 | 0.874 | 0.884 | 0.897 | 0.865 | 0.867 |
| Bank (AUC) | 0.919 | 0.913 | 0.869 | 0.880 | 0.896 | 0.722 | 0.882 |
| Credit (AUC) | 0.833 | 0.827 | 0.755 | 0.776 | 0.823 | 0.456 | 0.801 |
| Telco (AUC) | 0.833 | 0.829 | 0.804 | 0.810 | 0.821 | 0.610 | 0.810 |
| Housing (R²) | 0.688 | 0.628 | 0.533 | 0.397 | 0.607 | 0.058 | 0.436 |
| Insurance (R²) | 0.871 | 0.813 | 0.643 | 0.726 | 0.019 | 0.088 | 0.507 |
- How it was measured
- Each public table is shuffled with seed 7 and split 80/20. Every synthesizer trains on the same 80% (at most 30,000 rows); a random forest is trained on its synthetic rows and tested on the real 20%, next to one trained on the real 80%. Details on the benchmark overview.
- Uncertainty
- One run with fixed seeds, no confidence intervals. Differences of a point or two in Overall, or a few thousandths of AUC, are within noise.
- Scored by
- Ground's own report (self-scored). Independent scoring is pending first independent run.
- Limits
- SDV CTGAN ran 50 epochs (default 300) and MOSTLY AI had a 5-minute training cap, so their numbers understate what tuned runs could do.
- Raw output
- benchmark-results.json · evidence.json
- Source
apps/web/lib/benchmark-results.json; docs/benchmarks.md
Rare classes you can see and count
A 25-row preview of card transactions (is_fraud (2.9%)) has no fraud row in 47% of seeds today. The rare-cases option swaps rows so the rare class is always in the preview, and the exported file keeps the real rate once it passes about 1,000 rows. It is behind options that are off by default, with no UI yet.
Previews that contain the rare class
Share of 25-row previews over 200 seeds with at least one, and at least three, rare rows. Higher is better.
| Preview | Option off | Rare cases on |
|---|---|---|
| is_fraud (2.9%): at least 1 rare row | 53% | 100% |
| is_fraud (2.9%): at least 3 rare rows | 3% | 100% |
| Priority = urgent (6.9%): at least 1 rare row | 80.5% | 100% |
| Priority = urgent (6.9%): at least 3 rare rows | 26% | 100% |
| Dataset | What was asked | Largest count error |
|---|---|---|
| support-tickets | Enterprise ∧ urgent = 120 of 10,000 | 0 rows |
| card-transactions | online ∧ fraud = 500 of 10,000 | 0 rows |
| loans (upload) | West ∧ defaulted = 150 of 3,000 | 0 rows |
| loans (upload) | 30% defaulted within West | 0 rows |
| How the rows were made | Mean amount |
|---|---|
| true conditional (400k rows) | $1,336 |
| same-size true sample | $1,320 |
| attempt search (prototype) | $1,364 |
| forced values | $873 |
Searching for rows that meet a combination keeps what the other columns do inside it, where forcing the values breaks it (table above). What this doesn't show: whether a model trained on rebalanced rare-class rows does better on real rare cases. That measurement is pending first independent run.
- How it was measured
- 200 preview seeds and 20 count seeds per dataset, on the card-transactions and support-tickets templates and the loan sample fitted as an upload. TVD against two unconstrained runs with different seeds is the noise floor.
- Uncertainty
- Shares over 200 seeds; the baseline matches the closed form (1 − 0.971²⁵ = 0.52). Count errors are the largest over 20 seeds.
- Scored by
- Ground's assessment harness (self-scored).
- Raw output
- rare-cases.json
- Source
docs/assessments/rare-cases.md
Measured no-go: generating rows where your model fails
Failure-sliced minus plain synthetic rows: slice AUC
Paired difference, mean ± sd over 5 seeds. Right of the line means failure-sliced rows helped; every whisker crosses it.
| Table, real rows | Difference in slice AUC |
|---|---|
| Adult, 1,000 real rows | +0.002 ± 0.009 |
| Adult, 5,000 real rows | −0.002 ± 0.004 |
| Bank, 1,000 real rows | −0.002 ± 0.009 |
| Bank, 5,000 real rows | +0.006 ± 0.008 |
| Credit, 1,000 real rows | −0.003 ± 0.013 |
| Credit, 3,557 real rows | +0.002 ± 0.017 |
| Telco, 1,000 real rows | 0.000 ± 0.016 |
| Telco, 5,000 real rows | +0.005 ± 0.013 |
| Table, real rows | vs plain synthetic | vs repeated real slice rows |
|---|---|---|
| Housing, 1,000 | +3,057 ± 1,749 | +4,802 ± 1,876 |
| Housing, 5,000 | +766 ± 1,564 | +3,114 ± 978 |
| Insurance, 1,000 | +1,066 ± 737 | +1,514 ± 1,171 |
| Insurance, 1,071 | +297 ± 431 | +850 ± 442 |
- How it was measured
- Same six tables and split as the benchmark. Gradient-boosted trees (or a regression forest) trained on 1,000 or 5,000 real rows; five-fold out-of-fold errors find the worst slice (at least 50 rows); four arms add the same number of rows: none, plain synthetic, failure-sliced synthetic, or repeated real slice rows.
- Uncertainty
- sd of paired differences over 5 seeds. The test set is the same in every seed, so small test slices (insurance smokers: 56 rows) are less certain than the sd suggests.
- Scored by
- Ground's assessment harness (self-scored).
- Raw output
- failures-results.json · failures-results-boost3.json (tripled dose)
- Source
docs/assessments/failure-driven-generation.md
Check it on your own task: the notebook
Benchmarks on public tables are not your data. Most exports of an uploaded dataset (single-table files, not zip or related-table exports) come with a ready-to-run notebook: it trains a model on the synthetic rows and tests it on the real rows Ground held back when it learned your data, next to a model trained on the other real rows and one trained on both. It runs in Jupyter, VS Code or Google Colab with pandas and scikit-learn. Its result is the number that matters for your model; Ground doesn't publish it.
Next: what the same synthetic rows reveal about real people, or read synthetic data for machine learning.