Skip to content

Continuous distributions

Every continuous distribution inherits the shared method surface from ContinuousDistribution, documented first. The concrete classes follow, alphabetically, and list only what they define or override.

Base class

ContinuousDistribution

Abstract base class for continuous univariate distributions.

pdf

pdf(value: float | IntoExprColumn) -> Expr

Probability density function evaluated at value. Nulls and NaNs in value are propagated.

Source code in polars_stats/distributions/_base.py
def pdf(self, value: float | IntoExprColumn) -> pl.Expr:
    """Probability density function evaluated at `value`. Nulls and NaNs in `value` are propagated."""
    return self._pdf(as_expr(value))

log_pdf

log_pdf(value: float | IntoExprColumn) -> Expr

Natural logarithm of the pdf. Nulls and NaNs in value are propagated.

Source code in polars_stats/distributions/_base.py
def log_pdf(self, value: float | IntoExprColumn) -> pl.Expr:
    """Natural logarithm of the pdf. Nulls and NaNs in `value` are propagated."""
    return self._log_pdf(as_expr(value))

sample

sample(seed: int | None = None) -> Expr

Draw one random variate per row.

Output length follows the surrounding context (frame length under select / with_columns, partition length under over / group_by). Each row's draw derives from a sub-seed mixed from seed and the row's position, so the result is independent of chunking and thread scheduling.

A row with an invalid parameter raises; a row with a null parameter yields null. The output is named "sample" when every parameter is constant; otherwise it follows the first parameter expression (polars root-name semantics, so .name.* modifiers keep working).

Source code in polars_stats/distributions/_base.py
def sample(self, seed: int | None = None) -> pl.Expr:
    """Draw one random variate per row.

    Output length follows the surrounding context (frame length under `select` / `with_columns`,
    partition length under `over` / `group_by`). Each row's draw derives from a sub-seed mixed from
    `seed` and the row's position, so the result is independent of chunking and thread scheduling.

    A row with an invalid parameter raises; a row with a null parameter yields null. The output is
    named `"sample"` when every parameter is constant; otherwise it follows the first parameter
    expression (polars root-name semantics, so `.name.*` modifiers keep working).
    """
    return self._draw("sample", seed=_checked_seed(seed))

samples

samples(size: int, seed: int | None = None) -> Expr

Draw size random variates per row, as Array(inner=<element dtype>, shape=size).

Each row's draws are consecutive values from one per-row stream keyed by seed and the row's position, so samples(size=1) matches sample for the same seed and growing size extends each row's array without changing the existing draws. A null-parameter row yields a null array (outer validity), an invalid parameterisation raises. Named like sample, as "samples".

Source code in polars_stats/distributions/_base.py
def samples(self, size: int, seed: int | None = None) -> pl.Expr:
    """Draw `size` random variates per row, as `Array(inner=<element dtype>, shape=size)`.

    Each row's draws are consecutive values from one per-row stream keyed by `seed` and the row's
    position, so `samples(size=1)` matches `sample` for the same seed and growing `size` extends
    each row's array without changing the existing draws. A null-parameter row yields a null array
    (outer validity), an invalid parameterisation raises. Named like `sample`, as `"samples"`.
    """
    return self._draw("samples", size=_checked_size(size), seed=_checked_seed(seed))

cdf

cdf(value: float | IntoExprColumn) -> Expr

Cumulative distribution function, P(X <= value). Nulls and NaNs in value are propagated.

Source code in polars_stats/distributions/_base.py
def cdf(self, value: float | IntoExprColumn) -> pl.Expr:
    """Cumulative distribution function, `P(X <= value)`. Nulls and NaNs in `value` are propagated."""
    return self._cdf(as_expr(value))

log_cdf

log_cdf(value: float | IntoExprColumn) -> Expr

Natural logarithm of the cdf. Nulls and NaNs in value are propagated.

Source code in polars_stats/distributions/_base.py
def log_cdf(self, value: float | IntoExprColumn) -> pl.Expr:
    """Natural logarithm of the cdf. Nulls and NaNs in `value` are propagated."""
    return self._log_cdf(as_expr(value))

