Simulation
SEM-based data simulator with a known confound structure. See the Simulating Data guide for a conceptual overview.
compute_r2s(sim)
Convenience function to empirically estimate the R² components from the simulated data:
- r2_naive: R²(y ~ true_X)
- r2_conf_only: R²(y ~ all confounds)
- r2_full: R²(y ~ true_X + all confounds)
- r2_unique_X: r2_full - r2_conf_only
generate_confound_grid(r2_x_y_values=GRID_R2_X_Y, kappa_values=GRID_KAPPA, n_features=105, n_features_informative=10, n_confound_only_features=10, n_pure_signal_features=10, n_confounds=2, n_samples=5000, rho_informative=0.5, rho_confound_only=0.5, rho_pure_signal=0.5, randomize_signs=True, random_state=123)
Generate the full matrix of confound scenarios for the demonstration.
Rows sweep the brain–outcome strength R2_X_y (default {0.09, 0.36, 0.81});
columns sweep the spurious fraction kappa (default {0, 0.2, ..., 1.0}) — the
fraction of the naive R² that is confound-driven (see
:func:simulate_data_given_kappa). The true, deconfounded value in each cell is
R2_X_y_given_Z = (1 - kappa) * R2_X_y.
Each cell contains three interpretable edge classes (default 10 each): mixed (signal + confound), pure-signal (⟂ confound) and confound-only.
Returns:
| Type | Description |
|---|---|
dict keyed by ``(R2_X_y, kappa)`` → simulated-data dict (``X``, ``Z``, ``y``,
|
|
``true_X``, ``info``). Each cell gets an independent seed derived from
|
|
``random_state`` so cells are reproducible and mutually independent.
|
|
simulate_data_given_R2(R2_X_y, R2_X_y_given_Z, R2_Z_y, n_features=100, n_features_informative=10, n_confound_only_features=0, n_pure_signal_features=0, n_confounds=2, n_samples=10000, rho_informative=0.5, rho_confound_only=0.5, rho_pure_signal=0.5, randomize_signs=True, random_state=None)
Simulate data that matches specified R² relationships between a latent predictor X, confounds Z, and outcome y.
Inputs (targets)
R2_X_y : float Naive R² from regressing y ~ X. R2_X_y_given_Z : float Unique / incremental R² from X after adjusting for all confounds Z: R2_X_y_given_Z = R2(y ~ X + Z) - R2(y ~ Z). R2_Z_y : float Naive R² from regressing y ~ Z (all confounds jointly).
Data structure
- latent variable: true_X (standardized)
- confounds: conf1..confK (K = n_confounds); only conf1 carries the confound
- features: up to four edge classes —
mixed(copies of true_X; signal + confound), optionalpure_signal(copies of the confound-orthogonalised signal), optionalconfound_only(copies of the confound), and pure-noise edges — see_build_dataset_from_corr. - outcome: y (standardized)
R² logic
- Naive R²(y ~ X) ≈ R2_X_y
- Naive R²(y ~ Z) ≈ R2_Z_y
- Unique R² of X given Z ≈ R2_X_y_given_Z, so R2_full ≈ R2_Z_y + R2_X_y_given_Z
Returns:
| Type | Description |
|---|---|
dict with keys ``X``, ``Z``, ``y``, ``true_X`` (numpy arrays) and ``info``.
|
|
simulate_data_given_kappa(R2_X_y, kappa, n_features=100, n_features_informative=10, n_confound_only_features=10, n_pure_signal_features=10, n_confounds=2, n_samples=10000, rho_informative=0.5, rho_confound_only=0.5, rho_pure_signal=0.5, randomize_signs=True, random_state=None)
Simulate data by sweeping the confound strength as the spurious fraction
kappa — the fraction of the naive R²(y~X) that is confound-driven.
Convention (the confound "steals" a fraction kappa of the brain's
explained variance, adding no net variance):
R2_X_y_given_Z = (1 - kappa) * R2_X_y (true, deconfounded value)
R2_Z_y = kappa * R2_X_y
From these the required brain–confound coupling rho = corr(confound, X) is
solved internally; it depends only on kappa (not on R2_X_y):
rho ≈ {0, 0.45, 0.63, 0.77, 0.89, 0.99} for kappa = {0, .2, .4, .6, .8, 1}.
Unlike pinning corr(Z,y) = corr(X,y), this parameterisation is feasible for
all R2_X_y (including 0.81) across the whole kappa sweep.
kappa = 0 → no confounding (true == naive); kappa = 1 → full confounding
(true → 0; rho approaches its clamp at 0.99).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
R2_X_y
|
float
|
Naive R²(y ~ X). |
required |
kappa
|
float
|
Spurious fraction in [0, 1]. |
required |
Returns:
| Type | Description |
|---|---|
dict with keys ``X``, ``Z``, ``y``, ``true_X`` and ``info`` (the info dict also
|
|
records ``R2_X_y``, ``R2_X_y_given_Z``, ``R2_Z_y`` and ``spurious_fraction``).
|
|