Real-World Evidence on Synthetic Data

Can data generated by Aindo replace real patient records for a causal-inference study?

This page compares a full observational causal-inference workflow (the kind used for real-world-evidence (RWE) analyses) run on real patient data against the same workflow run on Aindo-generated synthetic data. We want to test not only that the Aindo-generated synthetic data preserves the statistical properties but also the underlying causal mechanisms.

The example: a published NHANES cohort examining statin use and all-cause mortality. Confounding by indication is present here: clinicians preferentially prescribe statins to older, higher-risk patients, to the point that a naive, unadjusted comparison shows the opposite of the effect reported in the literature. This makes it a useful test case: it requires the analysis to correctly identify and adjust for confounding, not just reproduce a simple average.

The analysis comprises four steps: a naive comparison and three causal-adjustment methods (G-computation, IPTW, TMLE). For each, we run the identical analysis on the real data and on the synthetic data generated by Aindo, and report both results side by side.

Data. NHANES 1999-2018, ten survey cycles, linked to the NCHS public-use mortality file (follow-up through Dec 31, 2019).

The question

Does statin use reduce all-cause mortality?

Statins are among the most widely prescribed drugs in the world, and randomized trials support a mortality benefit for many patient groups. But most real-world statin use is observational: clinicians decide who gets prescribed a statin based on perceived cardiovascular risk, not a coin flip. That is exactly the setup where confounding by indication can distort a naive comparison, in either direction.

Study variables

Treatmentstatinreported taking a statin in the past month (yes/no)
Outcomedeathassumed deceased per the NCHS mortality linkage (through Dec 31, 2019)
Confoundersdemographics + clinical measuresage, sex, race, poverty-income ratio, BMI, blood pressure, diabetes, smoking, total cholesterol

Cohorts

  • Real (NHANES analytic): 54,091 patients, 12 variables
  • Synthetic (Aindo-generated): 54,091 patients, 12 variables
  • NHANES 1999-2018, ten survey cycles, linked to the NCHS public-use mortality file (follow-up through Dec 31, 2019).

The data

How is the Aindo synthetic data generated?

Aindo generates synthetic patient records by learning the statistical and causal structure of a real, de-identified cohort, then sampling an entirely new synthetic cohort from what it learned: patients that never existed, with no one-to-one link back to a real person. This page loads the real NHANES analytic dataset side by side with a synthetic cohort Aindo generated from it.

1. Learn

A generative AI model is trained directly on the real, de-identified cohort. Because it learns the whole dataset jointly, not one column at a time, it captures not just each variable's own distribution, but how variables relate to one another (e.g. that statin use, age, blood pressure, and cholesterol move together). That joint structure is exactly the confounding structure a causal analysis like this one depends on.

2. Generate

Once training is done, the real data is set aside, and the model samples a brand-new synthetic cohort from what it learned: synthetic patients, not modified or resampled real ones, so no synthetic record traces back to a specific real person. This is Aindo's Synthesis mode, and it's what makes the output "void of personal information" while remaining statistically realistic, supporting GDPR-, EHDS-, and AI-Act-aligned data sharing.

3. Validate

Before a synthetic dataset ships, Aindo's platform reports a similarity score and a privacy score for the generation run, backed by univariate and bivariate analysis.

In code, the shape of it looks roughly like this (illustrative, not the actual Aindo API):

schema = {
    "statin": "categorical",
    "age": "numeric",
    "sex": "categorical",
    "total_cholesterol": "numeric",
    # ... one entry per column, with its real data type
}

model = AindoSyntheticDataModel(schema)
# Learn
model.fit(real_cohort)
# Generate
synthetic_cohort = model.generate(n_samples=<number of samples requested>)

Fidelity checks

Does the synthetic data look like the real data?

We perform three checks:

  1. Boxplot comparison for the continuous confounders, do individual distributions match?
  2. Prevalence comparison for the binary variables (statin, death, sex, diabetes, smoker), same question, for variables a boxplot doesn't apply to.
  3. Pairwise correlation agreement across every variable, including the categorical ones (race and the binary variables above). Do variables relate to each other the same way in both datasets? This is the one that actually matters for a causal analysis: two datasets can have identical marginals while differing completely in their confounding structure.

Continuous confounders: boxplot comparison

Similarly-shaped boxes (median, IQR, and whiskers) mean the real and synthetic distributions agree.

Age