sf

sf(value: float | IntoExprColumn) -> Expr

Survival function, P(X > value) = 1 - cdf(value). Nulls and NaNs in value are propagated.

Source code in polars_stats/distributions/_base.py
def sf(self, value: float | IntoExprColumn) -> pl.Expr:
    """Survival function, `P(X > value) = 1 - cdf(value)`. Nulls and NaNs in `value` are propagated."""
    return self._sf(as_expr(value))

log_sf

log_sf(value: float | IntoExprColumn) -> Expr

Natural logarithm of the survival function. Nulls and NaNs in value are propagated.

Source code in polars_stats/distributions/_base.py
def log_sf(self, value: float | IntoExprColumn) -> pl.Expr:
    """Natural logarithm of the survival function. Nulls and NaNs in `value` are propagated."""
    return self._log_sf(as_expr(value))

ppf

ppf(quantile: float | IntoExprColumn) -> Expr

Percent point function (inverse cdf).

A quantile outside [0, 1] yields null. Nulls are propagated and a NaN quantile yields NaN, matching scipy.

Source code in polars_stats/distributions/_base.py
def ppf(self, quantile: float | IntoExprColumn) -> pl.Expr:
    """Percent point function (inverse cdf).

    A `quantile` outside `[0, 1]` yields **null**. Nulls are propagated and a `NaN` quantile yields
    `NaN`, matching scipy.
    """
    return self._ppf(as_expr(quantile))

isf

isf(quantile: float | IntoExprColumn) -> Expr

Inverse survival function, the value x with sf(x) == quantile.

Same domain contract as ppf, with the endpoints reversed: quantile outside [0, 1] yields null, nulls propagate, NaN yields NaN.

Source code in polars_stats/distributions/_base.py
def isf(self, quantile: float | IntoExprColumn) -> pl.Expr:
    """Inverse survival function, the value `x` with `sf(x) == quantile`.

    Same domain contract as `ppf`, with the endpoints reversed: `quantile` outside `[0, 1]` yields
    null, nulls propagate, `NaN` yields `NaN`.
    """
    return self._isf(as_expr(quantile))

mean abstractmethod

mean() -> Expr

Expected value E[X].

Source code in polars_stats/distributions/_base.py
@abstractmethod
def mean(self) -> pl.Expr:
    """Expected value `E[X]`."""

variance abstractmethod

variance() -> Expr

Variance Var[X] = E[(X - E[X])^2].

Source code in polars_stats/distributions/_base.py
@abstractmethod
def variance(self) -> pl.Expr:
    """Variance `Var[X] = E[(X - E[X])^2]`."""

std

std() -> Expr

Standard deviation, sqrt(variance).

Source code in polars_stats/distributions/_base.py
def std(self) -> pl.Expr:
    """Standard deviation, `sqrt(variance)`."""
    return self.variance().sqrt()

median

median() -> Expr

Median, ppf(0.5).

Source code in polars_stats/distributions/_base.py
def median(self) -> pl.Expr:
    """Median, `ppf(0.5)`."""
    return self._ppf(as_expr(0.5))

entropy abstractmethod

entropy() -> Expr

Differential or Shannon entropy, in nats.

Source code in polars_stats/distributions/_base.py
@abstractmethod
def entropy(self) -> pl.Expr:
    """Differential or Shannon entropy, in nats."""

Distributions

Beta

Beta(a: float | IntoExprColumn, b: float | IntoExprColumn)

Bases: ContinuousDistribution

Beta distribution on [0, 1] with shape parameters a (alpha) and b (beta).

Equivalent to scipy.stats.beta(a, b). The parameter names follow scipy; statrs calls them shape_a / shape_b.

Parameters:

Name Type Description Default
a float | IntoExprColumn

First shape parameter (alpha), with a > 0. Either a Python float or an IntoExprColumn (pl.Expr, pl.Series or column name str) carrying one shape per row.

required
b float | IntoExprColumn

Second shape parameter (beta), with b > 0. Same accepted types as a.

required

