cleverly.datasets.make_nonlinear_bounded#

cleverly.datasets.make_nonlinear_bounded(n: int = 1000, *, seed: int | Generator | None = None, backend: Literal['pandas', 'polars'] | str | None = None) → tuple[Any, dict[str, float]][source]#

Generate a bounded outcome with nonlinear nuisance functions.

Parameters:
nint

Number of observations.

seedint, Generator, or None

Seed or NumPy random generator.

backend{“pandas”, “polars”, “pyarrow”} or None, default=None

Dataframe backend. None uses pandas when installed, then the first available backend.

Returns:
dataframe

Simulated observations with a proportion outcome, treatment, and covariates.

truthdict of str to float

Exact causal parameters for the data-generating process.

See also

cleverly.datasets.make_nonlinear_ate

The unbounded outcome with the same propensity.

Notes

The outcome Y is a proportion. Its known support is the open interval (0, 1). The prespecified outcome bounds for this law are therefore q_bounds=(0, 1). They come from the law, not from the observed outcomes.

The conditional mean of Y is the expit of a nonlinear predictor, and nonlinear_bounded_dgp() gives its terms. A linear model is misspecified for the propensity and for the outcome mean. The effect varies with W1 and W2, so ate, att, and atc differ.

The propensity is 0.05 + 0.90 expit(u(W)), so it lies in [0.05, 0.95]. This strong positivity keeps the ATE efficiency bound finite. nonlinear_dgp() gives u and the reason.

The truth holds ey1, ey0, ate, att, and atc. It holds no rr or or, because a fit treats a proportion as a continuous outcome and refuses those estimands for it.

Examples

>>> from cleverly.datasets import make_nonlinear_bounded
>>> frame, truth = make_nonlinear_bounded(n=200, seed=1)
>>> list(frame.columns)
['Y', 'A', 'W1', 'W2', 'W3', 'W4']
>>> bool(frame["Y"].between(0.0, 1.0, inclusive="neither").all())
True
>>> sorted(key for key in truth if not key.startswith("sample_"))
['atc', 'ate', 'att', 'ey0', 'ey1']