16.654.592.5Real: median 49.00, IQR [34.00, 64.50]RealSynthetic: median 48.00, IQR [33.00, 64.00]Synthetic

Poverty-income ratio

-0.22.55.3Real: median 2.16, IQR [1.15, 4.12]RealSynthetic: median 2.00, IQR [1.11, 3.98]Synthetic

BMI

9.73662.3Real: median 27.87, IQR [24.25, 32.30]RealSynthetic: median 27.95, IQR [24.20, 32.40]Synthetic

Systolic BP

49.7163276.3Real: median 122.00, IQR [112.00, 136.00]RealSynthetic: median 122.00, IQR [112.00, 136.00]Synthetic

Diastolic BP

13.684154.4Real: median 72.00, IQR [64.00, 78.00]RealSynthetic: median 70.00, IQR [64.00, 78.00]Synthetic

Total cholesterol

11.6214416.4Real: median 193.00, IQR [167.00, 221.00]RealSynthetic: median 190.00, IQR [165.00, 218.00]Synthetic
Interpretation. Boxplot comparison. Every continuous confounder's real and synthetic boxes (median, IQR, and whiskers) line up closely, meaning the synthetic data's marginal distributions match the real data's.

Binary variables: prevalence

A boxplot doesn't apply to a two-valued variable: comparing prevalence is the equivalent check.

Interpretation. Binary prevalence. Rates agree closely between real and synthetic: statin 16.2% vs 16.6%, diabetes 12.2% vs 11.8%, smoker 45.3% vs 43.5%, sex (male) 48.0% vs 46.8%. death shows the largest gap, 15.8% vs 13.4%.

Pairwise correlation agreement

Every pairwise correlation among treatment, outcome, and confounders (categoricals one-hot encoded), real vs. synthetic, 120 pairs in total.

Agreement

Mean absolute difference
0.0105
Worst-pair difference
0.0619
Variable pairs compared
120
Interpretation. Pairwise correlations. Across all 120 variable pairs (including the categorical ones, one-hot encoded), the mean absolute difference between real and synthetic correlations is ≈0.0105, and the single worst pair differs by only ≈0.0619. Each point is a correlation between two variables: the real-data correlation on the x-axis, the synthetic-data correlation on the y-axis.

Step 1

The naive comparison

Now we proceed with the main causal question posed in the beginning: does statin use reduce all-cause mortality?

An unadjusted comparison of mortality rates between statin users and non-users.

crude difference = Pr(death | statin) − Pr(death | no statin)

Run on both datasets to compare the two directly.

Crude odds ratio

SourceOdds ratio95% CI
Real2.428[2.300, 2.563]
Synthetic2.597[2.455, 2.748]

Crude mortality rate difference

Crude risk differenceReal Crude risk difference: 0.1398 [0.1300, 0.1497]Synthetic Crude risk difference: 0.1342 [0.1248, 0.1435]0.100.120.130.150.16Risk difference
RealSynthetic
Interpretation. Both datasets show a higher crude mortality rate among statin users, with odds ratios above 1 (2.43 [2.30 2.56] on the real dataset, 2.60 [2.462.75] on the synthetic): an unadjusted analysis would conclude statins increase mortality. This is inconsistent with the randomized-trial literature and is a signal of confounding, addressed in the next sections. Both real and synthetic data reproduce this pattern; the crude mortality rate difference estimates are also well aligned (0.1398 and 0.1342).

Why the naive estimate is wrong

Confounding by indication

Statins are not prescribed at random. Clinicians prescribe them to patients judged to be at higher cardiovascular risk. If statin users are systematically older and sicker, they have higher baseline mortality risk independent of the drug. The plot below shows the standardized mean difference (SMD) between statin users and non-users for each confounder, in the real data.

