{ } Raw JSON

bundles / scipy latest / scipy / stats / _distribution_infrastructure / make_distribution

function

scipy.stats._distribution_infrastructure:make_distribution

source: /scipy/stats/_distribution_infrastructure.py :3920

Signature

def   make_distribution ( dist )

Summary

Generate a UnivariateDistribution class from a compatible object

Extended Summary

The argument may be an instance of rv_continuous or an instance of another class that satisfies the interface described below.

The returned value is a ContinuousDistribution subclass if the input is an instance of rv_continuous or a DiscreteDistribution subclass if the input is an instance of rv_discrete. Like any subclass of UnivariateDistribution, it must be instantiated (i.e. by passing all shape parameters as keyword arguments) before use. Once instantiated, the resulting object will have the same interface as any other instance of UnivariateDistribution; e.g., scipy.stats.Normal, scipy.stats.Binomial.

Parameters

dist : `rv_continuous`

Instance of rv_continuous, rv_discrete, or an instance of any class with the following attributes:

__make_distribution_version__

__make_distribution_version__

parameters

parameters

support

support

The class must also define a pdf method and may define methods logentropy, entropy, median, mode, logpdf, logcdf, cdf, logccdf, ccdf, ilogcdf, icdf, ilogccdf, iccdf, moment, and sample. If defined, these methods must accept the parameters of the distribution as keyword arguments and also accept any positional-only arguments accepted by the corresponding method of ContinuousDistribution. When multiple parameterizations are defined, these methods must accept all parameters from all parameterizations. The moment method must accept the order and kind arguments by position or keyword, but may return None if a formula is not available for the arguments; in this case, the infrastructure will fall back to a default implementation. The sample method must accept shape by position or keyword, but contrary to the public method of the same name, the argument it receives will be the full shape of the output array - that is, the shape passed to the public method prepended to the broadcasted shape of random variable parameters.

Returns

CustomDistribution : `UnivariateDistribution`

A subclass of UnivariateDistribution corresponding with dist. The initializer requires all shape parameters to be passed as keyword arguments (using the same names as the instance of rv_continuous/rv_discrete).

Notes

The documentation of UnivariateDistribution is not rendered. See below for an example of how to instantiate the class (i.e. pass all shape parameters of dist to the initializer as keyword arguments). Documentation of all methods is identical to that of scipy.stats.Normal. Use help on the returned class or its methods for more information.

Array API Standard Support

make_distribution has experimental support for Python Array API Standard compatible backends in addition to NumPy. Please consider testing these features by setting an environment variable SCIPY_ARRAY_API=1 and providing CuPy, PyTorch, JAX, or Dask arrays as array arguments. The following combinations of backend and device (or other capability) are supported.

====================  ====================  ====================
Library               CPU                   GPU
====================  ====================  ====================
NumPy                 ✅                     n/a                 
CuPy                  n/a                   ⛔                   
PyTorch               ⛔                     ⛔                   
JAX                   ⛔                     ⛔                   
Dask                  ⛔                     n/a                 
====================  ====================  ====================

See dev-arrayapi for more information.

Examples

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
from scipy import special
Create a `ContinuousDistribution` from `scipy.stats.loguniform`.
LogUniform = stats.make_distribution(stats.loguniform)
X = LogUniform(a=1.0, b=3.0)
np.isclose((X + 0.25).median(), stats.loguniform.ppf(0.5, 1, 3, loc=0.25))
X.plot()
sample = X.sample(10000, rng=np.random.default_rng())
plt.hist(sample, density=True, bins=30)
plt.legend(('pdf', 'histogram'))
plt.show()
fig-57e74d9f38892e5a.png
Create a custom distribution.
class MyLogUniform:
    @property
    def __make_distribution_version__(self):
        return "1.16.0"

    @property
    def parameters(self):
        return {'a': {'endpoints': (0, np.inf),
                      'inclusive': (False, False)},
                'b': {'endpoints': ('a', np.inf),
                      'inclusive': (False, False)}}

    @property
    def support(self):
        return {'endpoints': ('a', 'b'), 'inclusive': (True, True)}

    def pdf(self, x, a, b):
        return 1 / (x * (np.log(b)- np.log(a)))
MyLogUniform = stats.make_distribution(MyLogUniform())
Y = MyLogUniform(a=1.0, b=3.0)
np.isclose(Y.cdf(2.), X.cdf(2.))
Create a custom distribution with variable support.
class MyUniformCube:
    @property
    def __make_distribution_version__(self):
        return "1.16.0"

    @property
    def parameters(self):
        return {"a": (-np.inf, np.inf),
                "b": {'endpoints':('a', np.inf), 'inclusive':(True, False)}}

    @property
    def support(self):
        def left(*, a, b):
            return a**3

        def right(*, a, b):
            return b**3
        return (left, right)

    def pdf(self, x, *, a, b):
        return 1 / (3*(b - a)*np.cbrt(x)**2)

    def cdf(self, x, *, a, b):
        return (np.cbrt(x) - a) / (b - a)
MyUniformCube = stats.make_distribution(MyUniformCube())
X = MyUniformCube(a=-2, b=2)
Y = stats.Uniform(a=-2, b=2)**3
X.support()
np.isclose(X.cdf(2.1), Y.cdf(2.1))
Create a custom distribution with multiple parameterizations. Here we create a custom version of the beta distribution that has an alternative parameterization in terms of the mean ``mu`` and a dispersion parameter ``nu``.
class MyBeta:
    @property
    def __make_distribution_version__(self):
        return "1.16.0"

    @property
    def parameters(self):
        return ({"a": (0, np.inf), "b": (0, np.inf)},
                {"mu": (0, 1), "nu": (0, np.inf)})

    def process_parameters(self, a=None, b=None, mu=None, nu=None):
        if a is not None and b is not None:
            nu = a + b
            mu = a / nu
        else:
            a = mu * nu
            b = nu - a
        return dict(a=a, b=b, mu=mu, nu=nu)

    @property
    def support(self):
        return {'endpoints': (0, 1)}

    def pdf(self, x, a, b, mu, nu):
        return special._ufuncs._beta_pdf(x, a, b)

    def cdf(self, x, a, b, mu, nu):
        return special.betainc(a, b, x)
MyBeta = stats.make_distribution(MyBeta())
X = MyBeta(a=2.0, b=2.0)
Y = MyBeta(mu=0.5, nu=4.0)
np.isclose(X.pdf(0.3), Y.pdf(0.3))

Aliases

  • scipy.stats.make_distribution

Referenced by