AIM-PIbd-32-Kurbanova-A-A/aimenv/Lib/site-packages/scipy/stats/_variation.py
2024-10-02 22:15:59 +04:00

129 lines
4.5 KiB
Python

import numpy as np
from scipy._lib._util import _get_nan
from scipy._lib._array_api import array_namespace, xp_copysign
from ._axis_nan_policy import _axis_nan_policy_factory
@_axis_nan_policy_factory(
lambda x: x, n_outputs=1, result_to_tuple=lambda x: (x,)
)
def variation(a, axis=0, nan_policy='propagate', ddof=0, *, keepdims=False):
"""
Compute the coefficient of variation.
The coefficient of variation is the standard deviation divided by the
mean. This function is equivalent to::
np.std(x, axis=axis, ddof=ddof) / np.mean(x)
The default for ``ddof`` is 0, but many definitions of the coefficient
of variation use the square root of the unbiased sample variance
for the sample standard deviation, which corresponds to ``ddof=1``.
The function does not take the absolute value of the mean of the data,
so the return value is negative if the mean is negative.
Parameters
----------
a : array_like
Input array.
axis : int or None, optional
Axis along which to calculate the coefficient of variation.
Default is 0. If None, compute over the whole array `a`.
nan_policy : {'propagate', 'raise', 'omit'}, optional
Defines how to handle when input contains ``nan``.
The following options are available:
* 'propagate': return ``nan``
* 'raise': raise an exception
* 'omit': perform the calculation with ``nan`` values omitted
The default is 'propagate'.
ddof : int, optional
Gives the "Delta Degrees Of Freedom" used when computing the
standard deviation. The divisor used in the calculation of the
standard deviation is ``N - ddof``, where ``N`` is the number of
elements. `ddof` must be less than ``N``; if it isn't, the result
will be ``nan`` or ``inf``, depending on ``N`` and the values in
the array. By default `ddof` is zero for backwards compatibility,
but it is recommended to use ``ddof=1`` to ensure that the sample
standard deviation is computed as the square root of the unbiased
sample variance.
Returns
-------
variation : ndarray
The calculated variation along the requested axis.
Notes
-----
There are several edge cases that are handled without generating a
warning:
* If both the mean and the standard deviation are zero, ``nan``
is returned.
* If the mean is zero and the standard deviation is nonzero, ``inf``
is returned.
* If the input has length zero (either because the array has zero
length, or all the input values are ``nan`` and ``nan_policy`` is
``'omit'``), ``nan`` is returned.
* If the input contains ``inf``, ``nan`` is returned.
References
----------
.. [1] Zwillinger, D. and Kokoska, S. (2000). CRC Standard
Probability and Statistics Tables and Formulae. Chapman & Hall: New
York. 2000.
Examples
--------
>>> import numpy as np
>>> from scipy.stats import variation
>>> variation([1, 2, 3, 4, 5], ddof=1)
0.5270462766947299
Compute the variation along a given dimension of an array that contains
a few ``nan`` values:
>>> x = np.array([[ 10.0, np.nan, 11.0, 19.0, 23.0, 29.0, 98.0],
... [ 29.0, 30.0, 32.0, 33.0, 35.0, 56.0, 57.0],
... [np.nan, np.nan, 12.0, 13.0, 16.0, 16.0, 17.0]])
>>> variation(x, axis=1, ddof=1, nan_policy='omit')
array([1.05109361, 0.31428986, 0.146483 ])
"""
xp = array_namespace(a)
a = xp.asarray(a)
# `nan_policy` and `keepdims` are handled by `_axis_nan_policy`
# `axis=None` is only handled for NumPy backend
if axis is None:
a = xp.reshape(a, (-1,))
axis = 0
n = a.shape[axis]
NaN = _get_nan(a)
if a.size == 0 or ddof > n:
# Handle as a special case to avoid spurious warnings.
# The return values, if any, are all nan.
shp = list(a.shape)
shp.pop(axis)
result = xp.full(shp, fill_value=NaN)
return result[()] if result.ndim == 0 else result
mean_a = xp.mean(a, axis=axis)
if ddof == n:
# Another special case. Result is either inf or nan.
std_a = xp.std(a, axis=axis, correction=0)
result = xp.where(std_a > 0, xp_copysign(xp.asarray(xp.inf), mean_a), NaN)
return result[()] if result.ndim == 0 else result
with np.errstate(divide='ignore', invalid='ignore'):
std_a = xp.std(a, axis=axis, correction=ddof)
result = std_a / mean_a
return result[()] if result.ndim == 0 else result