ageReal age: 1.3219Synthetic age: 1.3998diabetes_NoReal diabetes_No: -0.7484Synthetic diabetes_No: -0.8719diabetes_YesReal diabetes_Yes: 0.7206Synthetic diabetes_Yes: 0.8456total_cholesterolReal total_cholesterol: -0.5375Synthetic total_cholesterol: -0.5078systolic_bpReal systolic_bp: 0.4407Synthetic systolic_bp: 0.5198bmiReal bmi: 0.2510Synthetic bmi: 0.2151race_Non-Hispanic WhiteReal race_Non-Hispanic White: 0.2077Synthetic race_Non-Hispanic White: 0.2030race_Mexican AmericanReal race_Mexican American: -0.2000Synthetic race_Mexican American: -0.2026diastolic_bpReal diastolic_bp: -0.1878Synthetic diastolic_bp: -0.1190smoker_YesReal smoker_Yes: 0.1831Synthetic smoker_Yes: 0.1898smoker_NoReal smoker_No: -0.1813Synthetic smoker_No: -0.1890diabetes_BorderlineReal diabetes_Borderline: 0.1362Synthetic diabetes_Borderline: 0.1376sex_MaleReal sex_Male: 0.1192Synthetic sex_Male: 0.1223sex_FemaleReal sex_Female: -0.1192Synthetic sex_Female: -0.1223poverty_ratioReal poverty_ratio: 0.0891Synthetic poverty_ratio: 0.1143race_Other HispanicReal race_Other Hispanic: -0.0425Synthetic race_Other Hispanic: -0.0043race_Non-Hispanic BlackReal race_Non-Hispanic Black: -0.0344Synthetic race_Non-Hispanic Black: -0.0432race_OtherReal race_Other: -0.0226Synthetic race_Other: -0.0304-1.40-0.700.000.701.40Standardized mean difference
RealSynthetic

Dashed lines mark |SMD| = 0.1, the conventional imbalance threshold.

Interpretation. Several covariates exceed the |SMD| > 0.1 threshold, age most of all: statin users are, on average, roughly two decades older than non-users. Since age is a strong predictor of mortality, the naive comparison above largely reflects the age difference between groups rather than an effect of the drug. The synthetic data shows the same imbalance, consistent with its naive-comparison result above.

Step 2 · Outcome modeling

G-computation

The first technique used for dealing with these differences is G-computation. G-computation estimates an outcome model. This model learns the predictors of the outcome (death) and uses them to predict every participant's mortality risk in a counterfactual scenario where statin use is set to 1 and to 0 for everyone, then averages the difference. Here we use two different outcome models (a logistic regression and an XGBoost forest). Finally, we run the same analysis on both datasets and compare the results.

The confidence interval comes from a nonparametric bootstrap: we resample the dataset with replacement (same size as the original) 500 times, refit the outcome model from scratch on each resample, and take the 2.5th and 97.5th percentile of the resulting 500 estimates as the interval. The point estimate itself is not an average over these resamples. It is computed once, by fitting the model on the full original dataset; the bootstrap is only used to quantify the uncertainty around it.

Estimated treatment effect (risk difference)

Logistic regressionReal Logistic regression: -0.0365 [-0.0422, -0.0317]Synthetic Logistic regression: -0.0340 [-0.0386, -0.0274]XGBoostReal XGBoost: -0.0132 [-0.0169, -0.0070]Synthetic XGBoost: -0.0148 [-0.0187, -0.0060]-0.05-0.04-0.03-0.010.00ATE
RealSynthetic

Point estimates & 95% CI

ModelSourceATE95% CI
Logistic regressionReal-0.0365[-0.0422, -0.0317]
Logistic regressionSynthetic-0.0340[-0.0386, -0.0274]
XGBoostReal-0.0132[-0.0169, -0.0070]
XGBoostSynthetic-0.0148[-0.0187, -0.0060]
Interpretation. Once the outcome model adjusts for age and the other confounders, the estimated effect of statin use on mortality flips sign relative to the naive comparison, for both the real and synthetic data, model by model, with overlapping confidence intervals.

Step 3 · Propensity weighting

Inverse Probability of Treatment Weighting

Another approach is to model the treatment: the rationale is to learn the patterns that determine treatment assignment, then weight each individual by their probability of receiving the treatment they actually got. IPTW reweights each participant by the inverse probability of the statin use they actually received, so that in the reweighted pseudo-population, statin use no longer depends on the confounders. We then compare weighted mortality means between arms. As with G-computation, the confidence interval is a nonparametric bootstrap of 500 resamples of the dataset.

Estimated treatment effect (risk difference)

Logistic regressionReal Logistic regression: 0.0109 [0.0023, 0.0197]Synthetic Logistic regression: 0.0050 [-0.0027, 0.0151]XGBoostReal XGBoost: 0.0547 [0.0469, 0.0647]Synthetic XGBoost: 0.0497 [0.0437, 0.0632]-0.020.000.030.050.07ATE
RealSynthetic

