| |
| |
| from abc import ABC, abstractmethod |
|
|
| class _ProbabilityDistribution(ABC): |
| @abstractmethod |
| def support(self): |
| r"""Support of the random variable |
| |
| The support of a random variable is set of all possible outcomes; |
| i.e., the subset of the domain of argument :math:`x` for which |
| the probability density function :math:`f(x)` is nonzero. |
| |
| This function returns lower and upper bounds of the support. |
| |
| Returns |
| ------- |
| out : tuple of Array |
| The lower and upper bounds of the support. |
| |
| See Also |
| -------- |
| pdf |
| |
| References |
| ---------- |
| .. [1] Support (mathematics), *Wikipedia*, |
| https://en.wikipedia.org/wiki/Support_(mathematics) |
| |
| Notes |
| ----- |
| Suppose a continuous probability distribution has support ``(l, r)``. |
| The following table summarizes the value returned by methods |
| of ``ContinuousDistribution`` for arguments outside the support. |
| |
| +----------------+---------------------+---------------------+ |
| | Method | Value for ``x < l`` | Value for ``x > r`` | |
| +================+=====================+=====================+ |
| | ``pdf(x)`` | 0 | 0 | |
| +----------------+---------------------+---------------------+ |
| | ``logpdf(x)`` | -inf | -inf | |
| +----------------+---------------------+---------------------+ |
| | ``cdf(x)`` | 0 | 1 | |
| +----------------+---------------------+---------------------+ |
| | ``logcdf(x)`` | -inf | 0 | |
| +----------------+---------------------+---------------------+ |
| | ``ccdf(x)`` | 1 | 0 | |
| +----------------+---------------------+---------------------+ |
| | ``logccdf(x)`` | 0 | -inf | |
| +----------------+---------------------+---------------------+ |
| |
| For the ``cdf`` and related methods, the inequality need not be |
| strict; i.e. the tabulated value is returned when the method is |
| evaluated *at* the corresponding boundary. |
| |
| The following table summarizes the value returned by the inverse |
| methods of ``ContinuousDistribution`` for arguments at the boundaries |
| of the domain ``0`` to ``1``. |
| |
| +-------------+-----------+-----------+ |
| | Method | ``x = 0`` | ``x = 1`` | |
| +=============+===========+===========+ |
| | ``icdf(x)`` | ``l`` | ``r`` | |
| +-------------+-----------+-----------+ |
| | ``icdf(x)`` | ``r`` | ``l`` | |
| +-------------+-----------+-----------+ |
| |
| For the inverse log-functions, the same values are returned for |
| for ``x = log(0)`` and ``x = log(1)``. All inverse functions return |
| ``nan`` when evaluated at an argument outside the domain ``0`` to ``1``. |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-0.5, b=0.5) |
| |
| Retrieve the support of the distribution: |
| |
| >>> X.support() |
| (-0.5, 0.5) |
| |
| For a distribution with infinite support, |
| |
| >>> X = stats.Normal() |
| >>> X.support() |
| (-inf, inf) |
| |
| Due to underflow, the numerical value returned by the PDF may be zero |
| even for arguments within the support, even if the true value is |
| nonzero. In such cases, the log-PDF may be useful. |
| |
| >>> X.pdf([-100., 100.]) |
| array([0., 0.]) |
| >>> X.logpdf([-100., 100.]) |
| array([-5000.91893853, -5000.91893853]) |
| |
| Use cases for the log-CDF and related methods are analogous. |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def sample(self, shape, *, method, rng): |
| r"""Random sample from the distribution. |
| |
| Parameters |
| ---------- |
| shape : tuple of ints, default: () |
| The shape of the sample to draw. If the parameters of the distribution |
| underlying the random variable are arrays of shape ``param_shape``, |
| the output array will be of shape ``shape + param_shape``. |
| method : {None, 'formula', 'inverse_transform'} |
| The strategy used to produce the sample. By default (``None``), |
| the infrastructure chooses between the following options, |
| listed in order of precedence. |
| |
| - ``'formula'``: an implementation specific to the distribution |
| - ``'inverse_transform'``: generate a uniformly distributed sample and |
| return the inverse CDF at these arguments. |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a `NotImplementedError`` |
| will be raised. |
| rng : `numpy.random.Generator` or `scipy.stats.QMCEngine`, optional |
| Pseudo- or quasi-random number generator state. When `rng` is None, |
| a new `numpy.random.Generator` is created using entropy from the |
| operating system. Types other than `numpy.random.Generator` and |
| `scipy.stats.QMCEngine` are passed to `numpy.random.default_rng` |
| to instantiate a ``Generator``. |
| |
| If `rng` is an instance of `scipy.stats.QMCEngine` configured to use |
| scrambling and `shape` is not empty, then each slice along the zeroth |
| axis of the result is a "quasi-independent", low-discrepancy sequence; |
| that is, they are distinct sequences that can be treated as statistically |
| independent for most practical purposes. Separate calls to `sample` |
| produce new quasi-independent, low-discrepancy sequences. |
| |
| References |
| ---------- |
| .. [1] Sampling (statistics), *Wikipedia*, |
| https://en.wikipedia.org/wiki/Sampling_(statistics) |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> import numpy as np |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=0., b=1.) |
| |
| Generate a pseudorandom sample: |
| |
| >>> x = X.sample((1000, 1)) |
| >>> octiles = (np.arange(8) + 1) / 8 |
| >>> np.count_nonzero(x <= octiles, axis=0) |
| array([ 148, 263, 387, 516, 636, 751, 865, 1000]) # may vary |
| |
| >>> X = stats.Uniform(a=np.zeros((3, 1)), b=np.ones(2)) |
| >>> X.a.shape, |
| (3, 2) |
| >>> x = X.sample(shape=(5, 4)) |
| >>> x.shape |
| (5, 4, 3, 2) |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def moment(self, order, kind, *, method): |
| r"""Raw, central, or standard moment of positive integer order. |
| |
| In terms of probability density function :math:`f(x)` and support |
| :math:`\chi`, the "raw" moment (about the origin) of order :math:`n` of |
| a random variable :math:`X` is: |
| |
| .. math:: |
| |
| \mu'_n(X) = \int_{\chi} x^n f(x) dx |
| |
| The "central" moment is the raw moment taken about the mean, |
| :math:`\mu = \mu'_1`: |
| |
| .. math:: |
| |
| \mu_n(X) = \int_{\chi} (x - \mu) ^n f(x) dx |
| |
| The "standardized" moment is the central moment normalized by the |
| :math:`n^\text{th}` power of the standard deviation |
| :math:`\sigma = \sqrt{\mu_2}` to produce a scale invariant quantity: |
| |
| .. math:: |
| |
| \tilde{\mu}_n(X) = \frac{\mu_n(X)} |
| {\sigma^n} |
| |
| Parameters |
| ---------- |
| order : int |
| The integer order of the moment; i.e. :math:`n` in the formulae above. |
| kind : {'raw', 'central', 'standardized'} |
| Whether to return the raw (default), central, or standardized moment |
| defined above. |
| method : {None, 'formula', 'general', 'transform', 'normalize', 'quadrature', 'cache'} |
| The strategy used to evaluate the moment. By default (``None``), |
| the infrastructure chooses between the following options, |
| listed in order of precedence. |
| |
| - ``'cache'``: use the value of the moment most recently calculated |
| via another method |
| - ``'formula'``: use a formula for the moment itself |
| - ``'general'``: use a general result that is true for all distributions |
| with finite moments; for instance, the zeroth raw moment is |
| identically 1 |
| - ``'transform'``: transform a raw moment to a central moment or |
| vice versa (see Notes) |
| - ``'normalize'``: normalize a central moment to get a standardized |
| or vice versa |
| - ``'quadrature'``: numerically integrate according to the definition |
| |
| Not all `method` options are available for all orders, kinds, and |
| distributions. If the selected `method` is not available, a |
| ``NotImplementedError`` will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The moment of the random variable of the specified order and kind. |
| |
| See Also |
| -------- |
| pdf |
| mean |
| variance |
| standard_deviation |
| skewness |
| kurtosis |
| |
| Notes |
| ----- |
| Not all distributions have finite moments of all orders; moments of some |
| orders may be undefined or infinite. If a formula for the moment is not |
| specifically implemented for the chosen distribution, SciPy will attempt |
| to compute the moment via a generic method, which may yield a finite |
| result where none exists. This is not a critical bug, but an opportunity |
| for an enhancement. |
| |
| The definition of a raw moment in the summary is specific to the raw moment |
| about the origin. The raw moment about any point :math:`a` is: |
| |
| .. math:: |
| |
| E[(X-a)^n] = \int_{\chi} (x-a)^n f(x) dx |
| |
| In this notation, a raw moment about the origin is :math:`\mu'_n = E[x^n]`, |
| and a central moment is :math:`\mu_n = E[(x-\mu)^n]`, where :math:`\mu` |
| is the first raw moment; i.e. the mean. |
| |
| The ``'transform'`` method takes advantage of the following relationships |
| between moments taken about different points :math:`a` and :math:`b`. |
| |
| .. math:: |
| |
| E[(X-b)^n] = \sum_{i=0}^n E[(X-a)^i] {n \choose i} (a - b)^{n-i} |
| |
| For instance, to transform the raw moment to the central moment, we let |
| :math:`b = \mu` and :math:`a = 0`. |
| |
| The distribution infrastructure provides flexibility for distribution |
| authors to implement separate formulas for raw moments, central moments, |
| and standardized moments of any order. By default, the moment of the |
| desired order and kind is evaluated from the formula if such a formula |
| is available; if not, the infrastructure uses any formulas that are |
| available rather than resorting directly to numerical integration. |
| For instance, if formulas for the first three raw moments are |
| available and the third standardized moments is desired, the |
| infrastructure will evaluate the raw moments and perform the transforms |
| and standardization required. The decision tree is somewhat complex, |
| but the strategy for obtaining a moment of a given order and kind |
| (possibly as an intermediate step due to the recursive nature of the |
| transform formula above) roughly follows this order of priority: |
| |
| #. Use cache (if order of same moment and kind has been calculated) |
| #. Use formula (if available) |
| #. Transform between raw and central moment and/or normalize to convert |
| between central and standardized moments (if efficient) |
| #. Use a generic result true for most distributions (if available) |
| #. Use quadrature |
| |
| References |
| ---------- |
| .. [1] Moment, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Moment_(mathematics) |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> from scipy import stats |
| >>> X = stats.Normal(mu=1., sigma=2.) |
| |
| Evaluate the first raw moment: |
| |
| >>> X.moment(order=1, kind='raw') |
| 1.0 |
| >>> X.moment(order=1, kind='raw') == X.mean() == X.mu |
| True |
| |
| Evaluate the second central moment: |
| |
| >>> X.moment(order=2, kind='central') |
| 4.0 |
| >>> X.moment(order=2, kind='central') == X.variance() == X.sigma**2 |
| True |
| |
| Evaluate the fourth standardized moment: |
| |
| >>> X.moment(order=4, kind='standardized') |
| 3.0 |
| >>> X.moment(order=4, kind='standardized') == X.kurtosis(convention='non-excess') |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def mean(self, *, method): |
| r"""Mean (raw first moment about the origin) |
| |
| Parameters |
| ---------- |
| method : {None, 'formula', 'transform', 'quadrature', 'cache'} |
| Method used to calculate the raw first moment. Not |
| all methods are available for all distributions. See |
| `moment` for details. |
| |
| See Also |
| -------- |
| moment |
| median |
| mode |
| |
| References |
| ---------- |
| .. [1] Mean, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Mean#Mean_of_a_probability_distribution |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> from scipy import stats |
| >>> X = stats.Normal(mu=1., sigma=2.) |
| |
| Evaluate the variance: |
| |
| >>> X.mean() |
| 1.0 |
| >>> X.mean() == X.moment(order=1, kind='raw') == X.mu |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def median(self, *, method): |
| r"""Median (50th percentil) |
| |
| If a continuous random variable :math:`X` has probability :math:`0.5` of |
| taking on a value less than :math:`m`, then :math:`m` is the median. |
| That is, the median is the value :math:`m` for which: |
| |
| .. math:: |
| |
| P(X ≤ m) = 0.5 = P(X ≥ m) |
| |
| Parameters |
| ---------- |
| method : {None, 'formula', 'icdf'} |
| The strategy used to evaluate the median. |
| By default (``None``), the infrastructure chooses between the |
| following options, listed in order of precedence. |
| |
| - ``'formula'``: use a formula for the median |
| - ``'icdf'``: evaluate the inverse CDF of 0.5 |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The median |
| |
| See Also |
| -------- |
| mean |
| mode |
| icdf |
| |
| References |
| ---------- |
| .. [1] Median, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Median#Probability_distributions |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=0., b=10.) |
| |
| Compute the median: |
| |
| >>> X.median() |
| np.float64(5.0) |
| >>> X.median() == X.icdf(0.5) == X.iccdf(0.5) |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def mode(self, *, method): |
| r"""Mode (most likely value) |
| |
| Informally, the mode is a value that a random variable has the highest |
| probability (density) of assuming. That is, the mode is the element of |
| the support :math:`\chi` that maximizes the probability density |
| function :math:`f(x)`: |
| |
| .. math:: |
| |
| \text{mode} = \arg\max_{x \in \chi} f(x) |
| |
| Parameters |
| ---------- |
| method : {None, 'formula', 'optimization'} |
| The strategy used to evaluate the mode. |
| By default (``None``), the infrastructure chooses between the |
| following options, listed in order of precedence. |
| |
| - ``'formula'``: use a formula for the median |
| - ``'optimization'``: numerically maximize the PDF |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The mode |
| |
| See Also |
| -------- |
| mean |
| median |
| pdf |
| |
| Notes |
| ----- |
| For some distributions |
| |
| #. the mode is not unique (e.g. the uniform distribution); |
| #. the PDF has one or more singularities, and it is debateable whether |
| a singularity is considered to be in the domain and called the mode |
| (e.g. the gamma distribution with shape parameter less than 1); and/or |
| #. the probability density function may have one or more local maxima |
| that are not a global maximum (e.g. mixture distributions). |
| |
| In such cases, `mode` will |
| |
| #. return a single value, |
| #. consider the mode to occur at a singularity, and/or |
| #. return a local maximum which may or may not be a global maximum. |
| |
| If a formula for the mode is not specifically implemented for the |
| chosen distribution, SciPy will attempt to compute the mode |
| numerically, which may not meet the user's preferred definition of a |
| mode. In such cases, the user is encouraged to subclass the |
| distribution and override ``mode``. |
| |
| References |
| ---------- |
| .. [1] Mode (statistics), *Wikipedia*, |
| https://en.wikipedia.org/wiki/Mode_(statistics) |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> from scipy import stats |
| >>> X = stats.Normal(mu=1., sigma=2.) |
| |
| Evaluate the mode: |
| |
| >>> X.mode() |
| 1.0 |
| |
| If the mode is not uniquely defined, ``mode`` nonetheless returns a |
| single value. |
| |
| >>> X = stats.Uniform(a=0., b=1.) |
| >>> X.mode() |
| 0.5 |
| |
| If this choice does not satisfy your requirements, subclass the |
| distribution and override ``mode``: |
| |
| >>> class BetterUniform(stats.Uniform): |
| ... def mode(self): |
| ... return self.b |
| >>> X = BetterUniform(a=0., b=1.) |
| >>> X.mode() |
| 1.0 |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def variance(self, *, method): |
| r"""Variance (central second moment) |
| |
| Parameters |
| ---------- |
| method : {None, 'formula', 'transform', 'normalize', 'quadrature', 'cache'} |
| Method used to calculate the central second moment. Not |
| all methods are available for all distributions. See |
| `moment` for details. |
| |
| See Also |
| -------- |
| moment |
| standard_deviation |
| mean |
| |
| References |
| ---------- |
| .. [1] Variance, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Variance#Absolutely_continuous_random_variable |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> from scipy import stats |
| >>> X = stats.Normal(mu=1., sigma=2.) |
| |
| Evaluate the variance: |
| |
| >>> X.variance() |
| 4.0 |
| >>> X.variance() == X.moment(order=2, kind='central') == X.sigma**2 |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def standard_deviation(self, *, method): |
| r"""Standard deviation (square root of the second central moment) |
| |
| Parameters |
| ---------- |
| method : {None, 'formula', 'transform', 'normalize', 'quadrature', 'cache'} |
| Method used to calculate the central second moment. Not |
| all methods are available for all distributions. See |
| `moment` for details. |
| |
| See Also |
| -------- |
| variance |
| mean |
| moment |
| |
| References |
| ---------- |
| .. [1] Standard deviation, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Standard_deviation#Definition_of_population_values |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> from scipy import stats |
| >>> X = stats.Normal(mu=1., sigma=2.) |
| |
| Evaluate the standard deviation: |
| |
| >>> X.standard_deviation() |
| 2.0 |
| >>> X.standard_deviation() == X.moment(order=2, kind='central')**0.5 == X.sigma |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def skewness(self, *, method): |
| r"""Skewness (standardized third moment) |
| |
| Parameters |
| ---------- |
| method : {None, 'formula', 'general', 'transform', 'normalize', 'cache'} |
| Method used to calculate the standardized third moment. Not |
| all methods are available for all distributions. See |
| `moment` for details. |
| |
| See Also |
| -------- |
| moment |
| mean |
| variance |
| |
| References |
| ---------- |
| .. [1] Skewness, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Skewness |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> from scipy import stats |
| >>> X = stats.Normal(mu=1., sigma=2.) |
| |
| Evaluate the skewness: |
| |
| >>> X.skewness() |
| 0.0 |
| >>> X.skewness() == X.moment(order=3, kind='standardized') |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def kurtosis(self, *, method): |
| r"""Kurtosis (standardized fourth moment) |
| |
| By default, this is the standardized fourth moment, also known as the |
| "non-excess" or "Pearson" kurtosis (e.g. the kurtosis of the normal |
| distribution is 3). The "excess" or "Fisher" kurtosis (the standardized |
| fourth moment minus 3) is available via the `convention` parameter. |
| |
| Parameters |
| ---------- |
| method : {None, 'formula', 'general', 'transform', 'normalize', 'cache'} |
| Method used to calculate the standardized fourth moment. Not |
| all methods are available for all distributions. See |
| `moment` for details. |
| convention : {'non-excess', 'excess'} |
| Two distinct conventions are available: |
| |
| - ``'non-excess'``: the standardized fourth moment (Pearson's kurtosis) |
| - ``'excess'``: the standardized fourth moment minus 3 (Fisher's kurtosis) |
| |
| The default is ``'non-excess'``. |
| |
| See Also |
| -------- |
| moment |
| mean |
| variance |
| |
| References |
| ---------- |
| .. [1] Kurtosis, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Kurtosis |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> from scipy import stats |
| >>> X = stats.Normal(mu=1., sigma=2.) |
| |
| Evaluate the kurtosis: |
| |
| >>> X.kurtosis() |
| 3.0 |
| >>> (X.kurtosis() |
| ... == X.kurtosis(convention='excess') + 3. |
| ... == X.moment(order=4, kind='standardized')) |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def pdf(self, x, /, *, method): |
| r"""Probability density function |
| |
| The probability density function ("PDF"), denoted :math:`f(x)`, is the |
| probability *per unit length* that the random variable will assume the |
| value :math:`x`. Mathematically, it can be defined as the derivative |
| of the cumulative distribution function :math:`F(x)`: |
| |
| .. math:: |
| |
| f(x) = \frac{d}{dx} F(x) |
| |
| `pdf` accepts `x` for :math:`x`. |
| |
| Parameters |
| ---------- |
| x : array_like |
| The argument of the PDF. |
| method : {None, 'formula', 'logexp'} |
| The strategy used to evaluate the PDF. By default (``None``), the |
| infrastructure chooses between the following options, listed in |
| order of precedence. |
| |
| - ``'formula'``: use a formula for the PDF itself |
| - ``'logexp'``: evaluate the log-PDF and exponentiate |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The PDF evaluated at the argument `x`. |
| |
| See Also |
| -------- |
| cdf |
| logpdf |
| |
| Notes |
| ----- |
| Suppose a continuous probability distribution has support :math:`[l, r]`. |
| By definition of the support, the PDF evaluates to its minimum value |
| of :math:`0` outside the support; i.e. for :math:`x < l` or |
| :math:`x > r`. The maximum of the PDF may be less than or greater than |
| :math:`1`; since the valus is a probability *density*, only its integral |
| over the support must equal :math:`1`. |
| |
| References |
| ---------- |
| .. [1] Probability density function, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Probability_density_function |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-1., b=1.) |
| |
| Evaluate the PDF at the desired argument: |
| |
| >>> X.pdf(0.25) |
| 0.5 |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def logpdf(self, x, /, *, method): |
| r"""Log of the probability density function |
| |
| The probability density function ("PDF"), denoted :math:`f(x)`, is the |
| probability *per unit length* that the random variable will assume the |
| value :math:`x`. Mathematically, it can be defined as the derivative |
| of the cumulative distribution function :math:`F(x)`: |
| |
| .. math:: |
| |
| f(x) = \frac{d}{dx} F(x) |
| |
| `logpdf` computes the logarithm of the probability density function |
| ("log-PDF"), :math:`\log(f(x))`, but it may be numerically favorable |
| compared to the naive implementation (computing :math:`f(x)` and |
| taking the logarithm). |
| |
| `logpdf` accepts `x` for :math:`x`. |
| |
| Parameters |
| ---------- |
| x : array_like |
| The argument of the log-PDF. |
| method : {None, 'formula', 'logexp'} |
| The strategy used to evaluate the log-PDF. By default (``None``), the |
| infrastructure chooses between the following options, listed in order |
| of precedence. |
| |
| - ``'formula'``: use a formula for the log-PDF itself |
| - ``'logexp'``: evaluate the PDF and takes its logarithm |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The log-PDF evaluated at the argument `x`. |
| |
| See Also |
| -------- |
| pdf |
| logcdf |
| |
| Notes |
| ----- |
| Suppose a continuous probability distribution has support :math:`[l, r]`. |
| By definition of the support, the log-PDF evaluates to its minimum value |
| of :math:`-\infty` (i.e. :math:`\log(0)`) outside the support; i.e. for |
| :math:`x < l` or :math:`x > r`. The maximum of the log-PDF may be less |
| than or greater than :math:`\log(1) = 0` because the maximum of the PDF |
| can be any positive real. |
| |
| For distributions with infinite support, it is common for `pdf` to return |
| a value of ``0`` when the argument is theoretically within the support; |
| this can occur because the true value of the PDF is too small to be |
| represented by the chosen dtype. The log-PDF, however, will often be finite |
| (not ``-inf``) over a much larger domain. Consequently, it may be preferred |
| to work with the logarithms of probabilities and probability densities to |
| avoid underflow. |
| |
| References |
| ---------- |
| .. [1] Probability density function, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Probability_density_function |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> import numpy as np |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-1.0, b=1.0) |
| |
| Evaluate the log-PDF at the desired argument: |
| |
| >>> X.logpdf(0.5) |
| -0.6931471805599453 |
| >>> np.allclose(X.logpdf(0.5), np.log(X.pdf(0.5))) |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def cdf(self, x, y, /, *, method): |
| r"""Cumulative distribution function |
| |
| The cumulative distribution function ("CDF"), denoted :math:`F(x)`, is |
| the probability the random variable :math:`X` will assume a value |
| less than or equal to :math:`x`: |
| |
| .. math:: |
| |
| F(x) = P(X ≤ x) |
| |
| A two-argument variant of this function is also defined as the |
| probability the random variable :math:`X` will assume a value between |
| :math:`x` and :math:`y`. |
| |
| .. math:: |
| |
| F(x, y) = P(x ≤ X ≤ y) |
| |
| `cdf` accepts `x` for :math:`x` and `y` for :math:`y`. |
| |
| Parameters |
| ---------- |
| x, y : array_like |
| The arguments of the CDF. `x` is required; `y` is optional. |
| method : {None, 'formula', 'logexp', 'complement', 'quadrature', 'subtraction'} |
| The strategy used to evaluate the CDF. |
| By default (``None``), the one-argument form of the function |
| chooses between the following options, listed in order of precedence. |
| |
| - ``'formula'``: use a formula for the CDF itself |
| - ``'logexp'``: evaluate the log-CDF and exponentiate |
| - ``'complement'``: evaluate the CCDF and take the complement |
| - ``'quadrature'``: numerically integrate the PDF |
| |
| In place of ``'complement'``, the two-argument form accepts: |
| |
| - ``'subtraction'``: compute the CDF at each argument and take |
| the difference. |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The CDF evaluated at the provided argument(s). |
| |
| See Also |
| -------- |
| logcdf |
| ccdf |
| |
| Notes |
| ----- |
| Suppose a continuous probability distribution has support :math:`[l, r]`. |
| The CDF :math:`F(x)` is related to the probability density function |
| :math:`f(x)` by: |
| |
| .. math:: |
| |
| F(x) = \int_l^x f(u) du |
| |
| The two argument version is: |
| |
| .. math:: |
| |
| F(x, y) = \int_x^y f(u) du = F(y) - F(x) |
| |
| The CDF evaluates to its minimum value of :math:`0` for :math:`x ≤ l` |
| and its maximum value of :math:`1` for :math:`x ≥ r`. |
| |
| The CDF is also known simply as the "distribution function". |
| |
| References |
| ---------- |
| .. [1] Cumulative distribution function, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Cumulative_distribution_function |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-0.5, b=0.5) |
| |
| Evaluate the CDF at the desired argument: |
| |
| >>> X.cdf(0.25) |
| 0.75 |
| |
| Evaluate the cumulative probability between two arguments: |
| |
| >>> X.cdf(-0.25, 0.25) == X.cdf(0.25) - X.cdf(-0.25) |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def icdf(self, p, /, *, method): |
| r"""Inverse of the cumulative distribution function. |
| |
| The inverse of the cumulative distribution function ("inverse CDF"), |
| denoted :math:`F^{-1}(p)`, is the argument :math:`x` for which the |
| cumulative distribution function :math:`F(x)` evaluates to :math:`p`. |
| |
| .. math:: |
| |
| F^{-1}(p) = x \quad \text{s.t.} \quad F(x) = p |
| |
| `icdf` accepts `p` for :math:`p \in [0, 1]`. |
| |
| Parameters |
| ---------- |
| p : array_like |
| The argument of the inverse CDF. |
| method : {None, 'formula', 'complement', 'inversion'} |
| The strategy used to evaluate the inverse CDF. |
| By default (``None``), the infrastructure chooses between the |
| following options, listed in order of precedence. |
| |
| - ``'formula'``: use a formula for the inverse CDF itself |
| - ``'complement'``: evaluate the inverse CCDF at the |
| complement of `p` |
| - ``'inversion'``: solve numerically for the argument at which the |
| CDF is equal to `p` |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The inverse CDF evaluated at the provided argument. |
| |
| See Also |
| -------- |
| cdf |
| ilogcdf |
| |
| Notes |
| ----- |
| Suppose a continuous probability distribution has support :math:`[l, r]`. The |
| inverse CDF returns its minimum value of :math:`l` at :math:`p = 0` |
| and its maximum value of :math:`r` at :math:`p = 1`. Because the CDF |
| has range :math:`[0, 1]`, the inverse CDF is only defined on the |
| domain :math:`[0, 1]`; for :math:`p < 0` and :math:`p > 1`, `icdf` |
| returns ``nan``. |
| |
| The inverse CDF is also known as the quantile function, percentile function, |
| and percent-point function. |
| |
| References |
| ---------- |
| .. [1] Quantile function, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Quantile_function |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> import numpy as np |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-0.5, b=0.5) |
| |
| Evaluate the inverse CDF at the desired argument: |
| |
| >>> X.icdf(0.25) |
| -0.25 |
| >>> np.allclose(X.cdf(X.icdf(0.25)), 0.25) |
| True |
| |
| This function returns NaN when the argument is outside the domain. |
| |
| >>> X.icdf([-0.1, 0, 1, 1.1]) |
| array([ nan, -0.5, 0.5, nan]) |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def ccdf(self, x, y, /, *, method): |
| r"""Complementary cumulative distribution function |
| |
| The complementary cumulative distribution function ("CCDF"), denoted |
| :math:`G(x)`, is the complement of the cumulative distribution function |
| :math:`F(x)`; i.e., probability the random variable :math:`X` will |
| assume a value greater than :math:`x`: |
| |
| .. math:: |
| |
| G(x) = 1 - F(x) = P(X > x) |
| |
| A two-argument variant of this function is: |
| |
| .. math:: |
| |
| G(x, y) = 1 - F(x, y) = P(X < x \text{ or } X > y) |
| |
| `ccdf` accepts `x` for :math:`x` and `y` for :math:`y`. |
| |
| Parameters |
| ---------- |
| x, y : array_like |
| The arguments of the CCDF. `x` is required; `y` is optional. |
| method : {None, 'formula', 'logexp', 'complement', 'quadrature', 'addition'} |
| The strategy used to evaluate the CCDF. |
| By default (``None``), the infrastructure chooses between the |
| following options, listed in order of precedence. |
| |
| - ``'formula'``: use a formula for the CCDF itself |
| - ``'logexp'``: evaluate the log-CCDF and exponentiate |
| - ``'complement'``: evaluate the CDF and take the complement |
| - ``'quadrature'``: numerically integrate the PDF |
| |
| The two-argument form chooses between: |
| |
| - ``'formula'``: use a formula for the CCDF itself |
| - ``'addition'``: compute the CDF at `x` and the CCDF at `y`, then add |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The CCDF evaluated at the provided argument(s). |
| |
| See Also |
| -------- |
| cdf |
| logccdf |
| |
| Notes |
| ----- |
| Suppose a continuous probability distribution has support :math:`[l, r]`. |
| The CCDF :math:`G(x)` is related to the probability density function |
| :math:`f(x)` by: |
| |
| .. math:: |
| |
| G(x) = \int_x^r f(u) du |
| |
| The two argument version is: |
| |
| .. math:: |
| |
| G(x, y) = \int_l^x f(u) du + \int_y^r f(u) du |
| |
| The CCDF returns its minimum value of :math:`0` for :math:`x ≥ r` |
| and its maximum value of :math:`1` for :math:`x ≤ l`. |
| |
| The CCDF is also known as the "survival function". |
| |
| References |
| ---------- |
| .. [1] Cumulative distribution function, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Cumulative_distribution_function#Derived_functions |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> import numpy as np |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-0.5, b=0.5) |
| |
| Evaluate the CCDF at the desired argument: |
| |
| >>> X.ccdf(0.25) |
| 0.25 |
| >>> np.allclose(X.ccdf(0.25), 1-X.cdf(0.25)) |
| True |
| |
| Evaluate the complement of the cumulative probability between two arguments: |
| |
| >>> X.ccdf(-0.25, 0.25) == X.cdf(-0.25) + X.ccdf(0.25) |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def iccdf(self, p, /, *, method): |
| r"""Inverse complementary cumulative distribution function. |
| |
| The inverse complementary cumulative distribution function ("inverse CCDF"), |
| denoted :math:`G^{-1}(p)`, is the argument :math:`x` for which the |
| complementary cumulative distribution function :math:`G(x)` evaluates to |
| :math:`p`. |
| |
| .. math:: |
| |
| G^{-1}(p) = x \quad \text{s.t.} \quad G(x) = p |
| |
| `iccdf` accepts `p` for :math:`p \in [0, 1]`. |
| |
| Parameters |
| ---------- |
| p : array_like |
| The argument of the inverse CCDF. |
| method : {None, 'formula', 'complement', 'inversion'} |
| The strategy used to evaluate the inverse CCDF. |
| By default (``None``), the infrastructure chooses between the |
| following options, listed in order of precedence. |
| |
| - ``'formula'``: use a formula for the inverse CCDF itself |
| - ``'complement'``: evaluate the inverse CDF at the |
| complement of `p` |
| - ``'inversion'``: solve numerically for the argument at which the |
| CCDF is equal to `p` |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The inverse CCDF evaluated at the provided argument. |
| |
| Notes |
| ----- |
| Suppose a continuous probability distribution has support :math:`[l, r]`. The |
| inverse CCDF returns its minimum value of :math:`l` at :math:`p = 1` |
| and its maximum value of :math:`r` at :math:`p = 0`. Because the CCDF |
| has range :math:`[0, 1]`, the inverse CCDF is only defined on the |
| domain :math:`[0, 1]`; for :math:`p < 0` and :math:`p > 1`, ``iccdf`` |
| returns ``nan``. |
| |
| See Also |
| -------- |
| icdf |
| ilogccdf |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> import numpy as np |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-0.5, b=0.5) |
| |
| Evaluate the inverse CCDF at the desired argument: |
| |
| >>> X.iccdf(0.25) |
| 0.25 |
| >>> np.allclose(X.iccdf(0.25), X.icdf(1-0.25)) |
| True |
| |
| This function returns NaN when the argument is outside the domain. |
| |
| >>> X.iccdf([-0.1, 0, 1, 1.1]) |
| array([ nan, 0.5, -0.5, nan]) |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def logcdf(self, x, y, /, *, method): |
| r"""Log of the cumulative distribution function |
| |
| The cumulative distribution function ("CDF"), denoted :math:`F(x)`, is |
| the probability the random variable :math:`X` will assume a value |
| less than or equal to :math:`x`: |
| |
| .. math:: |
| |
| F(x) = P(X ≤ x) |
| |
| A two-argument variant of this function is also defined as the |
| probability the random variable :math:`X` will assume a value between |
| :math:`x` and :math:`y`. |
| |
| .. math:: |
| |
| F(x, y) = P(x ≤ X ≤ y) |
| |
| `logcdf` computes the logarithm of the cumulative distribution function |
| ("log-CDF"), :math:`\log(F(x))`/:math:`\log(F(x, y))`, but it may be |
| numerically favorable compared to the naive implementation (computing |
| the CDF and taking the logarithm). |
| |
| `logcdf` accepts `x` for :math:`x` and `y` for :math:`y`. |
| |
| Parameters |
| ---------- |
| x, y : array_like |
| The arguments of the log-CDF. `x` is required; `y` is optional. |
| method : {None, 'formula', 'logexp', 'complement', 'quadrature', 'subtraction'} |
| The strategy used to evaluate the log-CDF. |
| By default (``None``), the one-argument form of the function |
| chooses between the following options, listed in order of precedence. |
| |
| - ``'formula'``: use a formula for the log-CDF itself |
| - ``'logexp'``: evaluate the CDF and take the logarithm |
| - ``'complement'``: evaluate the log-CCDF and take the |
| logarithmic complement (see Notes) |
| - ``'quadrature'``: numerically log-integrate the log-PDF |
| |
| In place of ``'complement'``, the two-argument form accepts: |
| |
| - ``'subtraction'``: compute the log-CDF at each argument and take |
| the logarithmic difference (see Notes) |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The log-CDF evaluated at the provided argument(s). |
| |
| See Also |
| -------- |
| cdf |
| logccdf |
| |
| Notes |
| ----- |
| Suppose a continuous probability distribution has support :math:`[l, r]`. |
| The log-CDF evaluates to its minimum value of :math:`\log(0) = -\infty` |
| for :math:`x ≤ l` and its maximum value of :math:`\log(1) = 0` for |
| :math:`x ≥ r`. |
| |
| For distributions with infinite support, it is common for |
| `cdf` to return a value of ``0`` when the argument |
| is theoretically within the support; this can occur because the true value |
| of the CDF is too small to be represented by the chosen dtype. `logcdf`, |
| however, will often return a finite (not ``-inf``) result over a much larger |
| domain. Similarly, `logcdf` may provided a strictly negative result with |
| arguments for which `cdf` would return ``1.0``. Consequently, it may be |
| preferred to work with the logarithms of probabilities to avoid underflow |
| and related limitations of floating point numbers. |
| |
| The "logarithmic complement" of a number :math:`z` is mathematically |
| equivalent to :math:`\log(1-\exp(z))`, but it is computed to avoid loss |
| of precision when :math:`\exp(z)` is nearly :math:`0` or :math:`1`. |
| Similarly, the term "logarithmic difference" of :math:`w` and :math:`z` |
| is used here to mean :math:`\log(\exp(w)-\exp(z))`. |
| |
| If ``y < x``, the CDF is negative, and therefore the log-CCDF |
| is complex with imaginary part :math:`\pi`. For |
| consistency, the result of this function always has complex dtype |
| when `y` is provided, regardless of the value of the imaginary part. |
| |
| References |
| ---------- |
| .. [1] Cumulative distribution function, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Cumulative_distribution_function |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> import numpy as np |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-0.5, b=0.5) |
| |
| Evaluate the log-CDF at the desired argument: |
| |
| >>> X.logcdf(0.25) |
| -0.287682072451781 |
| >>> np.allclose(X.logcdf(0.), np.log(X.cdf(0.))) |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def ilogcdf(self, logp, /, *, method): |
| r"""Inverse of the logarithm of the cumulative distribution function. |
| |
| The inverse of the logarithm of the cumulative distribution function |
| ("inverse log-CDF") is the argument :math:`x` for which the logarithm |
| of the cumulative distribution function :math:`\log(F(x))` evaluates |
| to :math:`\log(p)`. |
| |
| Mathematically, it is equivalent to :math:`F^{-1}(\exp(y))`, where |
| :math:`y = \log(p)`, but it may be numerically favorable compared to |
| the naive implementation (computing :math:`p = \exp(y)`, then |
| :math:`F^{-1}(p)`). |
| |
| `ilogcdf` accepts `logp` for :math:`\log(p) ≤ 0`. |
| |
| Parameters |
| ---------- |
| logp : array_like |
| The argument of the inverse log-CDF. |
| method : {None, 'formula', 'complement', 'inversion'} |
| The strategy used to evaluate the inverse log-CDF. |
| By default (``None``), the infrastructure chooses between the |
| following options, listed in order of precedence. |
| |
| - ``'formula'``: use a formula for the inverse log-CDF itself |
| - ``'complement'``: evaluate the inverse log-CCDF at the |
| logarithmic complement of `logp` (see Notes) |
| - ``'inversion'``: solve numerically for the argument at which the |
| log-CDF is equal to `logp` |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The inverse log-CDF evaluated at the provided argument. |
| |
| See Also |
| -------- |
| icdf |
| logcdf |
| |
| Notes |
| ----- |
| Suppose a continuous probability distribution has support :math:`[l, r]`. |
| The inverse log-CDF returns its minimum value of :math:`l` at |
| :math:`\log(p) = \log(0) = -\infty` and its maximum value of :math:`r` at |
| :math:`\log(p) = \log(1) = 0`. Because the log-CDF has range |
| :math:`[-\infty, 0]`, the inverse log-CDF is only defined on the |
| negative reals; for :math:`\log(p) > 0`, `ilogcdf` returns ``nan``. |
| |
| Occasionally, it is needed to find the argument of the CDF for which |
| the resulting probability is very close to ``0`` or ``1`` - too close to |
| represent accurately with floating point arithmetic. In many cases, |
| however, the *logarithm* of this resulting probability may be |
| represented in floating point arithmetic, in which case this function |
| may be used to find the argument of the CDF for which the *logarithm* |
| of the resulting probability is :math:`y = \log(p)`. |
| |
| The "logarithmic complement" of a number :math:`z` is mathematically |
| equivalent to :math:`\log(1-\exp(z))`, but it is computed to avoid loss |
| of precision when :math:`\exp(z)` is nearly :math:`0` or :math:`1`. |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> import numpy as np |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-0.5, b=0.5) |
| |
| Evaluate the inverse log-CDF at the desired argument: |
| |
| >>> X.ilogcdf(-0.25) |
| 0.2788007830714034 |
| >>> np.allclose(X.ilogcdf(-0.25), X.icdf(np.exp(-0.25))) |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def logccdf(self, x, y, /, *, method): |
| r"""Log of the complementary cumulative distribution function |
| |
| The complementary cumulative distribution function ("CCDF"), denoted |
| :math:`G(x)` is the complement of the cumulative distribution function |
| :math:`F(x)`; i.e., probability the random variable :math:`X` will |
| assume a value greater than :math:`x`: |
| |
| .. math:: |
| |
| G(x) = 1 - F(x) = P(X > x) |
| |
| A two-argument variant of this function is: |
| |
| .. math:: |
| |
| G(x, y) = 1 - F(x, y) = P(X < x \quad \text{or} \quad X > y) |
| |
| `logccdf` computes the logarithm of the complementary cumulative |
| distribution function ("log-CCDF"), :math:`\log(G(x))`/:math:`\log(G(x, y))`, |
| but it may be numerically favorable compared to the naive implementation |
| (computing the CDF and taking the logarithm). |
| |
| `logccdf` accepts `x` for :math:`x` and `y` for :math:`y`. |
| |
| Parameters |
| ---------- |
| x, y : array_like |
| The arguments of the log-CCDF. `x` is required; `y` is optional. |
| method : {None, 'formula', 'logexp', 'complement', 'quadrature', 'addition'} |
| The strategy used to evaluate the log-CCDF. |
| By default (``None``), the one-argument form of the function |
| chooses between the following options, listed in order of precedence. |
| |
| - ``'formula'``: use a formula for the log CCDF itself |
| - ``'logexp'``: evaluate the CCDF and take the logarithm |
| - ``'complement'``: evaluate the log-CDF and take the |
| logarithmic complement (see Notes) |
| - ``'quadrature'``: numerically log-integrate the log-PDF |
| |
| The two-argument form chooses between: |
| |
| - ``'formula'``: use a formula for the log CCDF itself |
| - ``'addition'``: compute the log-CDF at `x` and the log-CCDF at `y`, |
| then take the logarithmic sum (see Notes) |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The log-CCDF evaluated at the provided argument(s). |
| |
| See Also |
| -------- |
| ccdf |
| logcdf |
| |
| Notes |
| ----- |
| Suppose a continuous probability distribution has support :math:`[l, r]`. |
| The log-CCDF returns its minimum value of :math:`\log(0)=-\infty` for |
| :math:`x ≥ r` and its maximum value of :math:`\log(1) = 0` for |
| :math:`x ≤ l`. |
| |
| For distributions with infinite support, it is common for |
| `ccdf` to return a value of ``0`` when the argument |
| is theoretically within the support; this can occur because the true value |
| of the CCDF is too small to be represented by the chosen dtype. The log |
| of the CCDF, however, will often be finite (not ``-inf``) over a much larger |
| domain. Similarly, `logccdf` may provided a strictly negative result with |
| arguments for which `ccdf` would return ``1.0``. Consequently, it may be |
| preferred to work with the logarithms of probabilities to avoid underflow |
| and related limitations of floating point numbers. |
| |
| The "logarithmic complement" of a number :math:`z` is mathematically |
| equivalent to :math:`\log(1-\exp(z))`, but it is computed to avoid loss |
| of precision when :math:`\exp(z)` is nearly :math:`0` or :math:`1`. |
| Similarly, the term "logarithmic sum" of :math:`w` and :math:`z` |
| is used here to mean the :math:`\log(\exp(w)+\exp(z))`, AKA |
| :math:`\text{LogSumExp}(w, z)`. |
| |
| References |
| ---------- |
| .. [1] Cumulative distribution function, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Cumulative_distribution_function#Derived_functions |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> import numpy as np |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-0.5, b=0.5) |
| |
| Evaluate the log-CCDF at the desired argument: |
| |
| >>> X.logccdf(0.25) |
| -1.3862943611198906 |
| >>> np.allclose(X.logccdf(0.), np.log(X.ccdf(0.))) |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def ilogccdf(self, logp, /, *, method): |
| r"""Inverse of the log of the complementary cumulative distribution function. |
| |
| The inverse of the logarithm of the complementary cumulative distribution |
| function ("inverse log-CCDF") is the argument :math:`x` for which the logarithm |
| of the complementary cumulative distribution function :math:`\log(G(x))` |
| evaluates to :math:`\log(p)`. |
| |
| Mathematically, it is equivalent to :math:`G^{-1}(\exp(y))`, where |
| :math:`y = \log(p)`, but it may be numerically favorable compared to the naive |
| implementation (computing :math:`p = \exp(y)`, then :math:`G^{-1}(p)`). |
| |
| `ilogccdf` accepts `logp` for :math:`\log(p) ≤ 0`. |
| |
| Parameters |
| ---------- |
| x : array_like |
| The argument of the inverse log-CCDF. |
| method : {None, 'formula', 'complement', 'inversion'} |
| The strategy used to evaluate the inverse log-CCDF. |
| By default (``None``), the infrastructure chooses between the |
| following options, listed in order of precedence. |
| |
| - ``'formula'``: use a formula for the inverse log-CCDF itself |
| - ``'complement'``: evaluate the inverse log-CDF at the |
| logarithmic complement of `x` (see Notes) |
| - ``'inversion'``: solve numerically for the argument at which the |
| log-CCDF is equal to `x` |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The inverse log-CCDF evaluated at the provided argument. |
| |
| Notes |
| ----- |
| Suppose a continuous probability distribution has support :math:`[l, r]`. The |
| inverse log-CCDF returns its minimum value of :math:`l` at |
| :math:`\log(p) = \log(1) = 0` and its maximum value of :math:`r` at |
| :math:`\log(p) = \log(0) = -\infty`. Because the log-CCDF has range |
| :math:`[-\infty, 0]`, the inverse log-CDF is only defined on the |
| negative reals; for :math:`\log(p) > 0`, `ilogccdf` returns ``nan``. |
| |
| Occasionally, it is needed to find the argument of the CCDF for which |
| the resulting probability is very close to ``0`` or ``1`` - too close to |
| represent accurately with floating point arithmetic. In many cases, |
| however, the *logarithm* of this resulting probability may be |
| represented in floating point arithmetic, in which case this function |
| may be used to find the argument of the CCDF for which the *logarithm* |
| of the resulting probability is `y = \log(p)`. |
| |
| The "logarithmic complement" of a number :math:`z` is mathematically |
| equivalent to :math:`\log(1-\exp(z))`, but it is computed to avoid loss |
| of precision when :math:`\exp(z)` is nearly :math:`0` or :math:`1`. |
| |
| See Also |
| -------- |
| iccdf |
| ilogccdf |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> import numpy as np |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-0.5, b=0.5) |
| |
| Evaluate the inverse log-CCDF at the desired argument: |
| |
| >>> X.ilogccdf(-0.25) |
| -0.2788007830714034 |
| >>> np.allclose(X.ilogccdf(-0.25), X.iccdf(np.exp(-0.25))) |
| True |
| |
| """ |
| raise NotImplementedError() |
|
|
| @abstractmethod |
| def logentropy(self, *, method): |
| r"""Logarithm of the differential entropy |
| |
| In terms of probability density function :math:`f(x)` and support |
| :math:`\chi`, the differential entropy (or simply "entropy") of a random |
| variable :math:`X` is: |
| |
| .. math:: |
| |
| h(X) = - \int_{\chi} f(x) \log f(x) dx |
| |
| `logentropy` computes the logarithm of the differential entropy |
| ("log-entropy"), :math:`log(h(X))`, but it may be numerically favorable |
| compared to the naive implementation (computing :math:`h(X)` then |
| taking the logarithm). |
| |
| Parameters |
| ---------- |
| method : {None, 'formula', 'logexp', 'quadrature} |
| The strategy used to evaluate the log-entropy. By default |
| (``None``), the infrastructure chooses between the following options, |
| listed in order of precedence. |
| |
| - ``'formula'``: use a formula for the log-entropy itself |
| - ``'logexp'``: evaluate the entropy and take the logarithm |
| - ``'quadrature'``: numerically log-integrate the logarithm of the |
| entropy integrand |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The log-entropy. |
| |
| See Also |
| -------- |
| entropy |
| logpdf |
| |
| Notes |
| ----- |
| If the entropy of a distribution is negative, then the log-entropy |
| is complex with imaginary part :math:`\pi`. For |
| consistency, the result of this function always has complex dtype, |
| regardless of the value of the imaginary part. |
| |
| References |
| ---------- |
| .. [1] Differential entropy, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Differential_entropy |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> import numpy as np |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-1., b=1.) |
| |
| Evaluate the log-entropy: |
| |
| >>> X.logentropy() |
| (-0.3665129205816642+0j) |
| >>> np.allclose(np.exp(X.logentropy()), X.entropy()) |
| True |
| |
| For a random variable with negative entropy, the log-entropy has an |
| imaginary part equal to `np.pi`. |
| |
| >>> X = stats.Uniform(a=-.1, b=.1) |
| >>> X.entropy(), X.logentropy() |
| (-1.6094379124341007, (0.4758849953271105+3.141592653589793j)) |
| |
| """ |
| raise NotImplementedError() |
| |
| @abstractmethod |
| def entropy(self, *, method): |
| r"""Differential entropy |
| |
| In terms of probability density function :math:`f(x)` and support |
| :math:`\chi`, the differential entropy (or simply "entropy") of a |
| continuous random variable :math:`X` is: |
| |
| .. math:: |
| |
| h(X) = - \int_{\chi} f(x) \log f(x) dx |
| |
| Parameters |
| ---------- |
| method : {None, 'formula', 'logexp', 'quadrature'} |
| The strategy used to evaluate the entropy. By default (``None``), |
| the infrastructure chooses between the following options, listed |
| in order of precedence. |
| |
| - ``'formula'``: use a formula for the entropy itself |
| - ``'logexp'``: evaluate the log-entropy and exponentiate |
| - ``'quadrature'``: use numerical integration |
| |
| Not all `method` options are available for all distributions. |
| If the selected `method` is not available, a ``NotImplementedError`` |
| will be raised. |
| |
| Returns |
| ------- |
| out : array |
| The entropy of the random variable. |
| |
| See Also |
| -------- |
| logentropy |
| pdf |
| |
| Notes |
| ----- |
| This function calculates the entropy using the natural logarithm; i.e. |
| the logarithm with base :math:`e`. Consequently, the value is expressed |
| in (dimensionless) "units" of nats. To convert the entropy to different |
| units (i.e. corresponding with a different base), divide the result by |
| the natural logarithm of the desired base. |
| |
| References |
| ---------- |
| .. [1] Differential entropy, *Wikipedia*, |
| https://en.wikipedia.org/wiki/Differential_entropy |
| |
| Examples |
| -------- |
| Instantiate a distribution with the desired parameters: |
| |
| >>> from scipy import stats |
| >>> X = stats.Uniform(a=-1., b=1.) |
| |
| Evaluate the entropy: |
| |
| >>> X.entropy() |
| 0.6931471805599454 |
| |
| """ |
| raise NotImplementedError() |
|
|