An invalid shape (a <= 0, b <= 0, or a non-finite parameter) is not checked at construction; it raises InvalidOperation (a ComputeError) when any method is evaluated. Null parameters propagate to null.

The support is [0, 1]: pdf is 0 outside it, and when a shape is < 1 the density diverges (inf or large finite values) at the corresponding boundary.

Source code in polars_stats/distributions/_beta.py
def __init__(self, a: float | IntoExprColumn, b: float | IntoExprColumn) -> None:
    self._a = coerce_param(a, name="a")
    self._b = coerce_param(b, name="b")
    self._scalar_kwargs = scalar_kwargs(a=scalar_float(a), b=scalar_float(b))

mean

mean() -> Expr

Expected value, a / (a + b).

Source code in polars_stats/distributions/_beta.py
def mean(self) -> pl.Expr:
    """Expected value, ``a / (a + b)``."""
    return self._moment(self._a / (self._a + self._b))

variance

variance() -> Expr

Variance, a * b / ((a + b)^2 * (a + b + 1)).

Source code in polars_stats/distributions/_beta.py
def variance(self) -> pl.Expr:
    """Variance, ``a * b / ((a + b)^2 * (a + b + 1))``."""
    return self._moment(self._a * self._b / ((self._a + self._b) ** 2 * (self._a + self._b + 1)))

entropy

entropy() -> Expr

Differential entropy in nats, ln B(a, b) - (a - 1) psi(a) - (b - 1) psi(b) + (a + b - 2) psi(a + b).

Log-Beta and digamma have no elementary closed form, so beta_entropy evaluates it in Rust.

Source code in polars_stats/distributions/_beta.py
def entropy(self) -> pl.Expr:
    """Differential entropy in nats, ``ln B(a, b) - (a - 1) psi(a) - (b - 1) psi(b) + (a + b - 2) psi(a + b)``.

    Log-Beta and digamma have no elementary closed form, so ``beta_entropy`` evaluates it in Rust.
    """
    return self._param_plugin("entropy")

Cauchy

Cauchy(loc: float | IntoExprColumn, scale: float | IntoExprColumn)

Bases: ContinuousDistribution

Cauchy distribution with location loc and scale scale.

Equivalent to scipy.stats.cauchy(loc=loc, scale=scale).

Parameters:

Name Type Description Default
loc float | IntoExprColumn

Location parameter, the median and the mode. Either a Python float or an IntoExprColumn (pl.Expr, pl.Series or column name str) carrying one location per row.

required
scale float | IntoExprColumn

Scale parameter, the half-width at half-maximum, with scale > 0. Same accepted types as loc.

required

Cauchy has no moments of any order, so mean(), variance() and std() are null where scipy returns nan. All three still validate: an invalid scale raises rather than nulling.

An invalid scale (scale <= 0 or a non-finite parameter) is not checked at construction; it raises InvalidOperation (a ComputeError) when any method is evaluated. Null parameters propagate to null.

Source code in polars_stats/distributions/_cauchy.py
def __init__(self, loc: float | IntoExprColumn, scale: float | IntoExprColumn) -> None:
    self._loc = coerce_param(loc, name="loc")
    self._scale = coerce_param(scale, name="scale")
    self._scalar_kwargs = scalar_kwargs(loc=scalar_float(loc), scale=scalar_float(scale))

mean

mean() -> Expr

Undefined, so null on every valid row; an invalid scale still raises.

Source code in polars_stats/distributions/_cauchy.py
def mean(self) -> pl.Expr:
    """Undefined, so **null** on every valid row; an invalid ``scale`` still raises."""
    return self._moment(_UNDEFINED_MOMENT)

variance

variance() -> Expr

Undefined, so null on every valid row; an invalid scale still raises.

Source code in polars_stats/distributions/_cauchy.py
def variance(self) -> pl.Expr:
    """Undefined, so **null** on every valid row; an invalid ``scale`` still raises."""
    return self._moment(_UNDEFINED_MOMENT)

median

median() -> Expr

Median, loc.