Point estimates & 95% CI

ModelSourceATE95% CI
Logistic regressionReal0.0109[0.0023, 0.0197]
Logistic regressionSynthetic0.0050[-0.0027, 0.0151]
XGBoostReal0.0547[0.0469, 0.0647]
XGBoostSynthetic0.0497[0.0437, 0.0632]
Interpretation. The propensity models still do not point in the reversed, beneficial direction on both datasets. This is a known limitation of IPTW: the estimate depends entirely on the propensity model, and a more flexible model can produce a small number of extreme weights that distort the weighted comparison; TMLE is designed to be robust to this. The synthetic data reproduces this same instability rather than smoothing it out.

Does weighting actually balance the groups?

As a direct check (weighting should make statin users and non-users look statistically alike on the measured confounders), we redo the SMD check on the real and synthetic data, weighted by the (stabilized) IPTW weight.

Real: unweighted vs. weighted

ageUnweighted age: 1.3219Weighted (XGBoost) age: 0.4568diabetes_NoUnweighted diabetes_No: -0.7484Weighted (XGBoost) diabetes_No: -0.1395diabetes_YesUnweighted diabetes_Yes: 0.7206Weighted (XGBoost) diabetes_Yes: 0.1298total_cholesterolUnweighted total_cholesterol: -0.5375Weighted (XGBoost) total_cholesterol: 0.0608systolic_bpUnweighted systolic_bp: 0.4407Weighted (XGBoost) systolic_bp: 0.1670bmiUnweighted bmi: 0.2510Weighted (XGBoost) bmi: 0.1045race_Non-Hispanic WhiteUnweighted race_Non-Hispanic White: 0.2077Weighted (XGBoost) race_Non-Hispanic White: 0.1140race_Mexican AmericanUnweighted race_Mexican American: -0.2000Weighted (XGBoost) race_Mexican American: -0.0994diastolic_bpUnweighted diastolic_bp: -0.1878Weighted (XGBoost) diastolic_bp: 0.0549smoker_YesUnweighted smoker_Yes: 0.1831Weighted (XGBoost) smoker_Yes: 0.1052smoker_NoUnweighted smoker_No: -0.1813Weighted (XGBoost) smoker_No: -0.1028diabetes_BorderlineUnweighted diabetes_Borderline: 0.1362Weighted (XGBoost) diabetes_Borderline: 0.0375sex_MaleUnweighted sex_Male: 0.1192Weighted (XGBoost) sex_Male: 0.0786sex_FemaleUnweighted sex_Female: -0.1192Weighted (XGBoost) sex_Female: -0.0786poverty_ratioUnweighted poverty_ratio: 0.0891Weighted (XGBoost) poverty_ratio: 0.0927race_Other HispanicUnweighted race_Other Hispanic: -0.0425Weighted (XGBoost) race_Other Hispanic: -0.0374race_Non-Hispanic BlackUnweighted race_Non-Hispanic Black: -0.0344Weighted (XGBoost) race_Non-Hispanic Black: -0.0174race_OtherUnweighted race_Other: -0.0226Weighted (XGBoost) race_Other: -0.0143-1.40-0.700.000.701.40SMD
UnweightedWeighted (XGBoost)

Synthetic: unweighted vs. weighted

