Skip to content

Censoring

Censoring-time samplers and the bivariate draw used by TDCM.

Only runifcens and rexpocens are wired into the generators through model_cens; the rest are standalone. See the Censoring guide for how to apply them.

Censoring times

censoring

CensoringFunc

Bases: Protocol

Protocol for censoring time generators.

CensoringModel

Bases: Protocol

Protocol for class-based censoring generators.

WeibullCensoring

WeibullCensoring(scale: float, shape: float)

Class-based generator for Weibull censoring times.

Store Weibull scale and shape parameters.

Parameters:

Name Type Description Default
scale float

Scale parameter of the Weibull distribution.

required
shape float

Shape parameter of the Weibull distribution.

required
Source code in gen_surv/censoring.py
def __init__(self, scale: float, shape: float) -> None:
    """Store Weibull scale and shape parameters.

    Parameters
    ----------
    scale : float
        Scale parameter of the Weibull distribution.
    shape : float
        Shape parameter of the Weibull distribution.
    """
    self.scale = scale
    self.shape = shape

LogNormalCensoring

LogNormalCensoring(mean: float, sigma: float)

Class-based generator for log-normal censoring times.

Store log-normal parameters.

Parameters:

Name Type Description Default
mean float

Mean of the underlying normal distribution.

required
sigma float

Standard deviation of the underlying normal distribution.

required
Source code in gen_surv/censoring.py
def __init__(self, mean: float, sigma: float) -> None:
    """Store log-normal parameters.

    Parameters
    ----------
    mean : float
        Mean of the underlying normal distribution.
    sigma : float
        Standard deviation of the underlying normal distribution.
    """
    self.mean = mean
    self.sigma = sigma

GammaCensoring

GammaCensoring(shape: float, scale: float)

Class-based generator for Gamma censoring times.

Store Gamma distribution parameters.

Parameters:

Name Type Description Default
shape float

Shape parameter of the Gamma distribution.

required
scale float

Scale parameter of the Gamma distribution.

required
Source code in gen_surv/censoring.py
def __init__(self, shape: float, scale: float) -> None:
    """Store Gamma distribution parameters.

    Parameters
    ----------
    shape : float
        Shape parameter of the Gamma distribution.
    scale : float
        Scale parameter of the Gamma distribution.
    """
    self.shape = shape
    self.scale = scale

runifcens

runifcens(
    size: int, cens_par: float, rng: Generator | None = None
) -> NDArray[float64]

Generate uniform censoring times.

Parameters:

Name Type Description Default
size int

Number of samples.

required
cens_par float

Upper bound for the uniform distribution.

required
rng Generator

Random number generator to use. If None, a default generator is created.

None

Returns:

Type Description
NDArray[float64]

Array of censoring times.

Source code in gen_surv/censoring.py
def runifcens(
    size: int, cens_par: float, rng: Generator | None = None
) -> NDArray[np.float64]:
    """Generate uniform censoring times.

    Parameters
    ----------
    size : int
        Number of samples.
    cens_par : float
        Upper bound for the uniform distribution.
    rng : Generator, optional
        Random number generator to use. If ``None``, a default generator is
        created.

    Returns
    -------
    NDArray[np.float64]
        Array of censoring times.
    """
    r = default_rng() if rng is None else rng
    return r.uniform(0, cens_par, size)

rexpocens

rexpocens(
    size: int, cens_par: float, rng: Generator | None = None
) -> NDArray[float64]

Generate exponential censoring times.

Parameters:

Name Type Description Default
size int

Number of samples.

required
cens_par float

Mean of the exponential distribution.

required
rng Generator

Random number generator to use. If None, a default generator is created.

None

Returns:

Type Description
NDArray[float64]

Array of censoring times.

Source code in gen_surv/censoring.py
def rexpocens(
    size: int, cens_par: float, rng: Generator | None = None
) -> NDArray[np.float64]:
    """Generate exponential censoring times.

    Parameters
    ----------
    size : int
        Number of samples.
    cens_par : float
        Mean of the exponential distribution.
    rng : Generator, optional
        Random number generator to use. If ``None``, a default generator is
        created.

    Returns
    -------
    NDArray[np.float64]
        Array of censoring times.
    """
    r = default_rng() if rng is None else rng
    return r.exponential(scale=cens_par, size=size)