Source code in polars_stats/distributions/_cauchy.py
def median(self) -> pl.Expr:
    """Median, ``loc``."""
    return self._moment(self._loc)

entropy

entropy() -> Expr

Differential entropy, log(4 * pi * scale).

Source code in polars_stats/distributions/_cauchy.py
def entropy(self) -> pl.Expr:
    """Differential entropy, ``log(4 * pi * scale)``."""
    return self._moment(_LOG_FOUR_PI + self._scale.log())

Exponential

Exponential(rate: float | IntoExprColumn)

Bases: ContinuousDistribution

Exponential distribution with rate rate (λ).

Equivalent to scipy.stats.expon(scale=1 / rate). The API exposes rate (the statrs parameterisation) rather than scipy's scale = 1 / rate: it is the natural parameter and avoids the divide-by-zero footgun of passing scale=0.

Parameters:

Name Type Description Default
rate float | IntoExprColumn

Rate parameter λ, with rate > 0. Either a Python float or an IntoExprColumn (pl.Expr, pl.Series or column name str) carrying one rate per row.

required

An invalid rate (rate <= 0 or NaN) is not checked at construction; it raises InvalidOperation (a ComputeError) when any method is evaluated. The support is x >= 0: pdf and cdf are 0 for x < 0, and sf is 1 there. A null rate nulls every method, on the support and below it.

Source code in polars_stats/distributions/_exponential.py
def __init__(self, rate: float | IntoExprColumn) -> None:
    self._rate = coerce_param(rate, name="rate")
    self._scalar_kwargs = scalar_kwargs(rate=scalar_float(rate))

mean

mean() -> Expr

Expected value, 1 / rate.

Source code in polars_stats/distributions/_exponential.py
def mean(self) -> pl.Expr:
    """Expected value, ``1 / rate``."""
    return 1 / self._validated_params

variance

variance() -> Expr

Variance, 1 / rate**2.

Source code in polars_stats/distributions/_exponential.py
def variance(self) -> pl.Expr:
    """Variance, ``1 / rate**2``."""
    return 1 / self._validated_params**2

std

std() -> Expr

Standard deviation, 1 / rate.

Not variance().sqrt(): squaring and unsquaring the rate saturates about 300 decades earlier.

Source code in polars_stats/distributions/_exponential.py
def std(self) -> pl.Expr:
    """Standard deviation, ``1 / rate``.

    Not ``variance().sqrt()``: squaring and unsquaring the rate saturates about 300 decades earlier.
    """
    return 1 / self._validated_params

median

median() -> Expr

Median, log(2) / rate.

Source code in polars_stats/distributions/_exponential.py
def median(self) -> pl.Expr:
    """Median, ``log(2) / rate``."""
    return math.log(2) / self._validated_params

entropy

entropy() -> Expr

Differential entropy, 1 - log(rate).

Source code in polars_stats/distributions/_exponential.py
def entropy(self) -> pl.Expr:
    """Differential entropy, ``1 - log(rate)``."""
    return 1 - self._validated_params.log()

LogNormal

LogNormal(mu: float | IntoExprColumn = 0.0, sigma: float | IntoExprColumn = 1.0)

Bases: ContinuousDistribution

Log-normal distribution: X such that ln(X) is Normal(mu, sigma).

Equivalent to scipy.stats.lognorm(s=sigma, scale=exp(mu)) (with loc=0): scipy's shape s is sigma and its scale is exp(mu).

The support is x > 0; pdf and cdf are 0 and sf is 1 for x <= 0, matching scipy.

Parameters:

Name Type Description Default
mu float | IntoExprColumn

Location of the underlying normal (mean of ln(X)). Either a Python float or an IntoExprColumn (pl.Expr, pl.Series or column name str) carrying one value per row.

0.0
sigma float | IntoExprColumn

Scale of the underlying normal (std-dev of ln(X)), with sigma > 0. Same accepted types as mu.

1.0

An invalid parameterisation (sigma <= 0 or a non-finite parameter) is not checked at construction; it raises InvalidOperation (a ComputeError) when any method is evaluated. Null parameters propagate to null.

