Getting Started with simple_model()¶
SRMI.simple_model() is the fastest way to go from a raw dataframe to a working multiple
imputation. Give it a dataframe and an id column, and it does the rest:
- Looks at every other column and finds the ones with missing values.
- For each one, decides whether it's binary (only two values, like a yes/no flag) or continuous (any other number).
- Picks a model for each - LightGBM by default, which works well for both.
- Builds the Variable objects and hands them to
SRMI, ready to run.
Nothing here is hidden or magic - it's building exactly the same Variable/SRMI objects
you'd build by hand (see Advanced/Manual Construction), just
picking sensible defaults for you. You can always inspect what it decided before running
anything, and override any part of it - later pages in this section show how.
Walkthrough¶
import numpy as np
import polars as pl
from survey_kit.imputation.srmi import SRMI
from survey_kit.utilities.dataframe import summary
from survey_kit import logger, config
# %%
# Draw some random data with a few variables missing
n_rows = 5_000
rng = np.random.default_rng(20260913)
x1 = rng.normal(size=n_rows)
x2 = rng.normal(size=n_rows)
income_latent = 40_000 + 8_000 * x1 - 3_000 * x2 + rng.normal(scale=5_000, size=n_rows)
has_disability = (rng.normal(size=n_rows) + 0.5 * x1 > 1.0).astype(int)
df = pl.DataFrame(
dict(
person_id=range(n_rows),
age=rng.integers(18, 90, size=n_rows),
education_years=rng.integers(8, 20, size=n_rows),
income=income_latent,
has_disability=has_disability,
)
)
# Punch some holes in the two variables we want imputed
missing_income = rng.random(n_rows) < 0.2
missing_disability = rng.random(n_rows) < 0.15
df = df.with_columns(
[
pl.when(pl.Series(missing_income)).then(None).otherwise(pl.col("income")).alias(
"income"
),
pl.when(pl.Series(missing_disability))
.then(None)
.otherwise(pl.col("has_disability"))
.alias("has_disability"),
]
)
logger.info(f"Missing income: {missing_income.sum()} of {n_rows} rows")
logger.info(f"Missing disability: {missing_disability.sum()} of {n_rows} rows")
# %%
logger.info("That's it - point SRMI.simple_model() at the dataframe and an id column")
logger.info(
"It finds every column with missing values, figures out whether each one is "
"binary or continuous, and picks a sensible model for each - no Variable objects "
"to build by hand."
)
srmi = SRMI.simple_model(
df=df,
index="person_id",
replication=SRMI.Replication(n_implicates=3, n_iterations=3),
parallel=SRMI.Parallel(enabled=False),
bootstrap=SRMI.Bootstrap(enabled=True),
storage=SRMI.Storage(
path_model=f"{config.path_temp_files}/tutorial_simple_model_getting_started",
force_start=True,
),
)
# %%
logger.info("Inspect what it decided before running anything")
for v in srmi.variables:
logger.info(f" {v.impute_var}: modeltype={v.modeltype.name}, predictors={v.model}")
# %%
logger.info("Now actually run the imputation")
srmi.run()
# %%
logger.info("Look at one completed implicate")
_ = srmi.df_implicates.pipe(summary)
What to do next¶
Once you've run something like the above, the natural next questions are usually:
- "One of my columns is really a category, not just binary/continuous" → see Variable Types & Models
- "One of my predictors is a category, or I want to borrow strength across a grouping variable" → see Categorical Predictors & Group Effects
- "One of my variables is mostly zero, with a real amount for everyone else" → see Semicontinuous Variables
- "I need to keep a variable out of a model" → see Controlling Predictors
- "Did this actually converge, and do the imputed values look right?" → see Convergence Diagnostics and Imputation Quality & Propensity Diagnostics