Chris@87: """ Chris@87: Functions that ignore NaN. Chris@87: Chris@87: Functions Chris@87: --------- Chris@87: Chris@87: - `nanmin` -- minimum non-NaN value Chris@87: - `nanmax` -- maximum non-NaN value Chris@87: - `nanargmin` -- index of minimum non-NaN value Chris@87: - `nanargmax` -- index of maximum non-NaN value Chris@87: - `nansum` -- sum of non-NaN values Chris@87: - `nanmean` -- mean of non-NaN values Chris@87: - `nanvar` -- variance of non-NaN values Chris@87: - `nanstd` -- standard deviation of non-NaN values Chris@87: Chris@87: """ Chris@87: from __future__ import division, absolute_import, print_function Chris@87: Chris@87: import warnings Chris@87: import numpy as np Chris@87: from numpy.lib.function_base import _ureduce as _ureduce Chris@87: Chris@87: __all__ = [ Chris@87: 'nansum', 'nanmax', 'nanmin', 'nanargmax', 'nanargmin', 'nanmean', Chris@87: 'nanmedian', 'nanpercentile', 'nanvar', 'nanstd' Chris@87: ] Chris@87: Chris@87: Chris@87: def _replace_nan(a, val): Chris@87: """ Chris@87: If `a` is of inexact type, make a copy of `a`, replace NaNs with Chris@87: the `val` value, and return the copy together with a boolean mask Chris@87: marking the locations where NaNs were present. If `a` is not of Chris@87: inexact type, do nothing and return `a` together with a mask of None. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : array-like Chris@87: Input array. Chris@87: val : float Chris@87: NaN values are set to val before doing the operation. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: y : ndarray Chris@87: If `a` is of inexact type, return a copy of `a` with the NaNs Chris@87: replaced by the fill value, otherwise return `a`. Chris@87: mask: {bool, None} Chris@87: If `a` is of inexact type, return a boolean mask marking locations of Chris@87: NaNs, otherwise return None. Chris@87: Chris@87: """ Chris@87: is_new = not isinstance(a, np.ndarray) Chris@87: if is_new: Chris@87: a = np.array(a) Chris@87: if not issubclass(a.dtype.type, np.inexact): Chris@87: return a, None Chris@87: if not is_new: Chris@87: # need copy Chris@87: a = np.array(a, subok=True) Chris@87: Chris@87: mask = np.isnan(a) Chris@87: np.copyto(a, val, where=mask) Chris@87: return a, mask Chris@87: Chris@87: Chris@87: def _copyto(a, val, mask): Chris@87: """ Chris@87: Replace values in `a` with NaN where `mask` is True. This differs from Chris@87: copyto in that it will deal with the case where `a` is a numpy scalar. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : ndarray or numpy scalar Chris@87: Array or numpy scalar some of whose values are to be replaced Chris@87: by val. Chris@87: val : numpy scalar Chris@87: Value used a replacement. Chris@87: mask : ndarray, scalar Chris@87: Boolean array. Where True the corresponding element of `a` is Chris@87: replaced by `val`. Broadcasts. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: res : ndarray, scalar Chris@87: Array with elements replaced or scalar `val`. Chris@87: Chris@87: """ Chris@87: if isinstance(a, np.ndarray): Chris@87: np.copyto(a, val, where=mask, casting='unsafe') Chris@87: else: Chris@87: a = a.dtype.type(val) Chris@87: return a Chris@87: Chris@87: Chris@87: def _divide_by_count(a, b, out=None): Chris@87: """ Chris@87: Compute a/b ignoring invalid results. If `a` is an array the division Chris@87: is done in place. If `a` is a scalar, then its type is preserved in the Chris@87: output. If out is None, then then a is used instead so that the Chris@87: division is in place. Note that this is only called with `a` an inexact Chris@87: type. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : {ndarray, numpy scalar} Chris@87: Numerator. Expected to be of inexact type but not checked. Chris@87: b : {ndarray, numpy scalar} Chris@87: Denominator. Chris@87: out : ndarray, optional Chris@87: Alternate output array in which to place the result. The default Chris@87: is ``None``; if provided, it must have the same shape as the Chris@87: expected output, but the type will be cast if necessary. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: ret : {ndarray, numpy scalar} Chris@87: The return value is a/b. If `a` was an ndarray the division is done Chris@87: in place. If `a` is a numpy scalar, the division preserves its type. Chris@87: Chris@87: """ Chris@87: with np.errstate(invalid='ignore'): Chris@87: if isinstance(a, np.ndarray): Chris@87: if out is None: Chris@87: return np.divide(a, b, out=a, casting='unsafe') Chris@87: else: Chris@87: return np.divide(a, b, out=out, casting='unsafe') Chris@87: else: Chris@87: if out is None: Chris@87: return a.dtype.type(a / b) Chris@87: else: Chris@87: # This is questionable, but currently a numpy scalar can Chris@87: # be output to a zero dimensional array. Chris@87: return np.divide(a, b, out=out, casting='unsafe') Chris@87: Chris@87: Chris@87: def nanmin(a, axis=None, out=None, keepdims=False): Chris@87: """ Chris@87: Return minimum of an array or minimum along an axis, ignoring any NaNs. Chris@87: When all-NaN slices are encountered a ``RuntimeWarning`` is raised and Chris@87: Nan is returned for that slice. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : array_like Chris@87: Array containing numbers whose minimum is desired. If `a` is not an Chris@87: array, a conversion is attempted. Chris@87: axis : int, optional Chris@87: Axis along which the minimum is computed. The default is to compute Chris@87: the minimum of the flattened array. Chris@87: out : ndarray, optional Chris@87: Alternate output array in which to place the result. The default Chris@87: is ``None``; if provided, it must have the same shape as the Chris@87: expected output, but the type will be cast if necessary. See Chris@87: `doc.ufuncs` for details. Chris@87: Chris@87: .. versionadded:: 1.8.0 Chris@87: keepdims : bool, optional Chris@87: If this is set to True, the axes which are reduced are left in the Chris@87: result as dimensions with size one. With this option, the result Chris@87: will broadcast correctly against the original `a`. Chris@87: Chris@87: .. versionadded:: 1.8.0 Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: nanmin : ndarray Chris@87: An array with the same shape as `a`, with the specified axis Chris@87: removed. If `a` is a 0-d array, or if axis is None, an ndarray Chris@87: scalar is returned. The same dtype as `a` is returned. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: nanmax : Chris@87: The maximum value of an array along a given axis, ignoring any NaNs. Chris@87: amin : Chris@87: The minimum value of an array along a given axis, propagating any NaNs. Chris@87: fmin : Chris@87: Element-wise minimum of two arrays, ignoring any NaNs. Chris@87: minimum : Chris@87: Element-wise minimum of two arrays, propagating any NaNs. Chris@87: isnan : Chris@87: Shows which elements are Not a Number (NaN). Chris@87: isfinite: Chris@87: Shows which elements are neither NaN nor infinity. Chris@87: Chris@87: amax, fmax, maximum Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: Numpy uses the IEEE Standard for Binary Floating-Point for Arithmetic Chris@87: (IEEE 754). This means that Not a Number is not equivalent to infinity. Chris@87: Positive infinity is treated as a very large number and negative Chris@87: infinity is treated as a very small (i.e. negative) number. Chris@87: Chris@87: If the input has a integer type the function is equivalent to np.min. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.array([[1, 2], [3, np.nan]]) Chris@87: >>> np.nanmin(a) Chris@87: 1.0 Chris@87: >>> np.nanmin(a, axis=0) Chris@87: array([ 1., 2.]) Chris@87: >>> np.nanmin(a, axis=1) Chris@87: array([ 1., 3.]) Chris@87: Chris@87: When positive infinity and negative infinity are present: Chris@87: Chris@87: >>> np.nanmin([1, 2, np.nan, np.inf]) Chris@87: 1.0 Chris@87: >>> np.nanmin([1, 2, np.nan, np.NINF]) Chris@87: -inf Chris@87: Chris@87: """ Chris@87: if not isinstance(a, np.ndarray) or type(a) is np.ndarray: Chris@87: # Fast, but not safe for subclasses of ndarray Chris@87: res = np.fmin.reduce(a, axis=axis, out=out, keepdims=keepdims) Chris@87: if np.isnan(res).any(): Chris@87: warnings.warn("All-NaN axis encountered", RuntimeWarning) Chris@87: else: Chris@87: # Slow, but safe for subclasses of ndarray Chris@87: a, mask = _replace_nan(a, +np.inf) Chris@87: res = np.amin(a, axis=axis, out=out, keepdims=keepdims) Chris@87: if mask is None: Chris@87: return res Chris@87: Chris@87: # Check for all-NaN axis Chris@87: mask = np.all(mask, axis=axis, keepdims=keepdims) Chris@87: if np.any(mask): Chris@87: res = _copyto(res, np.nan, mask) Chris@87: warnings.warn("All-NaN axis encountered", RuntimeWarning) Chris@87: return res Chris@87: Chris@87: Chris@87: def nanmax(a, axis=None, out=None, keepdims=False): Chris@87: """ Chris@87: Return the maximum of an array or maximum along an axis, ignoring any Chris@87: NaNs. When all-NaN slices are encountered a ``RuntimeWarning`` is Chris@87: raised and NaN is returned for that slice. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : array_like Chris@87: Array containing numbers whose maximum is desired. If `a` is not an Chris@87: array, a conversion is attempted. Chris@87: axis : int, optional Chris@87: Axis along which the maximum is computed. The default is to compute Chris@87: the maximum of the flattened array. Chris@87: out : ndarray, optional Chris@87: Alternate output array in which to place the result. The default Chris@87: is ``None``; if provided, it must have the same shape as the Chris@87: expected output, but the type will be cast if necessary. See Chris@87: `doc.ufuncs` for details. Chris@87: Chris@87: .. versionadded:: 1.8.0 Chris@87: keepdims : bool, optional Chris@87: If this is set to True, the axes which are reduced are left in the Chris@87: result as dimensions with size one. With this option, the result Chris@87: will broadcast correctly against the original `a`. Chris@87: Chris@87: .. versionadded:: 1.8.0 Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: nanmax : ndarray Chris@87: An array with the same shape as `a`, with the specified axis removed. Chris@87: If `a` is a 0-d array, or if axis is None, an ndarray scalar is Chris@87: returned. The same dtype as `a` is returned. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: nanmin : Chris@87: The minimum value of an array along a given axis, ignoring any NaNs. Chris@87: amax : Chris@87: The maximum value of an array along a given axis, propagating any NaNs. Chris@87: fmax : Chris@87: Element-wise maximum of two arrays, ignoring any NaNs. Chris@87: maximum : Chris@87: Element-wise maximum of two arrays, propagating any NaNs. Chris@87: isnan : Chris@87: Shows which elements are Not a Number (NaN). Chris@87: isfinite: Chris@87: Shows which elements are neither NaN nor infinity. Chris@87: Chris@87: amin, fmin, minimum Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: Numpy uses the IEEE Standard for Binary Floating-Point for Arithmetic Chris@87: (IEEE 754). This means that Not a Number is not equivalent to infinity. Chris@87: Positive infinity is treated as a very large number and negative Chris@87: infinity is treated as a very small (i.e. negative) number. Chris@87: Chris@87: If the input has a integer type the function is equivalent to np.max. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.array([[1, 2], [3, np.nan]]) Chris@87: >>> np.nanmax(a) Chris@87: 3.0 Chris@87: >>> np.nanmax(a, axis=0) Chris@87: array([ 3., 2.]) Chris@87: >>> np.nanmax(a, axis=1) Chris@87: array([ 2., 3.]) Chris@87: Chris@87: When positive infinity and negative infinity are present: Chris@87: Chris@87: >>> np.nanmax([1, 2, np.nan, np.NINF]) Chris@87: 2.0 Chris@87: >>> np.nanmax([1, 2, np.nan, np.inf]) Chris@87: inf Chris@87: Chris@87: """ Chris@87: if not isinstance(a, np.ndarray) or type(a) is np.ndarray: Chris@87: # Fast, but not safe for subclasses of ndarray Chris@87: res = np.fmax.reduce(a, axis=axis, out=out, keepdims=keepdims) Chris@87: if np.isnan(res).any(): Chris@87: warnings.warn("All-NaN slice encountered", RuntimeWarning) Chris@87: else: Chris@87: # Slow, but safe for subclasses of ndarray Chris@87: a, mask = _replace_nan(a, -np.inf) Chris@87: res = np.amax(a, axis=axis, out=out, keepdims=keepdims) Chris@87: if mask is None: Chris@87: return res Chris@87: Chris@87: # Check for all-NaN axis Chris@87: mask = np.all(mask, axis=axis, keepdims=keepdims) Chris@87: if np.any(mask): Chris@87: res = _copyto(res, np.nan, mask) Chris@87: warnings.warn("All-NaN axis encountered", RuntimeWarning) Chris@87: return res Chris@87: Chris@87: Chris@87: def nanargmin(a, axis=None): Chris@87: """ Chris@87: Return the indices of the minimum values in the specified axis ignoring Chris@87: NaNs. For all-NaN slices ``ValueError`` is raised. Warning: the results Chris@87: cannot be trusted if a slice contains only NaNs and Infs. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : array_like Chris@87: Input data. Chris@87: axis : int, optional Chris@87: Axis along which to operate. By default flattened input is used. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: index_array : ndarray Chris@87: An array of indices or a single index value. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: argmin, nanargmax Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.array([[np.nan, 4], [2, 3]]) Chris@87: >>> np.argmin(a) Chris@87: 0 Chris@87: >>> np.nanargmin(a) Chris@87: 2 Chris@87: >>> np.nanargmin(a, axis=0) Chris@87: array([1, 1]) Chris@87: >>> np.nanargmin(a, axis=1) Chris@87: array([1, 0]) Chris@87: Chris@87: """ Chris@87: a, mask = _replace_nan(a, np.inf) Chris@87: res = np.argmin(a, axis=axis) Chris@87: if mask is not None: Chris@87: mask = np.all(mask, axis=axis) Chris@87: if np.any(mask): Chris@87: raise ValueError("All-NaN slice encountered") Chris@87: return res Chris@87: Chris@87: Chris@87: def nanargmax(a, axis=None): Chris@87: """ Chris@87: Return the indices of the maximum values in the specified axis ignoring Chris@87: NaNs. For all-NaN slices ``ValueError`` is raised. Warning: the Chris@87: results cannot be trusted if a slice contains only NaNs and -Infs. Chris@87: Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : array_like Chris@87: Input data. Chris@87: axis : int, optional Chris@87: Axis along which to operate. By default flattened input is used. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: index_array : ndarray Chris@87: An array of indices or a single index value. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: argmax, nanargmin Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.array([[np.nan, 4], [2, 3]]) Chris@87: >>> np.argmax(a) Chris@87: 0 Chris@87: >>> np.nanargmax(a) Chris@87: 1 Chris@87: >>> np.nanargmax(a, axis=0) Chris@87: array([1, 0]) Chris@87: >>> np.nanargmax(a, axis=1) Chris@87: array([1, 1]) Chris@87: Chris@87: """ Chris@87: a, mask = _replace_nan(a, -np.inf) Chris@87: res = np.argmax(a, axis=axis) Chris@87: if mask is not None: Chris@87: mask = np.all(mask, axis=axis) Chris@87: if np.any(mask): Chris@87: raise ValueError("All-NaN slice encountered") Chris@87: return res Chris@87: Chris@87: Chris@87: def nansum(a, axis=None, dtype=None, out=None, keepdims=0): Chris@87: """ Chris@87: Return the sum of array elements over a given axis treating Not a Chris@87: Numbers (NaNs) as zero. Chris@87: Chris@87: In Numpy versions <= 1.8 Nan is returned for slices that are all-NaN or Chris@87: empty. In later versions zero is returned. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : array_like Chris@87: Array containing numbers whose sum is desired. If `a` is not an Chris@87: array, a conversion is attempted. Chris@87: axis : int, optional Chris@87: Axis along which the sum is computed. The default is to compute the Chris@87: sum of the flattened array. Chris@87: dtype : data-type, optional Chris@87: The type of the returned array and of the accumulator in which the Chris@87: elements are summed. By default, the dtype of `a` is used. An Chris@87: exception is when `a` has an integer type with less precision than Chris@87: the platform (u)intp. In that case, the default will be either Chris@87: (u)int32 or (u)int64 depending on whether the platform is 32 or 64 Chris@87: bits. For inexact inputs, dtype must be inexact. Chris@87: Chris@87: .. versionadded:: 1.8.0 Chris@87: out : ndarray, optional Chris@87: Alternate output array in which to place the result. The default Chris@87: is ``None``. If provided, it must have the same shape as the Chris@87: expected output, but the type will be cast if necessary. See Chris@87: `doc.ufuncs` for details. The casting of NaN to integer can yield Chris@87: unexpected results. Chris@87: Chris@87: .. versionadded:: 1.8.0 Chris@87: keepdims : bool, optional Chris@87: If True, the axes which are reduced are left in the result as Chris@87: dimensions with size one. With this option, the result will Chris@87: broadcast correctly against the original `arr`. Chris@87: Chris@87: .. versionadded:: 1.8.0 Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: y : ndarray or numpy scalar Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: numpy.sum : Sum across array propagating NaNs. Chris@87: isnan : Show which elements are NaN. Chris@87: isfinite: Show which elements are not NaN or +/-inf. Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: If both positive and negative infinity are present, the sum will be Not Chris@87: A Number (NaN). Chris@87: Chris@87: Numpy integer arithmetic is modular. If the size of a sum exceeds the Chris@87: size of an integer accumulator, its value will wrap around and the Chris@87: result will be incorrect. Specifying ``dtype=double`` can alleviate Chris@87: that problem. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> np.nansum(1) Chris@87: 1 Chris@87: >>> np.nansum([1]) Chris@87: 1 Chris@87: >>> np.nansum([1, np.nan]) Chris@87: 1.0 Chris@87: >>> a = np.array([[1, 1], [1, np.nan]]) Chris@87: >>> np.nansum(a) Chris@87: 3.0 Chris@87: >>> np.nansum(a, axis=0) Chris@87: array([ 2., 1.]) Chris@87: >>> np.nansum([1, np.nan, np.inf]) Chris@87: inf Chris@87: >>> np.nansum([1, np.nan, np.NINF]) Chris@87: -inf Chris@87: >>> np.nansum([1, np.nan, np.inf, -np.inf]) # both +/- infinity present Chris@87: nan Chris@87: Chris@87: """ Chris@87: a, mask = _replace_nan(a, 0) Chris@87: return np.sum(a, axis=axis, dtype=dtype, out=out, keepdims=keepdims) Chris@87: Chris@87: Chris@87: def nanmean(a, axis=None, dtype=None, out=None, keepdims=False): Chris@87: """ Chris@87: Compute the arithmetic mean along the specified axis, ignoring NaNs. Chris@87: Chris@87: Returns the average of the array elements. The average is taken over Chris@87: the flattened array by default, otherwise over the specified axis. Chris@87: `float64` intermediate and return values are used for integer inputs. Chris@87: Chris@87: For all-NaN slices, NaN is returned and a `RuntimeWarning` is raised. Chris@87: Chris@87: .. versionadded:: 1.8.0 Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : array_like Chris@87: Array containing numbers whose mean is desired. If `a` is not an Chris@87: array, a conversion is attempted. Chris@87: axis : int, optional Chris@87: Axis along which the means are computed. The default is to compute Chris@87: the mean of the flattened array. Chris@87: dtype : data-type, optional Chris@87: Type to use in computing the mean. For integer inputs, the default Chris@87: is `float64`; for inexact inputs, it is the same as the input Chris@87: dtype. Chris@87: out : ndarray, optional Chris@87: Alternate output array in which to place the result. The default Chris@87: is ``None``; if provided, it must have the same shape as the Chris@87: expected output, but the type will be cast if necessary. See Chris@87: `doc.ufuncs` for details. Chris@87: keepdims : bool, optional Chris@87: If this is set to True, the axes which are reduced are left in the Chris@87: result as dimensions with size one. With this option, the result Chris@87: will broadcast correctly against the original `arr`. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: m : ndarray, see dtype parameter above Chris@87: If `out=None`, returns a new array containing the mean values, Chris@87: otherwise a reference to the output array is returned. Nan is Chris@87: returned for slices that contain only NaNs. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: average : Weighted average Chris@87: mean : Arithmetic mean taken while not ignoring NaNs Chris@87: var, nanvar Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: The arithmetic mean is the sum of the non-NaN elements along the axis Chris@87: divided by the number of non-NaN elements. Chris@87: Chris@87: Note that for floating-point input, the mean is computed using the same Chris@87: precision the input has. Depending on the input data, this can cause Chris@87: the results to be inaccurate, especially for `float32`. Specifying a Chris@87: higher-precision accumulator using the `dtype` keyword can alleviate Chris@87: this issue. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.array([[1, np.nan], [3, 4]]) Chris@87: >>> np.nanmean(a) Chris@87: 2.6666666666666665 Chris@87: >>> np.nanmean(a, axis=0) Chris@87: array([ 2., 4.]) Chris@87: >>> np.nanmean(a, axis=1) Chris@87: array([ 1., 3.5]) Chris@87: Chris@87: """ Chris@87: arr, mask = _replace_nan(a, 0) Chris@87: if mask is None: Chris@87: return np.mean(arr, axis=axis, dtype=dtype, out=out, keepdims=keepdims) Chris@87: Chris@87: if dtype is not None: Chris@87: dtype = np.dtype(dtype) Chris@87: if dtype is not None and not issubclass(dtype.type, np.inexact): Chris@87: raise TypeError("If a is inexact, then dtype must be inexact") Chris@87: if out is not None and not issubclass(out.dtype.type, np.inexact): Chris@87: raise TypeError("If a is inexact, then out must be inexact") Chris@87: Chris@87: # The warning context speeds things up. Chris@87: with warnings.catch_warnings(): Chris@87: warnings.simplefilter('ignore') Chris@87: cnt = np.sum(~mask, axis=axis, dtype=np.intp, keepdims=keepdims) Chris@87: tot = np.sum(arr, axis=axis, dtype=dtype, out=out, keepdims=keepdims) Chris@87: avg = _divide_by_count(tot, cnt, out=out) Chris@87: Chris@87: isbad = (cnt == 0) Chris@87: if isbad.any(): Chris@87: warnings.warn("Mean of empty slice", RuntimeWarning) Chris@87: # NaN is the only possible bad value, so no further Chris@87: # action is needed to handle bad results. Chris@87: return avg Chris@87: Chris@87: Chris@87: def _nanmedian1d(arr1d, overwrite_input=False): Chris@87: """ Chris@87: Private function for rank 1 arrays. Compute the median ignoring NaNs. Chris@87: See nanmedian for parameter usage Chris@87: """ Chris@87: c = np.isnan(arr1d) Chris@87: s = np.where(c)[0] Chris@87: if s.size == arr1d.size: Chris@87: warnings.warn("All-NaN slice encountered", RuntimeWarning) Chris@87: return np.nan Chris@87: elif s.size == 0: Chris@87: return np.median(arr1d, overwrite_input=overwrite_input) Chris@87: else: Chris@87: if overwrite_input: Chris@87: x = arr1d Chris@87: else: Chris@87: x = arr1d.copy() Chris@87: # select non-nans at end of array Chris@87: enonan = arr1d[-s.size:][~c[-s.size:]] Chris@87: # fill nans in beginning of array with non-nans of end Chris@87: x[s[:enonan.size]] = enonan Chris@87: # slice nans away Chris@87: return np.median(x[:-s.size], overwrite_input=True) Chris@87: Chris@87: Chris@87: def _nanmedian(a, axis=None, out=None, overwrite_input=False): Chris@87: """ Chris@87: Private function that doesn't support extended axis or keepdims. Chris@87: These methods are extended to this function using _ureduce Chris@87: See nanmedian for parameter usage Chris@87: Chris@87: """ Chris@87: if axis is None or a.ndim == 1: Chris@87: part = a.ravel() Chris@87: if out is None: Chris@87: return _nanmedian1d(part, overwrite_input) Chris@87: else: Chris@87: out[...] = _nanmedian1d(part, overwrite_input) Chris@87: return out Chris@87: else: Chris@87: # for small medians use sort + indexing which is still faster than Chris@87: # apply_along_axis Chris@87: if a.shape[axis] < 400: Chris@87: return _nanmedian_small(a, axis, out, overwrite_input) Chris@87: result = np.apply_along_axis(_nanmedian1d, axis, a, overwrite_input) Chris@87: if out is not None: Chris@87: out[...] = result Chris@87: return result Chris@87: Chris@87: def _nanmedian_small(a, axis=None, out=None, overwrite_input=False): Chris@87: """ Chris@87: sort + indexing median, faster for small medians along multiple dimensions Chris@87: due to the high overhead of apply_along_axis Chris@87: see nanmedian for parameter usage Chris@87: """ Chris@87: a = np.ma.masked_array(a, np.isnan(a)) Chris@87: m = np.ma.median(a, axis=axis, overwrite_input=overwrite_input) Chris@87: for i in range(np.count_nonzero(m.mask.ravel())): Chris@87: warnings.warn("All-NaN slice encountered", RuntimeWarning) Chris@87: if out is not None: Chris@87: out[...] = m.filled(np.nan) Chris@87: return out Chris@87: return m.filled(np.nan) Chris@87: Chris@87: def nanmedian(a, axis=None, out=None, overwrite_input=False, keepdims=False): Chris@87: """ Chris@87: Compute the median along the specified axis, while ignoring NaNs. Chris@87: Chris@87: Returns the median of the array elements. Chris@87: Chris@87: .. versionadded:: 1.9.0 Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : array_like Chris@87: Input array or object that can be converted to an array. Chris@87: axis : int, optional Chris@87: Axis along which the medians are computed. The default (axis=None) Chris@87: is to compute the median along a flattened version of the array. Chris@87: A sequence of axes is supported since version 1.9.0. Chris@87: out : ndarray, optional Chris@87: Alternative output array in which to place the result. It must have Chris@87: the same shape and buffer length as the expected output, but the Chris@87: type (of the output) will be cast if necessary. Chris@87: overwrite_input : bool, optional Chris@87: If True, then allow use of memory of input array (a) for Chris@87: calculations. The input array will be modified by the call to Chris@87: median. This will save memory when you do not need to preserve Chris@87: the contents of the input array. Treat the input as undefined, Chris@87: but it will probably be fully or partially sorted. Default is Chris@87: False. Note that, if `overwrite_input` is True and the input Chris@87: is not already an ndarray, an error will be raised. Chris@87: keepdims : bool, optional Chris@87: If this is set to True, the axes which are reduced are left Chris@87: in the result as dimensions with size one. With this option, Chris@87: the result will broadcast correctly against the original `arr`. Chris@87: Chris@87: Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: median : ndarray Chris@87: A new array holding the result. If the input contains integers, or Chris@87: floats of smaller precision than 64, then the output data-type is Chris@87: float64. Otherwise, the output data-type is the same as that of the Chris@87: input. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: mean, median, percentile Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: Given a vector V of length N, the median of V is the middle value of Chris@87: a sorted copy of V, ``V_sorted`` - i.e., ``V_sorted[(N-1)/2]``, when N is Chris@87: odd. When N is even, it is the average of the two middle values of Chris@87: ``V_sorted``. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.array([[10.0, 7, 4], [3, 2, 1]]) Chris@87: >>> a[0, 1] = np.nan Chris@87: >>> a Chris@87: array([[ 10., nan, 4.], Chris@87: [ 3., 2., 1.]]) Chris@87: >>> np.median(a) Chris@87: nan Chris@87: >>> np.nanmedian(a) Chris@87: 3.0 Chris@87: >>> np.nanmedian(a, axis=0) Chris@87: array([ 6.5, 2., 2.5]) Chris@87: >>> np.median(a, axis=1) Chris@87: array([ 7., 2.]) Chris@87: >>> b = a.copy() Chris@87: >>> np.nanmedian(b, axis=1, overwrite_input=True) Chris@87: array([ 7., 2.]) Chris@87: >>> assert not np.all(a==b) Chris@87: >>> b = a.copy() Chris@87: >>> np.nanmedian(b, axis=None, overwrite_input=True) Chris@87: 3.0 Chris@87: >>> assert not np.all(a==b) Chris@87: Chris@87: """ Chris@87: a = np.asanyarray(a) Chris@87: # apply_along_axis in _nanmedian doesn't handle empty arrays well, Chris@87: # so deal them upfront Chris@87: if a.size == 0: Chris@87: return np.nanmean(a, axis, out=out, keepdims=keepdims) Chris@87: Chris@87: r, k = _ureduce(a, func=_nanmedian, axis=axis, out=out, Chris@87: overwrite_input=overwrite_input) Chris@87: if keepdims: Chris@87: return r.reshape(k) Chris@87: else: Chris@87: return r Chris@87: Chris@87: Chris@87: def nanpercentile(a, q, axis=None, out=None, overwrite_input=False, Chris@87: interpolation='linear', keepdims=False): Chris@87: """ Chris@87: Compute the qth percentile of the data along the specified axis, while Chris@87: ignoring nan values. Chris@87: Chris@87: Returns the qth percentile of the array elements. Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : array_like Chris@87: Input array or object that can be converted to an array. Chris@87: q : float in range of [0,100] (or sequence of floats) Chris@87: Percentile to compute which must be between 0 and 100 inclusive. Chris@87: axis : int or sequence of int, optional Chris@87: Axis along which the percentiles are computed. The default (None) Chris@87: is to compute the percentiles along a flattened version of the array. Chris@87: A sequence of axes is supported since version 1.9.0. Chris@87: out : ndarray, optional Chris@87: Alternative output array in which to place the result. It must Chris@87: have the same shape and buffer length as the expected output, Chris@87: but the type (of the output) will be cast if necessary. Chris@87: overwrite_input : bool, optional Chris@87: If True, then allow use of memory of input array `a` for Chris@87: calculations. The input array will be modified by the call to Chris@87: percentile. This will save memory when you do not need to preserve Chris@87: the contents of the input array. In this case you should not make Chris@87: any assumptions about the content of the passed in array `a` after Chris@87: this function completes -- treat it as undefined. Default is False. Chris@87: Note that, if the `a` input is not already an array this parameter Chris@87: will have no effect, `a` will be converted to an array internally Chris@87: regardless of the value of this parameter. Chris@87: interpolation : {'linear', 'lower', 'higher', 'midpoint', 'nearest'} Chris@87: This optional parameter specifies the interpolation method to use, Chris@87: when the desired quantile lies between two data points `i` and `j`: Chris@87: * linear: `i + (j - i) * fraction`, where `fraction` is the Chris@87: fractional part of the index surrounded by `i` and `j`. Chris@87: * lower: `i`. Chris@87: * higher: `j`. Chris@87: * nearest: `i` or `j` whichever is nearest. Chris@87: * midpoint: (`i` + `j`) / 2. Chris@87: Chris@87: keepdims : bool, optional Chris@87: If this is set to True, the axes which are reduced are left Chris@87: in the result as dimensions with size one. With this option, Chris@87: the result will broadcast correctly against the original `arr`. Chris@87: Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: nanpercentile : scalar or ndarray Chris@87: If a single percentile `q` is given and axis=None a scalar is Chris@87: returned. If multiple percentiles `q` are given an array holding Chris@87: the result is returned. The results are listed in the first axis. Chris@87: (If `out` is specified, in which case that array is returned Chris@87: instead). If the input contains integers, or floats of smaller Chris@87: precision than 64, then the output data-type is float64. Otherwise, Chris@87: the output data-type is the same as that of the input. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: nanmean, nanmedian, percentile, median, mean Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: Given a vector V of length N, the q-th percentile of V is the q-th ranked Chris@87: value in a sorted copy of V. The values and distances of the two Chris@87: nearest neighbors as well as the `interpolation` parameter will Chris@87: determine the percentile if the normalized ranking does not match q Chris@87: exactly. This function is the same as the median if ``q=50``, the same Chris@87: as the minimum if ``q=0``and the same as the maximum if ``q=100``. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.array([[10., 7., 4.], [3., 2., 1.]]) Chris@87: >>> a[0][1] = np.nan Chris@87: >>> a Chris@87: array([[ 10., nan, 4.], Chris@87: [ 3., 2., 1.]]) Chris@87: >>> np.percentile(a, 50) Chris@87: nan Chris@87: >>> np.nanpercentile(a, 50) Chris@87: 3.5 Chris@87: >>> np.nanpercentile(a, 50, axis=0) Chris@87: array([[ 6.5, 4.5, 2.5]]) Chris@87: >>> np.nanpercentile(a, 50, axis=1) Chris@87: array([[ 7.], Chris@87: [ 2.]]) Chris@87: >>> m = np.nanpercentile(a, 50, axis=0) Chris@87: >>> out = np.zeros_like(m) Chris@87: >>> np.nanpercentile(a, 50, axis=0, out=m) Chris@87: array([[ 6.5, 4.5, 2.5]]) Chris@87: >>> m Chris@87: array([[ 6.5, 4.5, 2.5]]) Chris@87: >>> b = a.copy() Chris@87: >>> np.nanpercentile(b, 50, axis=1, overwrite_input=True) Chris@87: array([[ 7.], Chris@87: [ 2.]]) Chris@87: >>> assert not np.all(a==b) Chris@87: >>> b = a.copy() Chris@87: >>> np.nanpercentile(b, 50, axis=None, overwrite_input=True) Chris@87: array([ 3.5]) Chris@87: Chris@87: """ Chris@87: Chris@87: a = np.asanyarray(a) Chris@87: q = np.asanyarray(q) Chris@87: # apply_along_axis in _nanpercentile doesn't handle empty arrays well, Chris@87: # so deal them upfront Chris@87: if a.size == 0: Chris@87: return np.nanmean(a, axis, out=out, keepdims=keepdims) Chris@87: Chris@87: r, k = _ureduce(a, func=_nanpercentile, q=q, axis=axis, out=out, Chris@87: overwrite_input=overwrite_input, Chris@87: interpolation=interpolation) Chris@87: if keepdims: Chris@87: if q.ndim == 0: Chris@87: return r.reshape(k) Chris@87: else: Chris@87: return r.reshape([len(q)] + k) Chris@87: else: Chris@87: return r Chris@87: Chris@87: Chris@87: def _nanpercentile(a, q, axis=None, out=None, overwrite_input=False, Chris@87: interpolation='linear', keepdims=False): Chris@87: """ Chris@87: Private function that doesn't support extended axis or keepdims. Chris@87: These methods are extended to this function using _ureduce Chris@87: See nanpercentile for parameter usage Chris@87: Chris@87: """ Chris@87: if axis is None: Chris@87: part = a.ravel() Chris@87: result = _nanpercentile1d(part, q, overwrite_input, interpolation) Chris@87: else: Chris@87: result = np.apply_along_axis(_nanpercentile1d, axis, a, q, Chris@87: overwrite_input, interpolation) Chris@87: Chris@87: if out is not None: Chris@87: out[...] = result Chris@87: return result Chris@87: Chris@87: Chris@87: def _nanpercentile1d(arr1d, q, overwrite_input=False, interpolation='linear'): Chris@87: """ Chris@87: Private function for rank 1 arrays. Compute percentile ignoring NaNs. Chris@87: See nanpercentile for parameter usage Chris@87: Chris@87: """ Chris@87: c = np.isnan(arr1d) Chris@87: s = np.where(c)[0] Chris@87: if s.size == arr1d.size: Chris@87: warnings.warn("All-NaN slice encountered", RuntimeWarning) Chris@87: return np.nan Chris@87: elif s.size == 0: Chris@87: return np.percentile(arr1d, q, overwrite_input=overwrite_input, Chris@87: interpolation=interpolation) Chris@87: else: Chris@87: if overwrite_input: Chris@87: x = arr1d Chris@87: else: Chris@87: x = arr1d.copy() Chris@87: # select non-nans at end of array Chris@87: enonan = arr1d[-s.size:][~c[-s.size:]] Chris@87: # fill nans in beginning of array with non-nans of end Chris@87: x[s[:enonan.size]] = enonan Chris@87: # slice nans away Chris@87: return np.percentile(x[:-s.size], q, overwrite_input=True, Chris@87: interpolation=interpolation) Chris@87: Chris@87: Chris@87: def nanvar(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False): Chris@87: """ Chris@87: Compute the variance along the specified axis, while ignoring NaNs. Chris@87: Chris@87: Returns the variance of the array elements, a measure of the spread of Chris@87: a distribution. The variance is computed for the flattened array by Chris@87: default, otherwise over the specified axis. Chris@87: Chris@87: For all-NaN slices or slices with zero degrees of freedom, NaN is Chris@87: returned and a `RuntimeWarning` is raised. Chris@87: Chris@87: .. versionadded:: 1.8.0 Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : array_like Chris@87: Array containing numbers whose variance is desired. If `a` is not an Chris@87: array, a conversion is attempted. Chris@87: axis : int, optional Chris@87: Axis along which the variance is computed. The default is to compute Chris@87: the variance of the flattened array. Chris@87: dtype : data-type, optional Chris@87: Type to use in computing the variance. For arrays of integer type Chris@87: the default is `float32`; for arrays of float types it is the same as Chris@87: the array type. Chris@87: out : ndarray, optional Chris@87: Alternate output array in which to place the result. It must have Chris@87: the same shape as the expected output, but the type is cast if Chris@87: necessary. Chris@87: ddof : int, optional Chris@87: "Delta Degrees of Freedom": the divisor used in the calculation is Chris@87: ``N - ddof``, where ``N`` represents the number of non-NaN Chris@87: elements. By default `ddof` is zero. Chris@87: keepdims : bool, optional Chris@87: If this is set to True, the axes which are reduced are left Chris@87: in the result as dimensions with size one. With this option, Chris@87: the result will broadcast correctly against the original `arr`. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: variance : ndarray, see dtype parameter above Chris@87: If `out` is None, return a new array containing the variance, Chris@87: otherwise return a reference to the output array. If ddof is >= the Chris@87: number of non-NaN elements in a slice or the slice contains only Chris@87: NaNs, then the result for that slice is NaN. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: std : Standard deviation Chris@87: mean : Average Chris@87: var : Variance while not ignoring NaNs Chris@87: nanstd, nanmean Chris@87: numpy.doc.ufuncs : Section "Output arguments" Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: The variance is the average of the squared deviations from the mean, Chris@87: i.e., ``var = mean(abs(x - x.mean())**2)``. Chris@87: Chris@87: The mean is normally calculated as ``x.sum() / N``, where ``N = len(x)``. Chris@87: If, however, `ddof` is specified, the divisor ``N - ddof`` is used Chris@87: instead. In standard statistical practice, ``ddof=1`` provides an Chris@87: unbiased estimator of the variance of a hypothetical infinite Chris@87: population. ``ddof=0`` provides a maximum likelihood estimate of the Chris@87: variance for normally distributed variables. Chris@87: Chris@87: Note that for complex numbers, the absolute value is taken before Chris@87: squaring, so that the result is always real and nonnegative. Chris@87: Chris@87: For floating-point input, the variance is computed using the same Chris@87: precision the input has. Depending on the input data, this can cause Chris@87: the results to be inaccurate, especially for `float32` (see example Chris@87: below). Specifying a higher-accuracy accumulator using the ``dtype`` Chris@87: keyword can alleviate this issue. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.array([[1, np.nan], [3, 4]]) Chris@87: >>> np.var(a) Chris@87: 1.5555555555555554 Chris@87: >>> np.nanvar(a, axis=0) Chris@87: array([ 1., 0.]) Chris@87: >>> np.nanvar(a, axis=1) Chris@87: array([ 0., 0.25]) Chris@87: Chris@87: """ Chris@87: arr, mask = _replace_nan(a, 0) Chris@87: if mask is None: Chris@87: return np.var(arr, axis=axis, dtype=dtype, out=out, ddof=ddof, Chris@87: keepdims=keepdims) Chris@87: Chris@87: if dtype is not None: Chris@87: dtype = np.dtype(dtype) Chris@87: if dtype is not None and not issubclass(dtype.type, np.inexact): Chris@87: raise TypeError("If a is inexact, then dtype must be inexact") Chris@87: if out is not None and not issubclass(out.dtype.type, np.inexact): Chris@87: raise TypeError("If a is inexact, then out must be inexact") Chris@87: Chris@87: with warnings.catch_warnings(): Chris@87: warnings.simplefilter('ignore') Chris@87: Chris@87: # Compute mean Chris@87: cnt = np.sum(~mask, axis=axis, dtype=np.intp, keepdims=True) Chris@87: avg = np.sum(arr, axis=axis, dtype=dtype, keepdims=True) Chris@87: avg = _divide_by_count(avg, cnt) Chris@87: Chris@87: # Compute squared deviation from mean. Chris@87: arr -= avg Chris@87: arr = _copyto(arr, 0, mask) Chris@87: if issubclass(arr.dtype.type, np.complexfloating): Chris@87: sqr = np.multiply(arr, arr.conj(), out=arr).real Chris@87: else: Chris@87: sqr = np.multiply(arr, arr, out=arr) Chris@87: Chris@87: # Compute variance. Chris@87: var = np.sum(sqr, axis=axis, dtype=dtype, out=out, keepdims=keepdims) Chris@87: if var.ndim < cnt.ndim: Chris@87: # Subclasses of ndarray may ignore keepdims, so check here. Chris@87: cnt = cnt.squeeze(axis) Chris@87: dof = cnt - ddof Chris@87: var = _divide_by_count(var, dof) Chris@87: Chris@87: isbad = (dof <= 0) Chris@87: if np.any(isbad): Chris@87: warnings.warn("Degrees of freedom <= 0 for slice.", RuntimeWarning) Chris@87: # NaN, inf, or negative numbers are all possible bad Chris@87: # values, so explicitly replace them with NaN. Chris@87: var = _copyto(var, np.nan, isbad) Chris@87: return var Chris@87: Chris@87: Chris@87: def nanstd(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False): Chris@87: """ Chris@87: Compute the standard deviation along the specified axis, while Chris@87: ignoring NaNs. Chris@87: Chris@87: Returns the standard deviation, a measure of the spread of a Chris@87: distribution, of the non-NaN array elements. The standard deviation is Chris@87: computed for the flattened array by default, otherwise over the Chris@87: specified axis. Chris@87: Chris@87: For all-NaN slices or slices with zero degrees of freedom, NaN is Chris@87: returned and a `RuntimeWarning` is raised. Chris@87: Chris@87: .. versionadded:: 1.8.0 Chris@87: Chris@87: Parameters Chris@87: ---------- Chris@87: a : array_like Chris@87: Calculate the standard deviation of the non-NaN values. Chris@87: axis : int, optional Chris@87: Axis along which the standard deviation is computed. The default is Chris@87: to compute the standard deviation of the flattened array. Chris@87: dtype : dtype, optional Chris@87: Type to use in computing the standard deviation. For arrays of Chris@87: integer type the default is float64, for arrays of float types it Chris@87: is the same as the array type. Chris@87: out : ndarray, optional Chris@87: Alternative output array in which to place the result. It must have Chris@87: the same shape as the expected output but the type (of the Chris@87: calculated values) will be cast if necessary. Chris@87: ddof : int, optional Chris@87: Means Delta Degrees of Freedom. The divisor used in calculations Chris@87: is ``N - ddof``, where ``N`` represents the number of non-NaN Chris@87: elements. By default `ddof` is zero. Chris@87: keepdims : bool, optional Chris@87: If this is set to True, the axes which are reduced are left Chris@87: in the result as dimensions with size one. With this option, Chris@87: the result will broadcast correctly against the original `arr`. Chris@87: Chris@87: Returns Chris@87: ------- Chris@87: standard_deviation : ndarray, see dtype parameter above. Chris@87: If `out` is None, return a new array containing the standard Chris@87: deviation, otherwise return a reference to the output array. If Chris@87: ddof is >= the number of non-NaN elements in a slice or the slice Chris@87: contains only NaNs, then the result for that slice is NaN. Chris@87: Chris@87: See Also Chris@87: -------- Chris@87: var, mean, std Chris@87: nanvar, nanmean Chris@87: numpy.doc.ufuncs : Section "Output arguments" Chris@87: Chris@87: Notes Chris@87: ----- Chris@87: The standard deviation is the square root of the average of the squared Chris@87: deviations from the mean: ``std = sqrt(mean(abs(x - x.mean())**2))``. Chris@87: Chris@87: The average squared deviation is normally calculated as Chris@87: ``x.sum() / N``, where ``N = len(x)``. If, however, `ddof` is Chris@87: specified, the divisor ``N - ddof`` is used instead. In standard Chris@87: statistical practice, ``ddof=1`` provides an unbiased estimator of the Chris@87: variance of the infinite population. ``ddof=0`` provides a maximum Chris@87: likelihood estimate of the variance for normally distributed variables. Chris@87: The standard deviation computed in this function is the square root of Chris@87: the estimated variance, so even with ``ddof=1``, it will not be an Chris@87: unbiased estimate of the standard deviation per se. Chris@87: Chris@87: Note that, for complex numbers, `std` takes the absolute value before Chris@87: squaring, so that the result is always real and nonnegative. Chris@87: Chris@87: For floating-point input, the *std* is computed using the same Chris@87: precision the input has. Depending on the input data, this can cause Chris@87: the results to be inaccurate, especially for float32 (see example Chris@87: below). Specifying a higher-accuracy accumulator using the `dtype` Chris@87: keyword can alleviate this issue. Chris@87: Chris@87: Examples Chris@87: -------- Chris@87: >>> a = np.array([[1, np.nan], [3, 4]]) Chris@87: >>> np.nanstd(a) Chris@87: 1.247219128924647 Chris@87: >>> np.nanstd(a, axis=0) Chris@87: array([ 1., 0.]) Chris@87: >>> np.nanstd(a, axis=1) Chris@87: array([ 0., 0.5]) Chris@87: Chris@87: """ Chris@87: var = nanvar(a, axis=axis, dtype=dtype, out=out, ddof=ddof, Chris@87: keepdims=keepdims) Chris@87: if isinstance(var, np.ndarray): Chris@87: std = np.sqrt(var, out=var) Chris@87: else: Chris@87: std = var.dtype.type(np.sqrt(var)) Chris@87: return std