Source code in polars_stats/distributions/_lognormal.py
def __init__(self, mu: float | IntoExprColumn = 0.0, sigma: float | IntoExprColumn = 1.0) -> None:
    self._mu = coerce_param(mu, name="mu")
    self._sigma = coerce_param(sigma, name="sigma")
    self._scalar_kwargs = scalar_kwargs(mu=scalar_float(mu), sigma=scalar_float(sigma))

mean

mean() -> Expr

Expected value, exp(mu + sigma ** 2 / 2).

Source code in polars_stats/distributions/_lognormal.py
def mean(self) -> pl.Expr:
    """Expected value, ``exp(mu + sigma ** 2 / 2)``."""
    return self._moment((self._mu + self._half_sigma_sq).exp())

variance

variance() -> Expr

Variance, (exp(sigma ** 2) - 1) * exp(2 * mu + sigma ** 2).

The leading factor goes through expm1: the literal exp(sigma ** 2) - 1 cancels for a small sigma. No cut-over is needed, the argument is positive.

Source code in polars_stats/distributions/_lognormal.py
def variance(self) -> pl.Expr:
    """Variance, ``(exp(sigma ** 2) - 1) * exp(2 * mu + sigma ** 2)``.

    The leading factor goes through `expm1`: the literal ``exp(sigma ** 2) - 1`` cancels for a small
    ``sigma``. No cut-over is needed, the argument is positive.
    """
    return self._moment(expm1(self._sigma**2) * (2 * self._mu + self._sigma**2).exp())

std

std() -> Expr

Standard deviation, exp(0.5 * log(exp(sigma ** 2) - 1) + mu + sigma ** 2 / 2).

Not variance().sqrt(): the variance overflows f64 above sigma ~ 18.8 (so inf is right there), the standard deviation only above sigma ~ 26.6. std() ** 2 and variance() are therefore not interchangeable at a large sigma.

Source code in polars_stats/distributions/_lognormal.py
def std(self) -> pl.Expr:
    """Standard deviation, ``exp(0.5 * log(exp(sigma ** 2) - 1) + mu + sigma ** 2 / 2)``.

    Not ``variance().sqrt()``: the variance overflows ``f64`` above ``sigma ~ 18.8`` (so ``inf`` is right
    *there*), the standard deviation only above ``sigma ~ 26.6``. ``std() ** 2`` and ``variance()`` are
    therefore not interchangeable at a large ``sigma``.
    """
    return self._moment((0.5 * log_abs_expm1(self._sigma**2) + self._mu + self._half_sigma_sq).exp())

median

median() -> Expr

Median, exp(mu).

Source code in polars_stats/distributions/_lognormal.py
def median(self) -> pl.Expr:
    """Median, ``exp(mu)``."""
    return self._moment(self._mu.exp())

entropy

entropy() -> Expr

Differential entropy, mu + 0.5 * log(2 * pi * e * sigma ** 2).

Source code in polars_stats/distributions/_lognormal.py
def entropy(self) -> pl.Expr:
    """Differential entropy, ``mu + 0.5 * log(2 * pi * e * sigma ** 2)``."""
    return self._moment(self._mu + 0.5 * (math.tau * math.e * self._sigma**2).log())

Normal

Normal(mu: float | IntoExprColumn = 0.0, sigma: float | IntoExprColumn = 1.0)

Bases: ContinuousDistribution

Normal (Gaussian) distribution with location mu and scale sigma.

Equivalent to scipy.stats.norm(loc=mu, scale=sigma). The standard normal (mu=0, sigma=1) is the default parameterisation.

Parameters:

Name Type Description Default
mu float | IntoExprColumn

Location parameter. Either a Python float or an IntoExprColumn (pl.Expr, pl.Series or column name str) carrying one location per row.

0.0
sigma float | IntoExprColumn

Scale parameter, with sigma > 0. Same accepted types as mu.

1.0

An invalid scale (sigma <= 0 or a non-finite parameter) is not checked at construction; it raises InvalidOperation (a ComputeError) when any method is evaluated. Null parameters propagate to null.