ageUnweighted age: 1.3998Weighted (XGBoost) age: 0.2471diabetes_NoUnweighted diabetes_No: -0.8719Weighted (XGBoost) diabetes_No: -0.0776diabetes_YesUnweighted diabetes_Yes: 0.8456Weighted (XGBoost) diabetes_Yes: 0.0780systolic_bpUnweighted systolic_bp: 0.5198Weighted (XGBoost) systolic_bp: 0.1274total_cholesterolUnweighted total_cholesterol: -0.5078Weighted (XGBoost) total_cholesterol: 0.0145bmiUnweighted bmi: 0.2151Weighted (XGBoost) bmi: 0.0617race_Non-Hispanic WhiteUnweighted race_Non-Hispanic White: 0.2030Weighted (XGBoost) race_Non-Hispanic White: 0.0189race_Mexican AmericanUnweighted race_Mexican American: -0.2026Weighted (XGBoost) race_Mexican American: 0.0381smoker_YesUnweighted smoker_Yes: 0.1898Weighted (XGBoost) smoker_Yes: 0.0677smoker_NoUnweighted smoker_No: -0.1890Weighted (XGBoost) smoker_No: -0.0663diabetes_BorderlineUnweighted diabetes_Borderline: 0.1376Weighted (XGBoost) diabetes_Borderline: 0.0084sex_FemaleUnweighted sex_Female: -0.1223Weighted (XGBoost) sex_Female: -0.0945sex_MaleUnweighted sex_Male: 0.1223Weighted (XGBoost) sex_Male: 0.0945diastolic_bpUnweighted diastolic_bp: -0.1190Weighted (XGBoost) diastolic_bp: 0.0613poverty_ratioUnweighted poverty_ratio: 0.1143Weighted (XGBoost) poverty_ratio: 0.0386race_Non-Hispanic BlackUnweighted race_Non-Hispanic Black: -0.0432Weighted (XGBoost) race_Non-Hispanic Black: -0.0130race_OtherUnweighted race_Other: -0.0304Weighted (XGBoost) race_Other: -0.0228race_Other HispanicUnweighted race_Other Hispanic: -0.0043Weighted (XGBoost) race_Other Hispanic: -0.0416-1.40-0.700.000.701.40SMD
UnweightedWeighted (XGBoost)
Interpretation. After weighting, the |SMD| of most confounders drops well below the unweighted values. Nonetheless, IPTW does not completely solve the problem, as mentioned above. For example, propensity weighting does not make the two groups' ages fully comparable, in either the synthetic or the original dataset.

Step 4 · Doubly robust

Targeted Maximum Likelihood Estimation

TMLE combines G-computation and IPTW into a single doubly-robust estimate. It starts from the same two ingredients used above, an outcome model that predicts mortality risk and a propensity model that predicts treatment assignment, and adds a "targeting" step: a small, one-parameter adjustment to the outcome model's predictions, fit using the propensity scores, that nudges the plain G-computation estimate just enough to solve for the ATE directly. The result is doubly robust, meaning it is consistent if either the outcome model or the propensity model is correctly specified, so the estimate does not have to bet entirely on one nuisance model the way G-computation and IPTW each do on their own.

Unlike G-computation and IPTW, TMLE's confidence interval is not a bootstrap. The targeting step comes with a closed-form standard error derived from its efficient influence curve, computed directly from the fitted models on the full dataset, no resampling needed.

Estimated treatment effect (risk difference)

Logistic regressionReal Logistic regression: -0.0271 [-0.0373, -0.0169]Synthetic Logistic regression: -0.0306 [-0.0393, -0.0220]XGBoostReal XGBoost: -0.0187 [-0.0255, -0.0120]Synthetic XGBoost: -0.0207 [-0.0269, -0.0146]-0.05-0.04-0.03-0.010.00ATE
RealSynthetic

Point estimates & 95% CI

ModelSourceATE95% CI
Logistic regressionReal-0.0271[-0.0373, -0.0169]
Logistic regressionSynthetic-0.0306[-0.0393, -0.0220]
XGBoostReal-0.0187[-0.0255, -0.0120]
XGBoostSynthetic-0.0207[-0.0269, -0.0146]
Interpretation. TMLE reverses the naive conclusion for both nuisance-model choices, including XGBoost (the one case where IPTW alone did not reverse) on both real and synthetic data. This reflects TMLE's doubly-robust property: its XGBoost-based estimate uses information from the outcome model to correct for the XGBoost propensity model's poor behavior seen in the IPTW section. The doubly-robust estimate and its confidence interval are the ones we would report, and real and synthetic results agree closely.

Putting it together

Naive vs. causally-adjusted estimates, real vs. synthetic

The naive/crude estimate points one direction; every causally-adjusted method points the other. The synthetic data's results match the real data's at every step.

