API reference¶
Technical description of the machinery. The generated docstrings live on two pages, Continuous and Discrete; the input types, dtypes, and error contracts are in Parameters and contracts.
For worked examples, see the tutorial and the How-to guides.
Catalogue¶
| Distribution | Kind | Parameters | scipy equivalent |
|---|---|---|---|
Beta(a, b) |
continuous | a > 0, b > 0 |
beta(a, b) |
Cauchy(loc, scale) |
continuous | scale > 0 |
cauchy(loc=loc, scale=scale); its undefined moments are null here, nan there |
Exponential(rate) |
continuous | rate > 0 |
expon(scale=1 / rate) |
LogNormal(mu, sigma) |
continuous | sigma > 0 |
lognorm(s=sigma, scale=exp(mu)) |
Normal(mu, sigma) |
continuous | sigma > 0 |
norm(loc=mu, scale=sigma) |
Pareto(scale, shape) |
continuous | scale > 0, shape > 0 |
pareto(b=shape, scale=scale); the divergent moments are +inf in both |
Uniform(min, max) |
continuous | max > min |
uniform(loc=min, scale=max - min) |
Weibull(shape, scale) |
continuous | shape > 0, scale > 0 |
weibull_min(c=shape, scale=scale) |
Bernoulli(p) |
discrete | 0 <= p <= 1 |
bernoulli(p) |
Binomial(n, p) |
discrete | n >= 0, 0 <= p <= 1 |
binom(n, p) |
DiscreteUniform(min, max) |
discrete | min <= max, both inclusive |
randint(low=min, high=max + 1); max is inclusive |
Geometric(p) |
discrete | 0 < p <= 1 |
geom(p) |
Each class names its parameters after the distribution's conventional parameters. Normal and LogNormal default to
mu=0.0, sigma=1.0; the others have no defaults. Parameter values are validated at evaluation, not at construction.
Method surface¶
Every distribution exposes the same surface, defined on the base classes. Value-keyed methods take a scalar, a column
name (str), or a pl.Expr; argument-free statistics take none. All return a pl.Expr.
| Method | Continuous | Discrete | Meaning |
|---|---|---|---|
pdf(x) |
yes | no | probability density |
log_pdf(x) |
yes | no | log density |
pmf(x) |
no | yes | probability mass |
log_pmf(x) |
no | yes | log mass |
cdf(x) |
yes | yes | P(X <= x) |
sf(x) |
yes | yes | survival, P(X > x), accurate in the upper tail |
ppf(q) |
yes | yes | inverse cdf, q in [0, 1] |
isf(q) |
yes | yes | inverse survival, the x with sf(x) = q |
log_cdf(x) |
yes | yes | log cdf |
log_sf(x) |
yes | yes | log survival |
mean() |
yes | yes | E[X] |
variance() / std() |
yes | yes | variance and its square root |
median() |
yes | yes | ppf(0.5), or a closed form when available |
entropy() |
yes | yes | differential / Shannon entropy, in nats |
sample(seed=None) |
yes | yes | one variate per row |
samples(size, seed=None) |
yes | yes | a width-size Array per row |
Every value-keyed method runs in Rust (a native statrs binding or a hand-written stable form); median is
ppf(0.5) unless a closed form exists, and std is sqrt(variance) unless a form with a wider representable range
does. The exceptions are Beta and Binomial, whose log_cdf / log_sf are log(cdf) / log(sf) for now (see
Accuracy).
Argument-free statistics return one value per row of parameters: with column-valued parameters, mean() yields the
mean of a different distribution on every row. A moment the distribution does not have is null, one whose
integral diverges is +inf, and both still raise on an invalid parameter; see
Parameters and contracts.
Type guards¶
Two module-level guards say which kind a distribution is, for code that accepts either and has to pick between
pmf and pdf. Both narrow the argument's type, so the branch body needs no cast.
is_discrete
¶
is_discrete(obj: object) -> TypeIs[DiscreteDistribution]
Whether obj is a discrete distribution.
Narrowing guard: on the true branch a type checker sees obj as a
DiscreteDistribution, so pmf / log_pmf are reachable without a cast, and on the
false branch it drops DiscreteDistribution from the type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
obj
|
object
|
Any object. |
required |
Returns:
| Type | Description |
|---|---|
TypeIs[DiscreteDistribution]
|
|
Examples:
>>> import polars_stats as ps
>>> ps.is_discrete(ps.Binomial(10, 0.5))
True
>>> ps.is_discrete(ps.Normal())
False
Dispatching on the kind picks the density method that exists:
>>> import polars as pl
>>> def density(dist: ps.DiscreteDistribution | ps.ContinuousDistribution, value: str):
... return dist.pmf(value) if ps.is_discrete(dist) else dist.pdf(value)
>>> pl.DataFrame({"x": [0.0, 1.0]}).select(density(ps.Binomial(10, 0.5), "x"))
shape: (2, 1)
┌──────────┐
│ x │
│ --- │
│ f64 │
╞══════════╡
│ 0.000977 │
│ 0.009766 │
└──────────┘
Source code in polars_stats/distributions/_base.py
is_continuous
¶
is_continuous(obj: object) -> TypeIs[ContinuousDistribution]
Whether obj is a continuous distribution.
The counterpart of is_discrete: the two kinds are disjoint, so
exactly one of the guards holds for any distribution in this package.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
obj
|
object
|
Any object. |
required |
Returns:
| Type | Description |
|---|---|
TypeIs[ContinuousDistribution]
|
|
Examples:
>>> import polars_stats as ps
>>> ps.is_continuous(ps.Normal())
True
>>> ps.is_continuous(ps.Binomial(10, 0.5))
False
The guard narrows, so pdf type checks inside the branch:
>>> import polars as pl
>>> dist = ps.Normal(mu=0.0, sigma=1.0)
>>> if ps.is_continuous(dist):
... print(round(pl.DataFrame({"x": [0.0]}).select(dist.pdf("x")).item(), 6))
0.398942
Source code in polars_stats/distributions/_base.py
Compatibility¶
| Dimension | Values |
|---|---|
| Python | 3.10 to 3.14 (per requires-python), single abi3 wheel |
| Polars | >=1.15 (the pyo3-polars ABI floor) |
| OS | wheels for Linux x86_64/aarch64, macOS arm64/x86_64, Windows x86_64 |
| Runtime dependencies | polars only |