Source code in polars_stats/distributions/_normal.py
def __init__(
    self,
    mu: float | IntoExprColumn = 0.0,
    sigma: float | IntoExprColumn = 1.0,
) -> None:
    self._mu = coerce_param(mu, name="mu")
    self._sigma = coerce_param(sigma, name="sigma")
    self._scalar_kwargs = scalar_kwargs(mu=scalar_float(mu), sigma=scalar_float(sigma))

mean

mean() -> Expr

Expected value, mu.

Source code in polars_stats/distributions/_normal.py
def mean(self) -> pl.Expr:
    """Expected value, ``mu``."""
    return self._moment(self._mu)

variance

variance() -> Expr

Variance, sigma ** 2.

Source code in polars_stats/distributions/_normal.py
def variance(self) -> pl.Expr:
    """Variance, ``sigma ** 2``."""
    return self._moment(self._sigma**2)

std

std() -> Expr

Standard deviation, sigma.

Not variance().sqrt(): squaring and unsquaring sigma saturates across roughly 300 decades.

Source code in polars_stats/distributions/_normal.py
def std(self) -> pl.Expr:
    """Standard deviation, ``sigma``.

    Not ``variance().sqrt()``: squaring and unsquaring ``sigma`` saturates across roughly 300 decades.
    """
    return self._moment(self._sigma)

median

median() -> Expr

Median, mu.

Source code in polars_stats/distributions/_normal.py
def median(self) -> pl.Expr:
    """Median, ``mu``."""
    return self._moment(self._mu)

entropy

entropy() -> Expr

Differential entropy, 0.5 * log(2 * pi * e * sigma ** 2).

Source code in polars_stats/distributions/_normal.py
def entropy(self) -> pl.Expr:
    """Differential entropy, ``0.5 * log(2 * pi * e * sigma ** 2)``."""
    return self._moment(0.5 * (math.tau * math.e * self._sigma**2).log())

Pareto

Pareto(scale: float | IntoExprColumn, shape: float | IntoExprColumn)

Bases: ContinuousDistribution

Pareto (type I) distribution with scale scale and shape shape, on the support x >= scale.

Equivalent to scipy.stats.pareto(b=shape, scale=scale): scipy's shape b is shape here, and the two arguments are in the opposite order, so pass both by keyword.

Parameters:

Name Type Description Default
scale float | IntoExprColumn

Scale parameter x_m, the lower bound of the support and the mode, with scale > 0. Either a Python float or an IntoExprColumn (pl.Expr, pl.Series or column name str) carrying one scale per row.

required
shape float | IntoExprColumn

Shape parameter alpha, the tail index (sf(x) = (scale / x) ** shape), with shape > 0. Same accepted types as scale.

required

mean() is +inf for shape <= 1 and variance() / std() for shape <= 2, where the integral diverges, as in scipy.

An invalid parameterisation (scale <= 0, shape <= 0 or a non-finite parameter) is not checked at construction; it raises InvalidOperation (a ComputeError) when any method is evaluated. Below the support pdf and cdf are 0 and sf is 1. A null parameter nulls every method, on the support and below it.

Source code in polars_stats/distributions/_pareto.py
def __init__(self, scale: float | IntoExprColumn, shape: float | IntoExprColumn) -> None:
    self._scale = coerce_param(scale, name="scale")
    self._shape = coerce_param(shape, name="shape")
    self._scalar_kwargs = scalar_kwargs(scale=scalar_float(scale), shape=scalar_float(shape))

mean

mean() -> Expr

Expected value, shape * scale / (shape - 1) for shape > 1, else +inf.

Source code in polars_stats/distributions/_pareto.py
def mean(self) -> pl.Expr:
    """Expected value, ``shape * scale / (shape - 1)`` for ``shape > 1``, else ``+inf``."""
    finite = self._scale * (self._shape / (self._shape - 1))
    return self._moment(pl.when(self._shape > _MEAN_DIVERGES_AT).then(finite).otherwise(math.inf))

variance

variance() -> Expr