Crude (naive)Real Crude (naive): 0.1398 [0.1300, 0.1497]Synthetic Crude (naive): 0.1342 [0.1248, 0.1435]G-computation (Logistic regression)Real G-computation (Logistic regression): -0.0365 [-0.0422, -0.0317]Synthetic G-computation (Logistic regression): -0.0340 [-0.0386, -0.0274]G-computation (XGBoost)Real G-computation (XGBoost): -0.0132 [-0.0169, -0.0070]Synthetic G-computation (XGBoost): -0.0148 [-0.0187, -0.0060]IPTW (Logistic regression)Real IPTW (Logistic regression): 0.0109 [0.0023, 0.0197]Synthetic IPTW (Logistic regression): 0.0050 [-0.0027, 0.0151]IPTW (XGBoost)Real IPTW (XGBoost): 0.0547 [0.0469, 0.0647]Synthetic IPTW (XGBoost): 0.0497 [0.0437, 0.0632]TMLE (Logistic regression)Real TMLE (Logistic regression): -0.0271 [-0.0373, -0.0169]Synthetic TMLE (Logistic regression): -0.0306 [-0.0393, -0.0220]TMLE (XGBoost)Real TMLE (XGBoost): -0.0187 [-0.0255, -0.0120]Synthetic TMLE (XGBoost): -0.0207 [-0.0269, -0.0146]-0.15-0.070.000.070.15Estimated treatment effect (risk difference)
RealSynthetic

A further use

Aindo's model as a predictor, not just a generator

Everything above used classical ML (logistic regression, XGBoost) as the outcome and propensity models. As a further demonstration, separate from the real-vs-synthetic comparison above, the same deep model architecture behind Aindo's synthetic data generation can also be trained as a plain predictive model: not to generate data, but to predict it.

Here we take a model trained by Aindo directly on the real cohort (no synthetic data involved in this section) and use it as the outcome model for a G-computation-style ATE and, paired with a logistic-regression propensity model, a TMLE estimate.

Outcome model AUC, predicting death (real data)

Outcome modelAUC
Logistic regression0.8751
XGBoost0.8890
Aindo model0.9100

ATE, XGBoost vs. Aindo model as the outcome model (real data)

MethodOutcome modelATE95% CI
G-computationXGBoost-0.0132[-0.0169, -0.0070]
G-computationAindo model-0.0118[-0.0120, -0.0116]
TMLEXGBoost-0.0187[-0.0255, -0.0120]
TMLEAindo model-0.0124[-0.0184, -0.0064]
Interpretation. Using Aindo's own model as the outcome model gives a G-computation-style ATE of -0.0118 [-0.0120, -0.0116] and a TMLE estimate of -0.0124 [-0.0184, -0.0064]. Both point in the same protective direction as every adjusted estimate above, and both confidence intervals overlap with the corresponding XGBoost-based estimates from earlier on this page; the G-computation CI here in fact sits entirely inside XGBoost's.

It also outperforms both classical outcome models on plain predictive performance: at discriminating who actually died, Aindo's model reaches an AUC of 0.91, ahead of XGBoost's 0.89 and logistic regression's 0.88. Aindo's modeling technology, in other words, isn't only useful for generating a realistic synthetic cohort: the same underlying model is a stronger nuisance model for the causal estimate than the classical alternatives used elsewhere in this analysis.

Note: this section uses only the real data.

Takeaway

Aindo's synthetic cohort reproduces the same causal conclusion

Takehome message: Aindo's synthetic cohort reproduces the same causal conclusion as the real data, at every stage of a full observational RWE pipeline, not just in its summary statistics.

  • Before any modeling, the synthetic data already matched the real data on individual variable distributions, binary prevalences, and the pairwise correlation structure across all confounders (the harder property to fake, and the one a causal analysis actually depends on).
  • The naive comparison was confounded by indication (higher-risk patients were preferentially prescribed statins) and pointed the wrong way (on both real and synthetic data: crude mortality rate 0.14 real vs. 0.13 synthetic). A real-world-evidence analysis has to correct for this; a naive synthetic-data check would not have caught it.
  • G-computation and TMLE corrected for the measured confounders and reversed that conclusion, in close agreement between the two datasets at every step (e.g. TMLE: -0.027 real vs. -0.031 synthetic for logistic regression, -0.019 vs. -0.021 for XGBoost). TMLE's doubly-robust estimate is the one we would report, and it lands in the same place whether it's computed on real patients or on Aindo's synthetic cohort. In all cases, point estimates from the synthetic data fall within the confidence intervals of the real data, and vice versa.

Put together, this is more than "the synthetic data looks similar"; it shows Aindo's synthetic data preserves the underlying causal mechanism, including the exact confounding-by-indication pattern this dataset was chosen to test. That is what makes it a credible substitute for the real patient data in this kind of analysis: an external collaborator, reviewer, or regulator could run this entire causal-inference workflow on the synthetic cohort alone, never touching an identifiable patient record, and reach the conclusion the real data supports, preserving both patient privacy and the validity of the inference.