rweibcens

rweibcens(
    size: int,
    scale: float,
    shape: float,
    rng: Generator | None = None,
) -> NDArray[float64]

Generate Weibull-distributed censoring times.

Parameters:

Name Type Description Default
size int

Number of samples.

required
scale float

Scale parameter of the Weibull distribution.

required
shape float

Shape parameter of the Weibull distribution.

required
rng Generator

Random number generator to use. If None, a default generator is created.

None

Returns:

Type Description
NDArray[float64]

Array of censoring times.

Source code in gen_surv/censoring.py
def rweibcens(
    size: int, scale: float, shape: float, rng: Generator | None = None
) -> NDArray[np.float64]:
    """Generate Weibull-distributed censoring times.

    Parameters
    ----------
    size : int
        Number of samples.
    scale : float
        Scale parameter of the Weibull distribution.
    shape : float
        Shape parameter of the Weibull distribution.
    rng : Generator, optional
        Random number generator to use. If ``None``, a default generator is
        created.

    Returns
    -------
    NDArray[np.float64]
        Array of censoring times.
    """
    r = default_rng() if rng is None else rng
    return r.weibull(shape, size) * scale

rlognormcens

rlognormcens(
    size: int,
    mean: float,
    sigma: float,
    rng: Generator | None = None,
) -> NDArray[float64]

Generate log-normal-distributed censoring times.

Parameters:

Name Type Description Default
size int

Number of samples.

required
mean float

Mean of the underlying normal distribution.

required
sigma float

Standard deviation of the underlying normal distribution.

required
rng Generator

Random number generator to use. If None, a default generator is created.

None

Returns:

Type Description
NDArray[float64]

Array of censoring times.

Source code in gen_surv/censoring.py
def rlognormcens(
    size: int, mean: float, sigma: float, rng: Generator | None = None
) -> NDArray[np.float64]:
    """Generate log-normal-distributed censoring times.

    Parameters
    ----------
    size : int
        Number of samples.
    mean : float
        Mean of the underlying normal distribution.
    sigma : float
        Standard deviation of the underlying normal distribution.
    rng : Generator, optional
        Random number generator to use. If ``None``, a default generator is
        created.

    Returns
    -------
    NDArray[np.float64]
        Array of censoring times.
    """
    r = default_rng() if rng is None else rng
    return r.lognormal(mean, sigma, size)

rgammacens

rgammacens(
    size: int,
    shape: float,
    scale: float,
    rng: Generator | None = None,
) -> NDArray[float64]

Generate Gamma-distributed censoring times.

Parameters:

Name Type Description Default
size int

Number of samples.

required
shape float

Shape parameter of the Gamma distribution.

required
scale float

Scale parameter of the Gamma distribution.

required
rng Generator

Random number generator to use. If None, a default generator is created.

None

Returns:

Type Description
NDArray[float64]

Array of censoring times.

Source code in gen_surv/censoring.py
def rgammacens(
    size: int, shape: float, scale: float, rng: Generator | None = None
) -> NDArray[np.float64]:
    """Generate Gamma-distributed censoring times.

    Parameters
    ----------
    size : int
        Number of samples.
    shape : float
        Shape parameter of the Gamma distribution.
    scale : float
        Scale parameter of the Gamma distribution.
    rng : Generator, optional
        Random number generator to use. If ``None``, a default generator is
        created.

    Returns
    -------
    NDArray[np.float64]
        Array of censoring times.
    """
    r = default_rng() if rng is None else rng
    return r.gamma(shape, scale, size)

Bivariate sampling

bivariate

sample_bivariate_distribution

sample_bivariate_distribution(
    n: int,
    dist: str,
    corr: float,
    dist_par: Sequence[float],
    seed: RandomStateLike = None,
) -> NDArray[float64]

Draw dependent samples with Weibull or exponential marginals.

Dependence is induced with a Gaussian copula: a pair of correlated standard normals is mapped to uniforms through the normal CDF, and those uniforms are pushed through the inverse marginal CDFs.