Variance, scale**2 * shape / ((shape - 1)**2 * (shape - 2)) for shape > 2, else +inf.

Source code in polars_stats/distributions/_pareto.py
def variance(self) -> pl.Expr:
    """Variance, ``scale**2 * shape / ((shape - 1)**2 * (shape - 2))`` for ``shape > 2``, else ``+inf``."""
    finite = (self._scale / (self._shape - 1)) ** 2 * (self._shape / (self._shape - 2))
    return self._moment(pl.when(self._shape > _VARIANCE_DIVERGES_AT).then(finite).otherwise(math.inf))

std

std() -> Expr

Standard deviation, scale / (shape - 1) * sqrt(shape / (shape - 2)) for shape > 2, else +inf.

Not variance().sqrt(): squaring and unsquaring the scale saturates about 300 decades earlier.

Source code in polars_stats/distributions/_pareto.py
def std(self) -> pl.Expr:
    """Standard deviation, ``scale / (shape - 1) * sqrt(shape / (shape - 2))`` for ``shape > 2``, else ``+inf``.

    Not ``variance().sqrt()``: squaring and unsquaring the scale saturates about 300 decades earlier.
    """
    finite = self._scale / (self._shape - 1) * (self._shape / (self._shape - 2)).sqrt()
    return self._moment(pl.when(self._shape > _VARIANCE_DIVERGES_AT).then(finite).otherwise(math.inf))

entropy

entropy() -> Expr

Differential entropy, log(scale / shape) + 1 / shape + 1.

Summed as log(scale) - log(shape): the ratio over- and underflows where neither log does.

Source code in polars_stats/distributions/_pareto.py
def entropy(self) -> pl.Expr:
    """Differential entropy, ``log(scale / shape) + 1 / shape + 1``.

    Summed as ``log(scale) - log(shape)``: the ratio over- and underflows where neither log does.
    """
    return self._moment(self._scale.log() - self._shape.log() + 1 / self._shape + 1)

Uniform

Uniform(min: float | IntoExprColumn, max: float | IntoExprColumn)

Bases: ContinuousDistribution

Continuous uniform distribution over [min, max].

Equivalent to scipy.stats.uniform(loc=min, scale=max - min).

Following scipy, the density, cdf and the other closed forms treat the support as the closed interval [min, max] (so pdf(max) == 1 / (max - min)); the sample plugin draws on the half-open [min, max).

Parameters:

Name Type Description Default
min float | IntoExprColumn

Lower bound. Either a Python float or an IntoExprColumn (pl.Expr, pl.Series or column name str) carrying one bound per row.

required
max float | IntoExprColumn

Upper bound, with max > min. Same accepted types as min.

required

An invalid parameterisation (max <= min, a non-finite bound, or a width max - min overflowing float64) is not checked at construction; it raises InvalidOperation (a ComputeError) when any method is evaluated. A null bound nulls every method, on the support and off it.

Source code in polars_stats/distributions/_uniform.py
def __init__(self, min: float | IntoExprColumn, max: float | IntoExprColumn) -> None:  # noqa: A002
    self._min = coerce_param(min, name="min")
    self._max = coerce_param(max, name="max")
    self._scalar_kwargs = scalar_kwargs(min=scalar_float(min), max=scalar_float(max))

range property

range: Expr

Width of the support, max - min, validated in Rust; the moments derive from it.

mean

mean() -> Expr

Expected value, (min + max) / 2.

Source code in polars_stats/distributions/_uniform.py
def mean(self) -> pl.Expr:
    """Expected value, ``(min + max) / 2``."""
    return self._min + self.range / 2

variance

variance() -> Expr

Variance, (max - min)^2 / 12.

Source code in polars_stats/distributions/_uniform.py
def variance(self) -> pl.Expr:
    """Variance, ``(max - min)^2 / 12``."""
    return self.range**2 * ONE_TWELFTH

std

std() -> Expr

Standard deviation, (max - min) / sqrt(12).

Not variance().sqrt(): squaring and unsquaring the span saturates about 300 decades earlier.

