Skip to content

Simulation results

The configuration and ground truth returned alongside the data. See the guide for what the truth keys mean per model.

results

Configuration and ground truth alongside the simulated data.

A generator returns a DataFrame, which is what an analyst wants and what an estimator consumes. It is not what a methodologist wants: the interesting quantities in a simulation study are the ones a real dataset could never contain — the coefficients that produced it, the latent event time before censoring intervened, which subjects are cured, when a covariate crossed over.

:func:simulate returns those alongside the frame:

from gen_surv import simulate result = simulate("cphm", n=100, beta=0.5, covariate_range=2.0, ... model_cens="uniform", cens_par=1.0, seed=42) result.data.shape (100, 3) sorted(result.truth) ['beta', 'censoring_time', 'covariates', 'event_time', 'linear_predictor']

The existing gen_* functions are unchanged and still return a frame. This is an addition, not a replacement.

SimulationConfig dataclass

SimulationConfig(
    model: str,
    params: Mapping[str, Any] = dict(),
    version: str = "",
)

Everything needed to reproduce a simulated dataset.

Attributes:

Name Type Description
model str

The generator's registered name, as passed to :func:gen_surv.generate.

params Mapping[str, Any]

The keyword arguments it was called with, seed included.

version str

The gen_surv version that produced the data. A bug fix in a sampler changes what a seed produces, so the version is part of the specification and not decoration.

seed property
seed: Any

The seed the data was produced with, or None if unseeded.

replace
replace(**changes: Any) -> 'SimulationConfig'

Return a copy with changes applied to the parameters.

The natural way to sweep: hold a scenario fixed and vary one thing.

base = SimulationConfig("cphm", {"n": 100, "beta": 0.5}) base.replace(seed=7).params["seed"] 7 base.params.get("seed") is None # the original is untouched True

Source code in gen_surv/results.py
def replace(self, **changes: Any) -> "SimulationConfig":
    """Return a copy with ``changes`` applied to the parameters.

    The natural way to sweep: hold a scenario fixed and vary one thing.

    >>> base = SimulationConfig("cphm", {"n": 100, "beta": 0.5})
    >>> base.replace(seed=7).params["seed"]
    7
    >>> base.params.get("seed") is None      # the original is untouched
    True
    """
    return SimulationConfig(
        model=self.model, params={**self.params, **changes}, version=self.version
    )
run
run() -> 'SimulationResult'

Run this configuration and return the result.

Source code in gen_surv/results.py
def run(self) -> "SimulationResult":
    """Run this configuration and return the result."""
    return simulate(self.model, **self.params)
to_dict
to_dict() -> dict[str, Any]

A plain dictionary, for writing to JSON or YAML.

Source code in gen_surv/results.py
def to_dict(self) -> dict[str, Any]:
    """A plain dictionary, for writing to JSON or YAML."""
    return {
        "model": self.model,
        "params": dict(self.params),
        "version": self.version,
    }
from_dict classmethod
from_dict(payload: Mapping[str, Any]) -> 'SimulationConfig'

Rebuild a configuration from :meth:to_dict output.

Source code in gen_surv/results.py
@classmethod
def from_dict(cls, payload: Mapping[str, Any]) -> "SimulationConfig":
    """Rebuild a configuration from :meth:`to_dict` output."""
    return cls(
        model=payload["model"],
        params=payload.get("params", {}),
        version=payload.get("version", ""),
    )

SimulationResult dataclass

SimulationResult(
    data: DataFrame,
    config: SimulationConfig,
    truth: Mapping[str, Any] = dict(),
)

Simulated data, the configuration behind it, and the ground truth.

Attributes:

Name Type Description
data DataFrame

Exactly what the corresponding gen_* function returns.

config SimulationConfig

The call that produced it.

truth Mapping[str, Any]

Quantities a real dataset could not contain. Which keys are present depends on the model; see :func:simulate.

n_subjects property
n_subjects: int

Number of subjects, which is not len(data) for every model.

truth_frame
truth_frame() -> DataFrame

The per-subject entries of truth as a frame.

Scalars and anything not one-per-subject are left out, so the result lines up with the subjects and can be joined onto the data.

Source code in gen_surv/results.py
def truth_frame(self) -> pd.DataFrame:
    """The per-subject entries of ``truth`` as a frame.

    Scalars and anything not one-per-subject are left out, so the result
    lines up with the subjects and can be joined onto the data.
    """
    n = self.n_subjects
    columns = {
        key: np.asarray(value)
        for key, value in self.truth.items()
        if isinstance(value, np.ndarray) and value.ndim == 1 and len(value) == n
    }
    return pd.DataFrame(columns)

simulate

simulate(model: str, **kwargs: Any) -> SimulationResult

Generate data and return it with its configuration and ground truth.

Parameters:

Name Type Description Default
model str

Any name accepted by :func:gen_surv.generate.

required
**kwargs Any

The model's parameters, exactly as for :func:gen_surv.generate.

{}

Returns:

Type Description
SimulationResult

The frame, the configuration, and whatever ground truth the model can expose.

Notes

The keys in truth vary by model. Common ones:

beta / betas The coefficients actually used. This matters most where they were drawn at random because the caller omitted them, in which case there is otherwise no way to learn what they were. covariates The covariate matrix, as an array. linear_predictor covariates @ betas. event_time and censoring_time The latent times before the minimum of the two was taken, so you can see what censoring hid.

Model-specific keys are documented on each model's page. A generator that cannot expose anything beyond its frame returns an empty truth rather than inventing entries.

Examples:

>>> from gen_surv import simulate
>>> result = simulate("piecewise_exponential", n=50, breakpoints=[1.0],
...                   hazard_rates=[0.5, 1.5], seed=7)
>>> result.truth["betas"]        # drawn at random, and otherwise unknowable
array([...])
Source code in gen_surv/results.py
def simulate(model: str, **kwargs: Any) -> SimulationResult:
    """Generate data and return it with its configuration and ground truth.

    Parameters
    ----------
    model : str
        Any name accepted by :func:`gen_surv.generate`.
    **kwargs
        The model's parameters, exactly as for :func:`gen_surv.generate`.

    Returns
    -------
    SimulationResult
        The frame, the configuration, and whatever ground truth the model can
        expose.

    Notes
    -----
    The keys in ``truth`` vary by model. Common ones:

    ``beta`` / ``betas``
        The coefficients actually used. This matters most where they were
        **drawn at random** because the caller omitted them, in which case
        there is otherwise no way to learn what they were.
    ``covariates``
        The covariate matrix, as an array.
    ``linear_predictor``
        ``covariates @ betas``.
    ``event_time`` and ``censoring_time``
        The latent times before the minimum of the two was taken, so you can
        see what censoring hid.

    Model-specific keys are documented on each model's page. A generator that
    cannot expose anything beyond its frame returns an empty ``truth`` rather
    than inventing entries.

    Examples
    --------
    >>> from gen_surv import simulate
    >>> result = simulate("piecewise_exponential", n=50, breakpoints=[1.0],
    ...                   hazard_rates=[0.5, 1.5], seed=7)
    >>> result.truth["betas"]        # drawn at random, and otherwise unknowable
    array([...])
    """
    from ._truth import capture
    from .interface import ModelType, generate

    config = SimulationConfig(model=model, params=dict(kwargs))

    # `generate` validates the name against the registry and raises a
    # ChoiceError listing the valid ones, so the cast only tells the type
    # checker what that check already guarantees at runtime.
    with capture() as truth:
        data = generate(cast(ModelType, model), **kwargs)

    return SimulationResult(data=data, config=config, truth=truth)