Source code for match_stream.simulate
"""`simulate_matching()`: a data set with a known treatment effect, for
examples, tests and benchmarks.
The design of tests/reference/make_data.py (which made the R reference
fixtures) at any size: exact strata ``r`` x ``i``, three normal covariates,
a logistic treatment with stratum effects, the true propensity score ``ps``
and an outcome ``y`` whose treatment effect is `effect` for everyone.
"""
from __future__ import annotations
import numpy as np
import polars as pl
[docs]
def simulate_matching(n: int = 20_000, *, n_r: int = 5, n_i: int = 4, effect: float = 1.0,
seed: int = 20261101) -> pl.DataFrame:
"""Simulated units for matching.
With the defaults it reproduces ``tests/data/ref_data.csv``, the data the
test suite's reference values were computed on.
Parameters
----------
n : int
Units.
n_r, n_i : int
Levels of the two stratum columns ``r`` and ``i`` (``n_r * n_i`` strata).
effect : float
The treatment effect on ``y``.
seed : int
Random seed.
Returns
-------
polars.DataFrame
Columns ``id`` (1..n), ``r``, ``i``, ``d`` (treatment, 0/1), ``x1``,
``x2``, ``x3``, ``ps`` (the true propensity score), ``y``.
"""
rng = np.random.default_rng(seed)
r = rng.integers(0, n_r, n)
i = rng.integers(0, n_i, n)
x = rng.normal(size=(n, 3))
# the stratum effects scale with the default 5 x 4 grid's spacing
cell = (r * 0.1 - 0.2) + (i * 0.15 - 0.2)
lin = -1.2 + 0.5 * x[:, 0] - 0.3 * x[:, 1] + 0.2 * x[:, 2] + cell
ps = 1 / (1 + np.exp(-lin))
d = (rng.random(n) < ps).astype(np.int64)
y = 1 + effect * d + x[:, 0] + 0.5 * x[:, 1] + 0.3 * x[:, 2] + cell + rng.normal(size=n)
return pl.DataFrame({"id": np.arange(1, n + 1), "r": r, "i": i, "d": d,
"x1": x[:, 0], "x2": x[:, 1], "x3": x[:, 2], "ps": ps, "y": y})