Source code in polars_stats/distributions/_uniform.py
def std(self) -> pl.Expr:
    """Standard deviation, ``(max - min) / sqrt(12)``.

    Not ``variance().sqrt()``: squaring and unsquaring the span saturates about 300 decades earlier.
    """
    return self.range / math.sqrt(12)

median

median() -> Expr

Median, (min + max) / 2.

Source code in polars_stats/distributions/_uniform.py
def median(self) -> pl.Expr:
    """Median, ``(min + max) / 2``."""
    return self._min + self.range / 2

entropy

entropy() -> Expr

Differential entropy, log(max - min).

Source code in polars_stats/distributions/_uniform.py
def entropy(self) -> pl.Expr:
    """Differential entropy, ``log(max - min)``."""
    return self.range.log()

Weibull

Weibull(shape: float | IntoExprColumn, scale: float | IntoExprColumn)

Bases: ContinuousDistribution

Weibull distribution with shape shape and scale scale, on the support x >= 0.

Equivalent to scipy.stats.weibull_min(c=shape, scale=scale): scipy's shape c is shape here. Weibull(shape=1.0, scale=s) is Exponential(rate=1 / s).

Parameters:

Name Type Description Default
shape float | IntoExprColumn

Shape parameter k, with shape > 0. Either a Python float or an IntoExprColumn (pl.Expr, pl.Series or column name str) carrying one shape per row.

required
scale float | IntoExprColumn

Scale parameter lambda, with scale > 0. Same accepted types as shape.

required

An invalid parameterisation (shape <= 0, scale <= 0 or a non-finite parameter) is not checked at construction; it raises InvalidOperation (a ComputeError) when any method is evaluated. Below the support pdf and cdf are 0 and sf is 1. A null parameter nulls every method, on the support and below it.

Source code in polars_stats/distributions/_weibull.py
def __init__(self, shape: float | IntoExprColumn, scale: float | IntoExprColumn) -> None:
    self._shape = coerce_param(shape, name="shape")
    self._scale = coerce_param(scale, name="scale")
    self._scalar_kwargs = scalar_kwargs(shape=scalar_float(shape), scale=scalar_float(scale))

mean

mean() -> Expr

Expected value, scale * Gamma(1 + 1 / shape).

Source code in polars_stats/distributions/_weibull.py
def mean(self) -> pl.Expr:
    """Expected value, ``scale * Gamma(1 + 1 / shape)``."""
    return self._param_plugin("mean")

variance

variance() -> Expr

Variance, scale**2 * (Gamma(1 + 2 / shape) - Gamma(1 + 1 / shape)**2).

Squared from std(), which saturates about 300 decades later than the gamma function does.

Source code in polars_stats/distributions/_weibull.py
def variance(self) -> pl.Expr:
    """Variance, ``scale**2 * (Gamma(1 + 2 / shape) - Gamma(1 + 1 / shape)**2)``.

    Squared from ``std()``, which saturates about 300 decades later than the gamma function does.
    """
    return self._param_plugin("variance")

std

std() -> Expr

Standard deviation, scale * sqrt(Gamma(1 + 2 / shape) - Gamma(1 + 1 / shape)**2).

Source code in polars_stats/distributions/_weibull.py
def std(self) -> pl.Expr:
    """Standard deviation, ``scale * sqrt(Gamma(1 + 2 / shape) - Gamma(1 + 1 / shape)**2)``."""
    return self._param_plugin("std")

entropy

entropy() -> Expr

Differential entropy, euler_gamma * (1 - 1 / shape) + log(scale / shape) + 1.

Summed as log(scale) - log(shape): the ratio over- and underflows where neither log does.

Source code in polars_stats/distributions/_weibull.py
def entropy(self) -> pl.Expr:
    """Differential entropy, ``euler_gamma * (1 - 1 / shape) + log(scale / shape) + 1``.

    Summed as ``log(scale) - log(shape)``: the ratio over- and underflows where neither log does.
    """
    return self._moment(_EULER_GAMMA * (1 - 1 / self._shape) + self._scale.log() - self._shape.log() + 1)