Parameters:

Name Type Description Default
n int

Number of samples to generate.

required
dist (weibull, exponential)

Type of marginal distributions.

"weibull"
corr float

Correlation of the underlying normals, in (-1, 1). Negative values produce negative dependence. Note that this is the correlation on the latent normal scale; because the marginals are skewed, the Pearson correlation of the returned values is smaller in magnitude, while the rank correlation is preserved.

required
dist_par Sequence[float]

Distribution parameters [a1, b1, a2, b2] for the Weibull case or [lambda1, lambda2] for the exponential case.

required
seed int or Generator

Seed or generator for reproducibility.

None

Returns:

Type Description
NDArray[float64]

Array of shape (n, 2) with the sampled pairs.

Examples:

>>> from gen_surv.bivariate import sample_bivariate_distribution
>>> sample_bivariate_distribution(
...     3,
...     "weibull",
...     0.3,
...     [1.0, 2.0, 1.5, 2.5],
...     seed=42,
... )
array([[...], [...], [...]])

Raises:

Type Description
ValidationError

If dist is unsupported or dist_par has an invalid length.

Source code in gen_surv/bivariate.py
def sample_bivariate_distribution(
    n: int,
    dist: str,
    corr: float,
    dist_par: Sequence[float],
    seed: RandomStateLike = None,
) -> NDArray[np.float64]:
    """Draw dependent samples with Weibull or exponential marginals.

    Dependence is induced with a Gaussian copula: a pair of correlated standard
    normals is mapped to uniforms through the normal CDF, and those uniforms are
    pushed through the inverse marginal CDFs.

    Parameters
    ----------
    n : int
        Number of samples to generate.
    dist : {"weibull", "exponential"}
        Type of marginal distributions.
    corr : float
        Correlation of the underlying normals, in ``(-1, 1)``. Negative values
        produce negative dependence. Note that this is the correlation on the
        latent normal scale; because the marginals are skewed, the Pearson
        correlation of the returned values is smaller in magnitude, while the
        rank correlation is preserved.
    dist_par : Sequence[float]
        Distribution parameters ``[a1, b1, a2, b2]`` for the Weibull case or
        ``[lambda1, lambda2]`` for the exponential case.
    seed : int or numpy.random.Generator, optional
        Seed or generator for reproducibility.

    Returns
    -------
    NDArray[np.float64]
        Array of shape ``(n, 2)`` with the sampled pairs.

    Examples
    --------
    >>> from gen_surv.bivariate import sample_bivariate_distribution
    >>> sample_bivariate_distribution(
    ...     3,
    ...     "weibull",
    ...     0.3,
    ...     [1.0, 2.0, 1.5, 2.5],
    ...     seed=42,
    ... )  # doctest: +ELLIPSIS
    array([[...], [...], [...]])

    Raises
    ------
    ValidationError
        If ``dist`` is unsupported or ``dist_par`` has an invalid length.
    """

    validate_dg_biv_inputs(n, dist, corr, dist_par)
    rng = resolve_rng(seed)

    # Correlated standard normals, then the probability integral transform.
    # Applying the normal CDF is what makes the marginals exact and keeps the
    # sign of ``corr``. Squaring the normals instead -- as releases up to 1.2.0
    # did -- yields chi-squared marginals and maps both +r and -r onto the same
    # positive dependence, so negative dependence became unreachable.
    cov = [[1.0, corr], [corr, 1.0]]
    z = rng.multivariate_normal([0.0, 0.0], cov, size=n)
    u = np.clip(ndtr(z), _CLIP_EPS, 1 - _CLIP_EPS)

    # Inverse marginal CDFs.
    if dist == "exponential":
        x1 = -np.log(1 - u[:, 0]) / dist_par[0]
        x2 = -np.log(1 - u[:, 1]) / dist_par[1]

    else:  # dist == "weibull"
        a1, b1, a2, b2 = dist_par
        x1 = (-np.log(1 - u[:, 0]) / a1) ** (1 / b1)
        x2 = (-np.log(1 - u[:, 1]) / a2) ** (1 / b2)

    return np.column_stack([x1, x2])