Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/numpy/ma/extras.py: 16%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2Masked arrays add-ons.
4A collection of utilities for `numpy.ma`.
6:author: Pierre Gerard-Marchant
7:contact: pierregm_at_uga_dot_edu
8:version: $Id: extras.py 3473 2007-10-29 15:18:13Z jarrod.millman $
10"""
11__all__ = [
12 'apply_along_axis', 'apply_over_axes', 'atleast_1d', 'atleast_2d',
13 'atleast_3d', 'average', 'clump_masked', 'clump_unmasked', 'column_stack',
14 'compress_cols', 'compress_nd', 'compress_rowcols', 'compress_rows',
15 'count_masked', 'corrcoef', 'cov', 'diagflat', 'dot', 'dstack', 'ediff1d',
16 'flatnotmasked_contiguous', 'flatnotmasked_edges', 'hsplit', 'hstack',
17 'isin', 'in1d', 'intersect1d', 'mask_cols', 'mask_rowcols', 'mask_rows',
18 'masked_all', 'masked_all_like', 'median', 'mr_', 'ndenumerate',
19 'notmasked_contiguous', 'notmasked_edges', 'polyfit', 'row_stack',
20 'setdiff1d', 'setxor1d', 'stack', 'unique', 'union1d', 'vander', 'vstack',
21 ]
23import itertools
24import warnings
26from . import core as ma
27from .core import (
28 MaskedArray, MAError, add, array, asarray, concatenate, filled, count,
29 getmask, getmaskarray, make_mask_descr, masked, masked_array, mask_or,
30 nomask, ones, sort, zeros, getdata, get_masked_subclass, dot
31 )
33import numpy as np
34from numpy import ndarray, array as nxarray
35from numpy.core.multiarray import normalize_axis_index
36from numpy.core.numeric import normalize_axis_tuple
37from numpy.lib.function_base import _ureduce
38from numpy.lib.index_tricks import AxisConcatenator
41def issequence(seq):
42 """
43 Is seq a sequence (ndarray, list or tuple)?
45 """
46 return isinstance(seq, (ndarray, tuple, list))
49def count_masked(arr, axis=None):
50 """
51 Count the number of masked elements along the given axis.
53 Parameters
54 ----------
55 arr : array_like
56 An array with (possibly) masked elements.
57 axis : int, optional
58 Axis along which to count. If None (default), a flattened
59 version of the array is used.
61 Returns
62 -------
63 count : int, ndarray
64 The total number of masked elements (axis=None) or the number
65 of masked elements along each slice of the given axis.
67 See Also
68 --------
69 MaskedArray.count : Count non-masked elements.
71 Examples
72 --------
73 >>> import numpy.ma as ma
74 >>> a = np.arange(9).reshape((3,3))
75 >>> a = ma.array(a)
76 >>> a[1, 0] = ma.masked
77 >>> a[1, 2] = ma.masked
78 >>> a[2, 1] = ma.masked
79 >>> a
80 masked_array(
81 data=[[0, 1, 2],
82 [--, 4, --],
83 [6, --, 8]],
84 mask=[[False, False, False],
85 [ True, False, True],
86 [False, True, False]],
87 fill_value=999999)
88 >>> ma.count_masked(a)
89 3
91 When the `axis` keyword is used an array is returned.
93 >>> ma.count_masked(a, axis=0)
94 array([1, 1, 1])
95 >>> ma.count_masked(a, axis=1)
96 array([0, 2, 1])
98 """
99 m = getmaskarray(arr)
100 return m.sum(axis)
103def masked_all(shape, dtype=float):
104 """
105 Empty masked array with all elements masked.
107 Return an empty masked array of the given shape and dtype, where all the
108 data are masked.
110 Parameters
111 ----------
112 shape : int or tuple of ints
113 Shape of the required MaskedArray, e.g., ``(2, 3)`` or ``2``.
114 dtype : dtype, optional
115 Data type of the output.
117 Returns
118 -------
119 a : MaskedArray
120 A masked array with all data masked.
122 See Also
123 --------
124 masked_all_like : Empty masked array modelled on an existing array.
126 Examples
127 --------
128 >>> import numpy.ma as ma
129 >>> ma.masked_all((3, 3))
130 masked_array(
131 data=[[--, --, --],
132 [--, --, --],
133 [--, --, --]],
134 mask=[[ True, True, True],
135 [ True, True, True],
136 [ True, True, True]],
137 fill_value=1e+20,
138 dtype=float64)
140 The `dtype` parameter defines the underlying data type.
142 >>> a = ma.masked_all((3, 3))
143 >>> a.dtype
144 dtype('float64')
145 >>> a = ma.masked_all((3, 3), dtype=np.int32)
146 >>> a.dtype
147 dtype('int32')
149 """
150 a = masked_array(np.empty(shape, dtype),
151 mask=np.ones(shape, make_mask_descr(dtype)))
152 return a
155def masked_all_like(arr):
156 """
157 Empty masked array with the properties of an existing array.
159 Return an empty masked array of the same shape and dtype as
160 the array `arr`, where all the data are masked.
162 Parameters
163 ----------
164 arr : ndarray
165 An array describing the shape and dtype of the required MaskedArray.
167 Returns
168 -------
169 a : MaskedArray
170 A masked array with all data masked.
172 Raises
173 ------
174 AttributeError
175 If `arr` doesn't have a shape attribute (i.e. not an ndarray)
177 See Also
178 --------
179 masked_all : Empty masked array with all elements masked.
181 Examples
182 --------
183 >>> import numpy.ma as ma
184 >>> arr = np.zeros((2, 3), dtype=np.float32)
185 >>> arr
186 array([[0., 0., 0.],
187 [0., 0., 0.]], dtype=float32)
188 >>> ma.masked_all_like(arr)
189 masked_array(
190 data=[[--, --, --],
191 [--, --, --]],
192 mask=[[ True, True, True],
193 [ True, True, True]],
194 fill_value=1e+20,
195 dtype=float32)
197 The dtype of the masked array matches the dtype of `arr`.
199 >>> arr.dtype
200 dtype('float32')
201 >>> ma.masked_all_like(arr).dtype
202 dtype('float32')
204 """
205 a = np.empty_like(arr).view(MaskedArray)
206 a._mask = np.ones(a.shape, dtype=make_mask_descr(a.dtype))
207 return a
210#####--------------------------------------------------------------------------
211#---- --- Standard functions ---
212#####--------------------------------------------------------------------------
213class _fromnxfunction:
214 """
215 Defines a wrapper to adapt NumPy functions to masked arrays.
218 An instance of `_fromnxfunction` can be called with the same parameters
219 as the wrapped NumPy function. The docstring of `newfunc` is adapted from
220 the wrapped function as well, see `getdoc`.
222 This class should not be used directly. Instead, one of its extensions that
223 provides support for a specific type of input should be used.
225 Parameters
226 ----------
227 funcname : str
228 The name of the function to be adapted. The function should be
229 in the NumPy namespace (i.e. ``np.funcname``).
231 """
233 def __init__(self, funcname):
234 self.__name__ = funcname
235 self.__doc__ = self.getdoc()
237 def getdoc(self):
238 """
239 Retrieve the docstring and signature from the function.
241 The ``__doc__`` attribute of the function is used as the docstring for
242 the new masked array version of the function. A note on application
243 of the function to the mask is appended.
245 Parameters
246 ----------
247 None
249 """
250 npfunc = getattr(np, self.__name__, None)
251 doc = getattr(npfunc, '__doc__', None)
252 if doc:
253 sig = self.__name__ + ma.get_object_signature(npfunc)
254 doc = ma.doc_note(doc, "The function is applied to both the _data "
255 "and the _mask, if any.")
256 return '\n\n'.join((sig, doc))
257 return
259 def __call__(self, *args, **params):
260 pass
263class _fromnxfunction_single(_fromnxfunction):
264 """
265 A version of `_fromnxfunction` that is called with a single array
266 argument followed by auxiliary args that are passed verbatim for
267 both the data and mask calls.
268 """
269 def __call__(self, x, *args, **params):
270 func = getattr(np, self.__name__)
271 if isinstance(x, ndarray):
272 _d = func(x.__array__(), *args, **params)
273 _m = func(getmaskarray(x), *args, **params)
274 return masked_array(_d, mask=_m)
275 else:
276 _d = func(np.asarray(x), *args, **params)
277 _m = func(getmaskarray(x), *args, **params)
278 return masked_array(_d, mask=_m)
281class _fromnxfunction_seq(_fromnxfunction):
282 """
283 A version of `_fromnxfunction` that is called with a single sequence
284 of arrays followed by auxiliary args that are passed verbatim for
285 both the data and mask calls.
286 """
287 def __call__(self, x, *args, **params):
288 func = getattr(np, self.__name__)
289 _d = func(tuple([np.asarray(a) for a in x]), *args, **params)
290 _m = func(tuple([getmaskarray(a) for a in x]), *args, **params)
291 return masked_array(_d, mask=_m)
294class _fromnxfunction_args(_fromnxfunction):
295 """
296 A version of `_fromnxfunction` that is called with multiple array
297 arguments. The first non-array-like input marks the beginning of the
298 arguments that are passed verbatim for both the data and mask calls.
299 Array arguments are processed independently and the results are
300 returned in a list. If only one array is found, the return value is
301 just the processed array instead of a list.
302 """
303 def __call__(self, *args, **params):
304 func = getattr(np, self.__name__)
305 arrays = []
306 args = list(args)
307 while len(args) > 0 and issequence(args[0]):
308 arrays.append(args.pop(0))
309 res = []
310 for x in arrays:
311 _d = func(np.asarray(x), *args, **params)
312 _m = func(getmaskarray(x), *args, **params)
313 res.append(masked_array(_d, mask=_m))
314 if len(arrays) == 1:
315 return res[0]
316 return res
319class _fromnxfunction_allargs(_fromnxfunction):
320 """
321 A version of `_fromnxfunction` that is called with multiple array
322 arguments. Similar to `_fromnxfunction_args` except that all args
323 are converted to arrays even if they are not so already. This makes
324 it possible to process scalars as 1-D arrays. Only keyword arguments
325 are passed through verbatim for the data and mask calls. Arrays
326 arguments are processed independently and the results are returned
327 in a list. If only one arg is present, the return value is just the
328 processed array instead of a list.
329 """
330 def __call__(self, *args, **params):
331 func = getattr(np, self.__name__)
332 res = []
333 for x in args:
334 _d = func(np.asarray(x), **params)
335 _m = func(getmaskarray(x), **params)
336 res.append(masked_array(_d, mask=_m))
337 if len(args) == 1:
338 return res[0]
339 return res
342atleast_1d = _fromnxfunction_allargs('atleast_1d')
343atleast_2d = _fromnxfunction_allargs('atleast_2d')
344atleast_3d = _fromnxfunction_allargs('atleast_3d')
346vstack = row_stack = _fromnxfunction_seq('vstack')
347hstack = _fromnxfunction_seq('hstack')
348column_stack = _fromnxfunction_seq('column_stack')
349dstack = _fromnxfunction_seq('dstack')
350stack = _fromnxfunction_seq('stack')
352hsplit = _fromnxfunction_single('hsplit')
354diagflat = _fromnxfunction_single('diagflat')
357#####--------------------------------------------------------------------------
358#----
359#####--------------------------------------------------------------------------
360def flatten_inplace(seq):
361 """Flatten a sequence in place."""
362 k = 0
363 while (k != len(seq)):
364 while hasattr(seq[k], '__iter__'):
365 seq[k:(k + 1)] = seq[k]
366 k += 1
367 return seq
370def apply_along_axis(func1d, axis, arr, *args, **kwargs):
371 """
372 (This docstring should be overwritten)
373 """
374 arr = array(arr, copy=False, subok=True)
375 nd = arr.ndim
376 axis = normalize_axis_index(axis, nd)
377 ind = [0] * (nd - 1)
378 i = np.zeros(nd, 'O')
379 indlist = list(range(nd))
380 indlist.remove(axis)
381 i[axis] = slice(None, None)
382 outshape = np.asarray(arr.shape).take(indlist)
383 i.put(indlist, ind)
384 res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
385 # if res is a number, then we have a smaller output array
386 asscalar = np.isscalar(res)
387 if not asscalar:
388 try:
389 len(res)
390 except TypeError:
391 asscalar = True
392 # Note: we shouldn't set the dtype of the output from the first result
393 # so we force the type to object, and build a list of dtypes. We'll
394 # just take the largest, to avoid some downcasting
395 dtypes = []
396 if asscalar:
397 dtypes.append(np.asarray(res).dtype)
398 outarr = zeros(outshape, object)
399 outarr[tuple(ind)] = res
400 Ntot = np.prod(outshape)
401 k = 1
402 while k < Ntot:
403 # increment the index
404 ind[-1] += 1
405 n = -1
406 while (ind[n] >= outshape[n]) and (n > (1 - nd)):
407 ind[n - 1] += 1
408 ind[n] = 0
409 n -= 1
410 i.put(indlist, ind)
411 res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
412 outarr[tuple(ind)] = res
413 dtypes.append(asarray(res).dtype)
414 k += 1
415 else:
416 res = array(res, copy=False, subok=True)
417 j = i.copy()
418 j[axis] = ([slice(None, None)] * res.ndim)
419 j.put(indlist, ind)
420 Ntot = np.prod(outshape)
421 holdshape = outshape
422 outshape = list(arr.shape)
423 outshape[axis] = res.shape
424 dtypes.append(asarray(res).dtype)
425 outshape = flatten_inplace(outshape)
426 outarr = zeros(outshape, object)
427 outarr[tuple(flatten_inplace(j.tolist()))] = res
428 k = 1
429 while k < Ntot:
430 # increment the index
431 ind[-1] += 1
432 n = -1
433 while (ind[n] >= holdshape[n]) and (n > (1 - nd)):
434 ind[n - 1] += 1
435 ind[n] = 0
436 n -= 1
437 i.put(indlist, ind)
438 j.put(indlist, ind)
439 res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
440 outarr[tuple(flatten_inplace(j.tolist()))] = res
441 dtypes.append(asarray(res).dtype)
442 k += 1
443 max_dtypes = np.dtype(np.asarray(dtypes).max())
444 if not hasattr(arr, '_mask'):
445 result = np.asarray(outarr, dtype=max_dtypes)
446 else:
447 result = asarray(outarr, dtype=max_dtypes)
448 result.fill_value = ma.default_fill_value(result)
449 return result
450apply_along_axis.__doc__ = np.apply_along_axis.__doc__
453def apply_over_axes(func, a, axes):
454 """
455 (This docstring will be overwritten)
456 """
457 val = asarray(a)
458 N = a.ndim
459 if array(axes).ndim == 0:
460 axes = (axes,)
461 for axis in axes:
462 if axis < 0:
463 axis = N + axis
464 args = (val, axis)
465 res = func(*args)
466 if res.ndim == val.ndim:
467 val = res
468 else:
469 res = ma.expand_dims(res, axis)
470 if res.ndim == val.ndim:
471 val = res
472 else:
473 raise ValueError("function is not returning "
474 "an array of the correct shape")
475 return val
478if apply_over_axes.__doc__ is not None:
479 apply_over_axes.__doc__ = np.apply_over_axes.__doc__[
480 :np.apply_over_axes.__doc__.find('Notes')].rstrip() + \
481 """
483 Examples
484 --------
485 >>> a = np.ma.arange(24).reshape(2,3,4)
486 >>> a[:,0,1] = np.ma.masked
487 >>> a[:,1,:] = np.ma.masked
488 >>> a
489 masked_array(
490 data=[[[0, --, 2, 3],
491 [--, --, --, --],
492 [8, 9, 10, 11]],
493 [[12, --, 14, 15],
494 [--, --, --, --],
495 [20, 21, 22, 23]]],
496 mask=[[[False, True, False, False],
497 [ True, True, True, True],
498 [False, False, False, False]],
499 [[False, True, False, False],
500 [ True, True, True, True],
501 [False, False, False, False]]],
502 fill_value=999999)
503 >>> np.ma.apply_over_axes(np.ma.sum, a, [0,2])
504 masked_array(
505 data=[[[46],
506 [--],
507 [124]]],
508 mask=[[[False],
509 [ True],
510 [False]]],
511 fill_value=999999)
513 Tuple axis arguments to ufuncs are equivalent:
515 >>> np.ma.sum(a, axis=(0,2)).reshape((1,-1,1))
516 masked_array(
517 data=[[[46],
518 [--],
519 [124]]],
520 mask=[[[False],
521 [ True],
522 [False]]],
523 fill_value=999999)
524 """
527def average(a, axis=None, weights=None, returned=False, *,
528 keepdims=np._NoValue):
529 """
530 Return the weighted average of array over the given axis.
532 Parameters
533 ----------
534 a : array_like
535 Data to be averaged.
536 Masked entries are not taken into account in the computation.
537 axis : int, optional
538 Axis along which to average `a`. If None, averaging is done over
539 the flattened array.
540 weights : array_like, optional
541 The importance that each element has in the computation of the average.
542 The weights array can either be 1-D (in which case its length must be
543 the size of `a` along the given axis) or of the same shape as `a`.
544 If ``weights=None``, then all data in `a` are assumed to have a
545 weight equal to one. The 1-D calculation is::
547 avg = sum(a * weights) / sum(weights)
549 The only constraint on `weights` is that `sum(weights)` must not be 0.
550 returned : bool, optional
551 Flag indicating whether a tuple ``(result, sum of weights)``
552 should be returned as output (True), or just the result (False).
553 Default is False.
554 keepdims : bool, optional
555 If this is set to True, the axes which are reduced are left
556 in the result as dimensions with size one. With this option,
557 the result will broadcast correctly against the original `a`.
558 *Note:* `keepdims` will not work with instances of `numpy.matrix`
559 or other classes whose methods do not support `keepdims`.
561 .. versionadded:: 1.23.0
563 Returns
564 -------
565 average, [sum_of_weights] : (tuple of) scalar or MaskedArray
566 The average along the specified axis. When returned is `True`,
567 return a tuple with the average as the first element and the sum
568 of the weights as the second element. The return type is `np.float64`
569 if `a` is of integer type and floats smaller than `float64`, or the
570 input data-type, otherwise. If returned, `sum_of_weights` is always
571 `float64`.
573 Examples
574 --------
575 >>> a = np.ma.array([1., 2., 3., 4.], mask=[False, False, True, True])
576 >>> np.ma.average(a, weights=[3, 1, 0, 0])
577 1.25
579 >>> x = np.ma.arange(6.).reshape(3, 2)
580 >>> x
581 masked_array(
582 data=[[0., 1.],
583 [2., 3.],
584 [4., 5.]],
585 mask=False,
586 fill_value=1e+20)
587 >>> avg, sumweights = np.ma.average(x, axis=0, weights=[1, 2, 3],
588 ... returned=True)
589 >>> avg
590 masked_array(data=[2.6666666666666665, 3.6666666666666665],
591 mask=[False, False],
592 fill_value=1e+20)
594 With ``keepdims=True``, the following result has shape (3, 1).
596 >>> np.ma.average(x, axis=1, keepdims=True)
597 masked_array(
598 data=[[0.5],
599 [2.5],
600 [4.5]],
601 mask=False,
602 fill_value=1e+20)
603 """
604 a = asarray(a)
605 m = getmask(a)
607 # inspired by 'average' in numpy/lib/function_base.py
609 if keepdims is np._NoValue:
610 # Don't pass on the keepdims argument if one wasn't given.
611 keepdims_kw = {}
612 else:
613 keepdims_kw = {'keepdims': keepdims}
615 if weights is None:
616 avg = a.mean(axis, **keepdims_kw)
617 scl = avg.dtype.type(a.count(axis))
618 else:
619 wgt = asarray(weights)
621 if issubclass(a.dtype.type, (np.integer, np.bool_)):
622 result_dtype = np.result_type(a.dtype, wgt.dtype, 'f8')
623 else:
624 result_dtype = np.result_type(a.dtype, wgt.dtype)
626 # Sanity checks
627 if a.shape != wgt.shape:
628 if axis is None:
629 raise TypeError(
630 "Axis must be specified when shapes of a and weights "
631 "differ.")
632 if wgt.ndim != 1:
633 raise TypeError(
634 "1D weights expected when shapes of a and weights differ.")
635 if wgt.shape[0] != a.shape[axis]:
636 raise ValueError(
637 "Length of weights not compatible with specified axis.")
639 # setup wgt to broadcast along axis
640 wgt = np.broadcast_to(wgt, (a.ndim-1)*(1,) + wgt.shape, subok=True)
641 wgt = wgt.swapaxes(-1, axis)
643 if m is not nomask:
644 wgt = wgt*(~a.mask)
645 wgt.mask |= a.mask
647 scl = wgt.sum(axis=axis, dtype=result_dtype, **keepdims_kw)
648 avg = np.multiply(a, wgt,
649 dtype=result_dtype).sum(axis, **keepdims_kw) / scl
651 if returned:
652 if scl.shape != avg.shape:
653 scl = np.broadcast_to(scl, avg.shape).copy()
654 return avg, scl
655 else:
656 return avg
659def median(a, axis=None, out=None, overwrite_input=False, keepdims=False):
660 """
661 Compute the median along the specified axis.
663 Returns the median of the array elements.
665 Parameters
666 ----------
667 a : array_like
668 Input array or object that can be converted to an array.
669 axis : int, optional
670 Axis along which the medians are computed. The default (None) is
671 to compute the median along a flattened version of the array.
672 out : ndarray, optional
673 Alternative output array in which to place the result. It must
674 have the same shape and buffer length as the expected output
675 but the type will be cast if necessary.
676 overwrite_input : bool, optional
677 If True, then allow use of memory of input array (a) for
678 calculations. The input array will be modified by the call to
679 median. This will save memory when you do not need to preserve
680 the contents of the input array. Treat the input as undefined,
681 but it will probably be fully or partially sorted. Default is
682 False. Note that, if `overwrite_input` is True, and the input
683 is not already an `ndarray`, an error will be raised.
684 keepdims : bool, optional
685 If this is set to True, the axes which are reduced are left
686 in the result as dimensions with size one. With this option,
687 the result will broadcast correctly against the input array.
689 .. versionadded:: 1.10.0
691 Returns
692 -------
693 median : ndarray
694 A new array holding the result is returned unless out is
695 specified, in which case a reference to out is returned.
696 Return data-type is `float64` for integers and floats smaller than
697 `float64`, or the input data-type, otherwise.
699 See Also
700 --------
701 mean
703 Notes
704 -----
705 Given a vector ``V`` with ``N`` non masked values, the median of ``V``
706 is the middle value of a sorted copy of ``V`` (``Vs``) - i.e.
707 ``Vs[(N-1)/2]``, when ``N`` is odd, or ``{Vs[N/2 - 1] + Vs[N/2]}/2``
708 when ``N`` is even.
710 Examples
711 --------
712 >>> x = np.ma.array(np.arange(8), mask=[0]*4 + [1]*4)
713 >>> np.ma.median(x)
714 1.5
716 >>> x = np.ma.array(np.arange(10).reshape(2, 5), mask=[0]*6 + [1]*4)
717 >>> np.ma.median(x)
718 2.5
719 >>> np.ma.median(x, axis=-1, overwrite_input=True)
720 masked_array(data=[2.0, 5.0],
721 mask=[False, False],
722 fill_value=1e+20)
724 """
725 if not hasattr(a, 'mask'):
726 m = np.median(getdata(a, subok=True), axis=axis,
727 out=out, overwrite_input=overwrite_input,
728 keepdims=keepdims)
729 if isinstance(m, np.ndarray) and 1 <= m.ndim:
730 return masked_array(m, copy=False)
731 else:
732 return m
734 return _ureduce(a, func=_median, keepdims=keepdims, axis=axis, out=out,
735 overwrite_input=overwrite_input)
738def _median(a, axis=None, out=None, overwrite_input=False):
739 # when an unmasked NaN is present return it, so we need to sort the NaN
740 # values behind the mask
741 if np.issubdtype(a.dtype, np.inexact):
742 fill_value = np.inf
743 else:
744 fill_value = None
745 if overwrite_input:
746 if axis is None:
747 asorted = a.ravel()
748 asorted.sort(fill_value=fill_value)
749 else:
750 a.sort(axis=axis, fill_value=fill_value)
751 asorted = a
752 else:
753 asorted = sort(a, axis=axis, fill_value=fill_value)
755 if axis is None:
756 axis = 0
757 else:
758 axis = normalize_axis_index(axis, asorted.ndim)
760 if asorted.shape[axis] == 0:
761 # for empty axis integer indices fail so use slicing to get same result
762 # as median (which is mean of empty slice = nan)
763 indexer = [slice(None)] * asorted.ndim
764 indexer[axis] = slice(0, 0)
765 indexer = tuple(indexer)
766 return np.ma.mean(asorted[indexer], axis=axis, out=out)
768 if asorted.ndim == 1:
769 idx, odd = divmod(count(asorted), 2)
770 mid = asorted[idx + odd - 1:idx + 1]
771 if np.issubdtype(asorted.dtype, np.inexact) and asorted.size > 0:
772 # avoid inf / x = masked
773 s = mid.sum(out=out)
774 if not odd:
775 s = np.true_divide(s, 2., casting='safe', out=out)
776 s = np.lib.utils._median_nancheck(asorted, s, axis)
777 else:
778 s = mid.mean(out=out)
780 # if result is masked either the input contained enough
781 # minimum_fill_value so that it would be the median or all values
782 # masked
783 if np.ma.is_masked(s) and not np.all(asorted.mask):
784 return np.ma.minimum_fill_value(asorted)
785 return s
787 counts = count(asorted, axis=axis, keepdims=True)
788 h = counts // 2
790 # duplicate high if odd number of elements so mean does nothing
791 odd = counts % 2 == 1
792 l = np.where(odd, h, h-1)
794 lh = np.concatenate([l,h], axis=axis)
796 # get low and high median
797 low_high = np.take_along_axis(asorted, lh, axis=axis)
799 def replace_masked(s):
800 # Replace masked entries with minimum_full_value unless it all values
801 # are masked. This is required as the sort order of values equal or
802 # larger than the fill value is undefined and a valid value placed
803 # elsewhere, e.g. [4, --, inf].
804 if np.ma.is_masked(s):
805 rep = (~np.all(asorted.mask, axis=axis, keepdims=True)) & s.mask
806 s.data[rep] = np.ma.minimum_fill_value(asorted)
807 s.mask[rep] = False
809 replace_masked(low_high)
811 if np.issubdtype(asorted.dtype, np.inexact):
812 # avoid inf / x = masked
813 s = np.ma.sum(low_high, axis=axis, out=out)
814 np.true_divide(s.data, 2., casting='unsafe', out=s.data)
816 s = np.lib.utils._median_nancheck(asorted, s, axis)
817 else:
818 s = np.ma.mean(low_high, axis=axis, out=out)
820 return s
823def compress_nd(x, axis=None):
824 """Suppress slices from multiple dimensions which contain masked values.
826 Parameters
827 ----------
828 x : array_like, MaskedArray
829 The array to operate on. If not a MaskedArray instance (or if no array
830 elements are masked), `x` is interpreted as a MaskedArray with `mask`
831 set to `nomask`.
832 axis : tuple of ints or int, optional
833 Which dimensions to suppress slices from can be configured with this
834 parameter.
835 - If axis is a tuple of ints, those are the axes to suppress slices from.
836 - If axis is an int, then that is the only axis to suppress slices from.
837 - If axis is None, all axis are selected.
839 Returns
840 -------
841 compress_array : ndarray
842 The compressed array.
843 """
844 x = asarray(x)
845 m = getmask(x)
846 # Set axis to tuple of ints
847 if axis is None:
848 axis = tuple(range(x.ndim))
849 else:
850 axis = normalize_axis_tuple(axis, x.ndim)
852 # Nothing is masked: return x
853 if m is nomask or not m.any():
854 return x._data
855 # All is masked: return empty
856 if m.all():
857 return nxarray([])
858 # Filter elements through boolean indexing
859 data = x._data
860 for ax in axis:
861 axes = tuple(list(range(ax)) + list(range(ax + 1, x.ndim)))
862 data = data[(slice(None),)*ax + (~m.any(axis=axes),)]
863 return data
866def compress_rowcols(x, axis=None):
867 """
868 Suppress the rows and/or columns of a 2-D array that contain
869 masked values.
871 The suppression behavior is selected with the `axis` parameter.
873 - If axis is None, both rows and columns are suppressed.
874 - If axis is 0, only rows are suppressed.
875 - If axis is 1 or -1, only columns are suppressed.
877 Parameters
878 ----------
879 x : array_like, MaskedArray
880 The array to operate on. If not a MaskedArray instance (or if no array
881 elements are masked), `x` is interpreted as a MaskedArray with
882 `mask` set to `nomask`. Must be a 2D array.
883 axis : int, optional
884 Axis along which to perform the operation. Default is None.
886 Returns
887 -------
888 compressed_array : ndarray
889 The compressed array.
891 Examples
892 --------
893 >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0],
894 ... [1, 0, 0],
895 ... [0, 0, 0]])
896 >>> x
897 masked_array(
898 data=[[--, 1, 2],
899 [--, 4, 5],
900 [6, 7, 8]],
901 mask=[[ True, False, False],
902 [ True, False, False],
903 [False, False, False]],
904 fill_value=999999)
906 >>> np.ma.compress_rowcols(x)
907 array([[7, 8]])
908 >>> np.ma.compress_rowcols(x, 0)
909 array([[6, 7, 8]])
910 >>> np.ma.compress_rowcols(x, 1)
911 array([[1, 2],
912 [4, 5],
913 [7, 8]])
915 """
916 if asarray(x).ndim != 2:
917 raise NotImplementedError("compress_rowcols works for 2D arrays only.")
918 return compress_nd(x, axis=axis)
921def compress_rows(a):
922 """
923 Suppress whole rows of a 2-D array that contain masked values.
925 This is equivalent to ``np.ma.compress_rowcols(a, 0)``, see
926 `compress_rowcols` for details.
928 See Also
929 --------
930 compress_rowcols
932 """
933 a = asarray(a)
934 if a.ndim != 2:
935 raise NotImplementedError("compress_rows works for 2D arrays only.")
936 return compress_rowcols(a, 0)
939def compress_cols(a):
940 """
941 Suppress whole columns of a 2-D array that contain masked values.
943 This is equivalent to ``np.ma.compress_rowcols(a, 1)``, see
944 `compress_rowcols` for details.
946 See Also
947 --------
948 compress_rowcols
950 """
951 a = asarray(a)
952 if a.ndim != 2:
953 raise NotImplementedError("compress_cols works for 2D arrays only.")
954 return compress_rowcols(a, 1)
957def mask_rowcols(a, axis=None):
958 """
959 Mask rows and/or columns of a 2D array that contain masked values.
961 Mask whole rows and/or columns of a 2D array that contain
962 masked values. The masking behavior is selected using the
963 `axis` parameter.
965 - If `axis` is None, rows *and* columns are masked.
966 - If `axis` is 0, only rows are masked.
967 - If `axis` is 1 or -1, only columns are masked.
969 Parameters
970 ----------
971 a : array_like, MaskedArray
972 The array to mask. If not a MaskedArray instance (or if no array
973 elements are masked), the result is a MaskedArray with `mask` set
974 to `nomask` (False). Must be a 2D array.
975 axis : int, optional
976 Axis along which to perform the operation. If None, applies to a
977 flattened version of the array.
979 Returns
980 -------
981 a : MaskedArray
982 A modified version of the input array, masked depending on the value
983 of the `axis` parameter.
985 Raises
986 ------
987 NotImplementedError
988 If input array `a` is not 2D.
990 See Also
991 --------
992 mask_rows : Mask rows of a 2D array that contain masked values.
993 mask_cols : Mask cols of a 2D array that contain masked values.
994 masked_where : Mask where a condition is met.
996 Notes
997 -----
998 The input array's mask is modified by this function.
1000 Examples
1001 --------
1002 >>> import numpy.ma as ma
1003 >>> a = np.zeros((3, 3), dtype=int)
1004 >>> a[1, 1] = 1
1005 >>> a
1006 array([[0, 0, 0],
1007 [0, 1, 0],
1008 [0, 0, 0]])
1009 >>> a = ma.masked_equal(a, 1)
1010 >>> a
1011 masked_array(
1012 data=[[0, 0, 0],
1013 [0, --, 0],
1014 [0, 0, 0]],
1015 mask=[[False, False, False],
1016 [False, True, False],
1017 [False, False, False]],
1018 fill_value=1)
1019 >>> ma.mask_rowcols(a)
1020 masked_array(
1021 data=[[0, --, 0],
1022 [--, --, --],
1023 [0, --, 0]],
1024 mask=[[False, True, False],
1025 [ True, True, True],
1026 [False, True, False]],
1027 fill_value=1)
1029 """
1030 a = array(a, subok=False)
1031 if a.ndim != 2:
1032 raise NotImplementedError("mask_rowcols works for 2D arrays only.")
1033 m = getmask(a)
1034 # Nothing is masked: return a
1035 if m is nomask or not m.any():
1036 return a
1037 maskedval = m.nonzero()
1038 a._mask = a._mask.copy()
1039 if not axis:
1040 a[np.unique(maskedval[0])] = masked
1041 if axis in [None, 1, -1]:
1042 a[:, np.unique(maskedval[1])] = masked
1043 return a
1046def mask_rows(a, axis=np._NoValue):
1047 """
1048 Mask rows of a 2D array that contain masked values.
1050 This function is a shortcut to ``mask_rowcols`` with `axis` equal to 0.
1052 See Also
1053 --------
1054 mask_rowcols : Mask rows and/or columns of a 2D array.
1055 masked_where : Mask where a condition is met.
1057 Examples
1058 --------
1059 >>> import numpy.ma as ma
1060 >>> a = np.zeros((3, 3), dtype=int)
1061 >>> a[1, 1] = 1
1062 >>> a
1063 array([[0, 0, 0],
1064 [0, 1, 0],
1065 [0, 0, 0]])
1066 >>> a = ma.masked_equal(a, 1)
1067 >>> a
1068 masked_array(
1069 data=[[0, 0, 0],
1070 [0, --, 0],
1071 [0, 0, 0]],
1072 mask=[[False, False, False],
1073 [False, True, False],
1074 [False, False, False]],
1075 fill_value=1)
1077 >>> ma.mask_rows(a)
1078 masked_array(
1079 data=[[0, 0, 0],
1080 [--, --, --],
1081 [0, 0, 0]],
1082 mask=[[False, False, False],
1083 [ True, True, True],
1084 [False, False, False]],
1085 fill_value=1)
1087 """
1088 if axis is not np._NoValue:
1089 # remove the axis argument when this deprecation expires
1090 # NumPy 1.18.0, 2019-11-28
1091 warnings.warn(
1092 "The axis argument has always been ignored, in future passing it "
1093 "will raise TypeError", DeprecationWarning, stacklevel=2)
1094 return mask_rowcols(a, 0)
1097def mask_cols(a, axis=np._NoValue):
1098 """
1099 Mask columns of a 2D array that contain masked values.
1101 This function is a shortcut to ``mask_rowcols`` with `axis` equal to 1.
1103 See Also
1104 --------
1105 mask_rowcols : Mask rows and/or columns of a 2D array.
1106 masked_where : Mask where a condition is met.
1108 Examples
1109 --------
1110 >>> import numpy.ma as ma
1111 >>> a = np.zeros((3, 3), dtype=int)
1112 >>> a[1, 1] = 1
1113 >>> a
1114 array([[0, 0, 0],
1115 [0, 1, 0],
1116 [0, 0, 0]])
1117 >>> a = ma.masked_equal(a, 1)
1118 >>> a
1119 masked_array(
1120 data=[[0, 0, 0],
1121 [0, --, 0],
1122 [0, 0, 0]],
1123 mask=[[False, False, False],
1124 [False, True, False],
1125 [False, False, False]],
1126 fill_value=1)
1127 >>> ma.mask_cols(a)
1128 masked_array(
1129 data=[[0, --, 0],
1130 [0, --, 0],
1131 [0, --, 0]],
1132 mask=[[False, True, False],
1133 [False, True, False],
1134 [False, True, False]],
1135 fill_value=1)
1137 """
1138 if axis is not np._NoValue:
1139 # remove the axis argument when this deprecation expires
1140 # NumPy 1.18.0, 2019-11-28
1141 warnings.warn(
1142 "The axis argument has always been ignored, in future passing it "
1143 "will raise TypeError", DeprecationWarning, stacklevel=2)
1144 return mask_rowcols(a, 1)
1147#####--------------------------------------------------------------------------
1148#---- --- arraysetops ---
1149#####--------------------------------------------------------------------------
1151def ediff1d(arr, to_end=None, to_begin=None):
1152 """
1153 Compute the differences between consecutive elements of an array.
1155 This function is the equivalent of `numpy.ediff1d` that takes masked
1156 values into account, see `numpy.ediff1d` for details.
1158 See Also
1159 --------
1160 numpy.ediff1d : Equivalent function for ndarrays.
1162 """
1163 arr = ma.asanyarray(arr).flat
1164 ed = arr[1:] - arr[:-1]
1165 arrays = [ed]
1166 #
1167 if to_begin is not None:
1168 arrays.insert(0, to_begin)
1169 if to_end is not None:
1170 arrays.append(to_end)
1171 #
1172 if len(arrays) != 1:
1173 # We'll save ourselves a copy of a potentially large array in the common
1174 # case where neither to_begin or to_end was given.
1175 ed = hstack(arrays)
1176 #
1177 return ed
1180def unique(ar1, return_index=False, return_inverse=False):
1181 """
1182 Finds the unique elements of an array.
1184 Masked values are considered the same element (masked). The output array
1185 is always a masked array. See `numpy.unique` for more details.
1187 See Also
1188 --------
1189 numpy.unique : Equivalent function for ndarrays.
1191 Examples
1192 --------
1193 >>> import numpy.ma as ma
1194 >>> a = [1, 2, 1000, 2, 3]
1195 >>> mask = [0, 0, 1, 0, 0]
1196 >>> masked_a = ma.masked_array(a, mask)
1197 >>> masked_a
1198 masked_array(data=[1, 2, --, 2, 3],
1199 mask=[False, False, True, False, False],
1200 fill_value=999999)
1201 >>> ma.unique(masked_a)
1202 masked_array(data=[1, 2, 3, --],
1203 mask=[False, False, False, True],
1204 fill_value=999999)
1205 >>> ma.unique(masked_a, return_index=True)
1206 (masked_array(data=[1, 2, 3, --],
1207 mask=[False, False, False, True],
1208 fill_value=999999), array([0, 1, 4, 2]))
1209 >>> ma.unique(masked_a, return_inverse=True)
1210 (masked_array(data=[1, 2, 3, --],
1211 mask=[False, False, False, True],
1212 fill_value=999999), array([0, 1, 3, 1, 2]))
1213 >>> ma.unique(masked_a, return_index=True, return_inverse=True)
1214 (masked_array(data=[1, 2, 3, --],
1215 mask=[False, False, False, True],
1216 fill_value=999999), array([0, 1, 4, 2]), array([0, 1, 3, 1, 2]))
1217 """
1218 output = np.unique(ar1,
1219 return_index=return_index,
1220 return_inverse=return_inverse)
1221 if isinstance(output, tuple):
1222 output = list(output)
1223 output[0] = output[0].view(MaskedArray)
1224 output = tuple(output)
1225 else:
1226 output = output.view(MaskedArray)
1227 return output
1230def intersect1d(ar1, ar2, assume_unique=False):
1231 """
1232 Returns the unique elements common to both arrays.
1234 Masked values are considered equal one to the other.
1235 The output is always a masked array.
1237 See `numpy.intersect1d` for more details.
1239 See Also
1240 --------
1241 numpy.intersect1d : Equivalent function for ndarrays.
1243 Examples
1244 --------
1245 >>> x = np.ma.array([1, 3, 3, 3], mask=[0, 0, 0, 1])
1246 >>> y = np.ma.array([3, 1, 1, 1], mask=[0, 0, 0, 1])
1247 >>> np.ma.intersect1d(x, y)
1248 masked_array(data=[1, 3, --],
1249 mask=[False, False, True],
1250 fill_value=999999)
1252 """
1253 if assume_unique:
1254 aux = ma.concatenate((ar1, ar2))
1255 else:
1256 # Might be faster than unique( intersect1d( ar1, ar2 ) )?
1257 aux = ma.concatenate((unique(ar1), unique(ar2)))
1258 aux.sort()
1259 return aux[:-1][aux[1:] == aux[:-1]]
1262def setxor1d(ar1, ar2, assume_unique=False):
1263 """
1264 Set exclusive-or of 1-D arrays with unique elements.
1266 The output is always a masked array. See `numpy.setxor1d` for more details.
1268 See Also
1269 --------
1270 numpy.setxor1d : Equivalent function for ndarrays.
1272 """
1273 if not assume_unique:
1274 ar1 = unique(ar1)
1275 ar2 = unique(ar2)
1277 aux = ma.concatenate((ar1, ar2))
1278 if aux.size == 0:
1279 return aux
1280 aux.sort()
1281 auxf = aux.filled()
1282# flag = ediff1d( aux, to_end = 1, to_begin = 1 ) == 0
1283 flag = ma.concatenate(([True], (auxf[1:] != auxf[:-1]), [True]))
1284# flag2 = ediff1d( flag ) == 0
1285 flag2 = (flag[1:] == flag[:-1])
1286 return aux[flag2]
1289def in1d(ar1, ar2, assume_unique=False, invert=False):
1290 """
1291 Test whether each element of an array is also present in a second
1292 array.
1294 The output is always a masked array. See `numpy.in1d` for more details.
1296 We recommend using :func:`isin` instead of `in1d` for new code.
1298 See Also
1299 --------
1300 isin : Version of this function that preserves the shape of ar1.
1301 numpy.in1d : Equivalent function for ndarrays.
1303 Notes
1304 -----
1305 .. versionadded:: 1.4.0
1307 """
1308 if not assume_unique:
1309 ar1, rev_idx = unique(ar1, return_inverse=True)
1310 ar2 = unique(ar2)
1312 ar = ma.concatenate((ar1, ar2))
1313 # We need this to be a stable sort, so always use 'mergesort'
1314 # here. The values from the first array should always come before
1315 # the values from the second array.
1316 order = ar.argsort(kind='mergesort')
1317 sar = ar[order]
1318 if invert:
1319 bool_ar = (sar[1:] != sar[:-1])
1320 else:
1321 bool_ar = (sar[1:] == sar[:-1])
1322 flag = ma.concatenate((bool_ar, [invert]))
1323 indx = order.argsort(kind='mergesort')[:len(ar1)]
1325 if assume_unique:
1326 return flag[indx]
1327 else:
1328 return flag[indx][rev_idx]
1331def isin(element, test_elements, assume_unique=False, invert=False):
1332 """
1333 Calculates `element in test_elements`, broadcasting over
1334 `element` only.
1336 The output is always a masked array of the same shape as `element`.
1337 See `numpy.isin` for more details.
1339 See Also
1340 --------
1341 in1d : Flattened version of this function.
1342 numpy.isin : Equivalent function for ndarrays.
1344 Notes
1345 -----
1346 .. versionadded:: 1.13.0
1348 """
1349 element = ma.asarray(element)
1350 return in1d(element, test_elements, assume_unique=assume_unique,
1351 invert=invert).reshape(element.shape)
1354def union1d(ar1, ar2):
1355 """
1356 Union of two arrays.
1358 The output is always a masked array. See `numpy.union1d` for more details.
1360 See Also
1361 --------
1362 numpy.union1d : Equivalent function for ndarrays.
1364 """
1365 return unique(ma.concatenate((ar1, ar2), axis=None))
1368def setdiff1d(ar1, ar2, assume_unique=False):
1369 """
1370 Set difference of 1D arrays with unique elements.
1372 The output is always a masked array. See `numpy.setdiff1d` for more
1373 details.
1375 See Also
1376 --------
1377 numpy.setdiff1d : Equivalent function for ndarrays.
1379 Examples
1380 --------
1381 >>> x = np.ma.array([1, 2, 3, 4], mask=[0, 1, 0, 1])
1382 >>> np.ma.setdiff1d(x, [1, 2])
1383 masked_array(data=[3, --],
1384 mask=[False, True],
1385 fill_value=999999)
1387 """
1388 if assume_unique:
1389 ar1 = ma.asarray(ar1).ravel()
1390 else:
1391 ar1 = unique(ar1)
1392 ar2 = unique(ar2)
1393 return ar1[in1d(ar1, ar2, assume_unique=True, invert=True)]
1396###############################################################################
1397# Covariance #
1398###############################################################################
1401def _covhelper(x, y=None, rowvar=True, allow_masked=True):
1402 """
1403 Private function for the computation of covariance and correlation
1404 coefficients.
1406 """
1407 x = ma.array(x, ndmin=2, copy=True, dtype=float)
1408 xmask = ma.getmaskarray(x)
1409 # Quick exit if we can't process masked data
1410 if not allow_masked and xmask.any():
1411 raise ValueError("Cannot process masked data.")
1412 #
1413 if x.shape[0] == 1:
1414 rowvar = True
1415 # Make sure that rowvar is either 0 or 1
1416 rowvar = int(bool(rowvar))
1417 axis = 1 - rowvar
1418 if rowvar:
1419 tup = (slice(None), None)
1420 else:
1421 tup = (None, slice(None))
1422 #
1423 if y is None:
1424 xnotmask = np.logical_not(xmask).astype(int)
1425 else:
1426 y = array(y, copy=False, ndmin=2, dtype=float)
1427 ymask = ma.getmaskarray(y)
1428 if not allow_masked and ymask.any():
1429 raise ValueError("Cannot process masked data.")
1430 if xmask.any() or ymask.any():
1431 if y.shape == x.shape:
1432 # Define some common mask
1433 common_mask = np.logical_or(xmask, ymask)
1434 if common_mask is not nomask:
1435 xmask = x._mask = y._mask = ymask = common_mask
1436 x._sharedmask = False
1437 y._sharedmask = False
1438 x = ma.concatenate((x, y), axis)
1439 xnotmask = np.logical_not(np.concatenate((xmask, ymask), axis)).astype(int)
1440 x -= x.mean(axis=rowvar)[tup]
1441 return (x, xnotmask, rowvar)
1444def cov(x, y=None, rowvar=True, bias=False, allow_masked=True, ddof=None):
1445 """
1446 Estimate the covariance matrix.
1448 Except for the handling of missing data this function does the same as
1449 `numpy.cov`. For more details and examples, see `numpy.cov`.
1451 By default, masked values are recognized as such. If `x` and `y` have the
1452 same shape, a common mask is allocated: if ``x[i,j]`` is masked, then
1453 ``y[i,j]`` will also be masked.
1454 Setting `allow_masked` to False will raise an exception if values are
1455 missing in either of the input arrays.
1457 Parameters
1458 ----------
1459 x : array_like
1460 A 1-D or 2-D array containing multiple variables and observations.
1461 Each row of `x` represents a variable, and each column a single
1462 observation of all those variables. Also see `rowvar` below.
1463 y : array_like, optional
1464 An additional set of variables and observations. `y` has the same
1465 shape as `x`.
1466 rowvar : bool, optional
1467 If `rowvar` is True (default), then each row represents a
1468 variable, with observations in the columns. Otherwise, the relationship
1469 is transposed: each column represents a variable, while the rows
1470 contain observations.
1471 bias : bool, optional
1472 Default normalization (False) is by ``(N-1)``, where ``N`` is the
1473 number of observations given (unbiased estimate). If `bias` is True,
1474 then normalization is by ``N``. This keyword can be overridden by
1475 the keyword ``ddof`` in numpy versions >= 1.5.
1476 allow_masked : bool, optional
1477 If True, masked values are propagated pair-wise: if a value is masked
1478 in `x`, the corresponding value is masked in `y`.
1479 If False, raises a `ValueError` exception when some values are missing.
1480 ddof : {None, int}, optional
1481 If not ``None`` normalization is by ``(N - ddof)``, where ``N`` is
1482 the number of observations; this overrides the value implied by
1483 ``bias``. The default value is ``None``.
1485 .. versionadded:: 1.5
1487 Raises
1488 ------
1489 ValueError
1490 Raised if some values are missing and `allow_masked` is False.
1492 See Also
1493 --------
1494 numpy.cov
1496 """
1497 # Check inputs
1498 if ddof is not None and ddof != int(ddof):
1499 raise ValueError("ddof must be an integer")
1500 # Set up ddof
1501 if ddof is None:
1502 if bias:
1503 ddof = 0
1504 else:
1505 ddof = 1
1507 (x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked)
1508 if not rowvar:
1509 fact = np.dot(xnotmask.T, xnotmask) * 1. - ddof
1510 result = (dot(x.T, x.conj(), strict=False) / fact).squeeze()
1511 else:
1512 fact = np.dot(xnotmask, xnotmask.T) * 1. - ddof
1513 result = (dot(x, x.T.conj(), strict=False) / fact).squeeze()
1514 return result
1517def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, allow_masked=True,
1518 ddof=np._NoValue):
1519 """
1520 Return Pearson product-moment correlation coefficients.
1522 Except for the handling of missing data this function does the same as
1523 `numpy.corrcoef`. For more details and examples, see `numpy.corrcoef`.
1525 Parameters
1526 ----------
1527 x : array_like
1528 A 1-D or 2-D array containing multiple variables and observations.
1529 Each row of `x` represents a variable, and each column a single
1530 observation of all those variables. Also see `rowvar` below.
1531 y : array_like, optional
1532 An additional set of variables and observations. `y` has the same
1533 shape as `x`.
1534 rowvar : bool, optional
1535 If `rowvar` is True (default), then each row represents a
1536 variable, with observations in the columns. Otherwise, the relationship
1537 is transposed: each column represents a variable, while the rows
1538 contain observations.
1539 bias : _NoValue, optional
1540 Has no effect, do not use.
1542 .. deprecated:: 1.10.0
1543 allow_masked : bool, optional
1544 If True, masked values are propagated pair-wise: if a value is masked
1545 in `x`, the corresponding value is masked in `y`.
1546 If False, raises an exception. Because `bias` is deprecated, this
1547 argument needs to be treated as keyword only to avoid a warning.
1548 ddof : _NoValue, optional
1549 Has no effect, do not use.
1551 .. deprecated:: 1.10.0
1553 See Also
1554 --------
1555 numpy.corrcoef : Equivalent function in top-level NumPy module.
1556 cov : Estimate the covariance matrix.
1558 Notes
1559 -----
1560 This function accepts but discards arguments `bias` and `ddof`. This is
1561 for backwards compatibility with previous versions of this function. These
1562 arguments had no effect on the return values of the function and can be
1563 safely ignored in this and previous versions of numpy.
1564 """
1565 msg = 'bias and ddof have no effect and are deprecated'
1566 if bias is not np._NoValue or ddof is not np._NoValue:
1567 # 2015-03-15, 1.10
1568 warnings.warn(msg, DeprecationWarning, stacklevel=2)
1569 # Get the data
1570 (x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked)
1571 # Compute the covariance matrix
1572 if not rowvar:
1573 fact = np.dot(xnotmask.T, xnotmask) * 1.
1574 c = (dot(x.T, x.conj(), strict=False) / fact).squeeze()
1575 else:
1576 fact = np.dot(xnotmask, xnotmask.T) * 1.
1577 c = (dot(x, x.T.conj(), strict=False) / fact).squeeze()
1578 # Check whether we have a scalar
1579 try:
1580 diag = ma.diagonal(c)
1581 except ValueError:
1582 return 1
1583 #
1584 if xnotmask.all():
1585 _denom = ma.sqrt(ma.multiply.outer(diag, diag))
1586 else:
1587 _denom = diagflat(diag)
1588 _denom._sharedmask = False # We know return is always a copy
1589 n = x.shape[1 - rowvar]
1590 if rowvar:
1591 for i in range(n - 1):
1592 for j in range(i + 1, n):
1593 _x = mask_cols(vstack((x[i], x[j]))).var(axis=1)
1594 _denom[i, j] = _denom[j, i] = ma.sqrt(ma.multiply.reduce(_x))
1595 else:
1596 for i in range(n - 1):
1597 for j in range(i + 1, n):
1598 _x = mask_cols(
1599 vstack((x[:, i], x[:, j]))).var(axis=1)
1600 _denom[i, j] = _denom[j, i] = ma.sqrt(ma.multiply.reduce(_x))
1601 return c / _denom
1603#####--------------------------------------------------------------------------
1604#---- --- Concatenation helpers ---
1605#####--------------------------------------------------------------------------
1607class MAxisConcatenator(AxisConcatenator):
1608 """
1609 Translate slice objects to concatenation along an axis.
1611 For documentation on usage, see `mr_class`.
1613 See Also
1614 --------
1615 mr_class
1617 """
1618 concatenate = staticmethod(concatenate)
1620 @classmethod
1621 def makemat(cls, arr):
1622 # There used to be a view as np.matrix here, but we may eventually
1623 # deprecate that class. In preparation, we use the unmasked version
1624 # to construct the matrix (with copy=False for backwards compatibility
1625 # with the .view)
1626 data = super().makemat(arr.data, copy=False)
1627 return array(data, mask=arr.mask)
1629 def __getitem__(self, key):
1630 # matrix builder syntax, like 'a, b; c, d'
1631 if isinstance(key, str):
1632 raise MAError("Unavailable for masked array.")
1634 return super().__getitem__(key)
1637class mr_class(MAxisConcatenator):
1638 """
1639 Translate slice objects to concatenation along the first axis.
1641 This is the masked array version of `lib.index_tricks.RClass`.
1643 See Also
1644 --------
1645 lib.index_tricks.RClass
1647 Examples
1648 --------
1649 >>> np.ma.mr_[np.ma.array([1,2,3]), 0, 0, np.ma.array([4,5,6])]
1650 masked_array(data=[1, 2, 3, ..., 4, 5, 6],
1651 mask=False,
1652 fill_value=999999)
1654 """
1655 def __init__(self):
1656 MAxisConcatenator.__init__(self, 0)
1658mr_ = mr_class()
1661#####--------------------------------------------------------------------------
1662#---- Find unmasked data ---
1663#####--------------------------------------------------------------------------
1665def ndenumerate(a, compressed=True):
1666 """
1667 Multidimensional index iterator.
1669 Return an iterator yielding pairs of array coordinates and values,
1670 skipping elements that are masked. With `compressed=False`,
1671 `ma.masked` is yielded as the value of masked elements. This
1672 behavior differs from that of `numpy.ndenumerate`, which yields the
1673 value of the underlying data array.
1675 Notes
1676 -----
1677 .. versionadded:: 1.23.0
1679 Parameters
1680 ----------
1681 a : array_like
1682 An array with (possibly) masked elements.
1683 compressed : bool, optional
1684 If True (default), masked elements are skipped.
1686 See Also
1687 --------
1688 numpy.ndenumerate : Equivalent function ignoring any mask.
1690 Examples
1691 --------
1692 >>> a = np.ma.arange(9).reshape((3, 3))
1693 >>> a[1, 0] = np.ma.masked
1694 >>> a[1, 2] = np.ma.masked
1695 >>> a[2, 1] = np.ma.masked
1696 >>> a
1697 masked_array(
1698 data=[[0, 1, 2],
1699 [--, 4, --],
1700 [6, --, 8]],
1701 mask=[[False, False, False],
1702 [ True, False, True],
1703 [False, True, False]],
1704 fill_value=999999)
1705 >>> for index, x in np.ma.ndenumerate(a):
1706 ... print(index, x)
1707 (0, 0) 0
1708 (0, 1) 1
1709 (0, 2) 2
1710 (1, 1) 4
1711 (2, 0) 6
1712 (2, 2) 8
1714 >>> for index, x in np.ma.ndenumerate(a, compressed=False):
1715 ... print(index, x)
1716 (0, 0) 0
1717 (0, 1) 1
1718 (0, 2) 2
1719 (1, 0) --
1720 (1, 1) 4
1721 (1, 2) --
1722 (2, 0) 6
1723 (2, 1) --
1724 (2, 2) 8
1725 """
1726 for it, mask in zip(np.ndenumerate(a), getmaskarray(a).flat):
1727 if not mask:
1728 yield it
1729 elif not compressed:
1730 yield it[0], masked
1733def flatnotmasked_edges(a):
1734 """
1735 Find the indices of the first and last unmasked values.
1737 Expects a 1-D `MaskedArray`, returns None if all values are masked.
1739 Parameters
1740 ----------
1741 a : array_like
1742 Input 1-D `MaskedArray`
1744 Returns
1745 -------
1746 edges : ndarray or None
1747 The indices of first and last non-masked value in the array.
1748 Returns None if all values are masked.
1750 See Also
1751 --------
1752 flatnotmasked_contiguous, notmasked_contiguous, notmasked_edges
1753 clump_masked, clump_unmasked
1755 Notes
1756 -----
1757 Only accepts 1-D arrays.
1759 Examples
1760 --------
1761 >>> a = np.ma.arange(10)
1762 >>> np.ma.flatnotmasked_edges(a)
1763 array([0, 9])
1765 >>> mask = (a < 3) | (a > 8) | (a == 5)
1766 >>> a[mask] = np.ma.masked
1767 >>> np.array(a[~a.mask])
1768 array([3, 4, 6, 7, 8])
1770 >>> np.ma.flatnotmasked_edges(a)
1771 array([3, 8])
1773 >>> a[:] = np.ma.masked
1774 >>> print(np.ma.flatnotmasked_edges(a))
1775 None
1777 """
1778 m = getmask(a)
1779 if m is nomask or not np.any(m):
1780 return np.array([0, a.size - 1])
1781 unmasked = np.flatnonzero(~m)
1782 if len(unmasked) > 0:
1783 return unmasked[[0, -1]]
1784 else:
1785 return None
1788def notmasked_edges(a, axis=None):
1789 """
1790 Find the indices of the first and last unmasked values along an axis.
1792 If all values are masked, return None. Otherwise, return a list
1793 of two tuples, corresponding to the indices of the first and last
1794 unmasked values respectively.
1796 Parameters
1797 ----------
1798 a : array_like
1799 The input array.
1800 axis : int, optional
1801 Axis along which to perform the operation.
1802 If None (default), applies to a flattened version of the array.
1804 Returns
1805 -------
1806 edges : ndarray or list
1807 An array of start and end indexes if there are any masked data in
1808 the array. If there are no masked data in the array, `edges` is a
1809 list of the first and last index.
1811 See Also
1812 --------
1813 flatnotmasked_contiguous, flatnotmasked_edges, notmasked_contiguous
1814 clump_masked, clump_unmasked
1816 Examples
1817 --------
1818 >>> a = np.arange(9).reshape((3, 3))
1819 >>> m = np.zeros_like(a)
1820 >>> m[1:, 1:] = 1
1822 >>> am = np.ma.array(a, mask=m)
1823 >>> np.array(am[~am.mask])
1824 array([0, 1, 2, 3, 6])
1826 >>> np.ma.notmasked_edges(am)
1827 array([0, 6])
1829 """
1830 a = asarray(a)
1831 if axis is None or a.ndim == 1:
1832 return flatnotmasked_edges(a)
1833 m = getmaskarray(a)
1834 idx = array(np.indices(a.shape), mask=np.asarray([m] * a.ndim))
1835 return [tuple([idx[i].min(axis).compressed() for i in range(a.ndim)]),
1836 tuple([idx[i].max(axis).compressed() for i in range(a.ndim)]), ]
1839def flatnotmasked_contiguous(a):
1840 """
1841 Find contiguous unmasked data in a masked array.
1843 Parameters
1844 ----------
1845 a : array_like
1846 The input array.
1848 Returns
1849 -------
1850 slice_list : list
1851 A sorted sequence of `slice` objects (start index, end index).
1853 .. versionchanged:: 1.15.0
1854 Now returns an empty list instead of None for a fully masked array
1856 See Also
1857 --------
1858 flatnotmasked_edges, notmasked_contiguous, notmasked_edges
1859 clump_masked, clump_unmasked
1861 Notes
1862 -----
1863 Only accepts 2-D arrays at most.
1865 Examples
1866 --------
1867 >>> a = np.ma.arange(10)
1868 >>> np.ma.flatnotmasked_contiguous(a)
1869 [slice(0, 10, None)]
1871 >>> mask = (a < 3) | (a > 8) | (a == 5)
1872 >>> a[mask] = np.ma.masked
1873 >>> np.array(a[~a.mask])
1874 array([3, 4, 6, 7, 8])
1876 >>> np.ma.flatnotmasked_contiguous(a)
1877 [slice(3, 5, None), slice(6, 9, None)]
1878 >>> a[:] = np.ma.masked
1879 >>> np.ma.flatnotmasked_contiguous(a)
1880 []
1882 """
1883 m = getmask(a)
1884 if m is nomask:
1885 return [slice(0, a.size)]
1886 i = 0
1887 result = []
1888 for (k, g) in itertools.groupby(m.ravel()):
1889 n = len(list(g))
1890 if not k:
1891 result.append(slice(i, i + n))
1892 i += n
1893 return result
1896def notmasked_contiguous(a, axis=None):
1897 """
1898 Find contiguous unmasked data in a masked array along the given axis.
1900 Parameters
1901 ----------
1902 a : array_like
1903 The input array.
1904 axis : int, optional
1905 Axis along which to perform the operation.
1906 If None (default), applies to a flattened version of the array, and this
1907 is the same as `flatnotmasked_contiguous`.
1909 Returns
1910 -------
1911 endpoints : list
1912 A list of slices (start and end indexes) of unmasked indexes
1913 in the array.
1915 If the input is 2d and axis is specified, the result is a list of lists.
1917 See Also
1918 --------
1919 flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
1920 clump_masked, clump_unmasked
1922 Notes
1923 -----
1924 Only accepts 2-D arrays at most.
1926 Examples
1927 --------
1928 >>> a = np.arange(12).reshape((3, 4))
1929 >>> mask = np.zeros_like(a)
1930 >>> mask[1:, :-1] = 1; mask[0, 1] = 1; mask[-1, 0] = 0
1931 >>> ma = np.ma.array(a, mask=mask)
1932 >>> ma
1933 masked_array(
1934 data=[[0, --, 2, 3],
1935 [--, --, --, 7],
1936 [8, --, --, 11]],
1937 mask=[[False, True, False, False],
1938 [ True, True, True, False],
1939 [False, True, True, False]],
1940 fill_value=999999)
1941 >>> np.array(ma[~ma.mask])
1942 array([ 0, 2, 3, 7, 8, 11])
1944 >>> np.ma.notmasked_contiguous(ma)
1945 [slice(0, 1, None), slice(2, 4, None), slice(7, 9, None), slice(11, 12, None)]
1947 >>> np.ma.notmasked_contiguous(ma, axis=0)
1948 [[slice(0, 1, None), slice(2, 3, None)], [], [slice(0, 1, None)], [slice(0, 3, None)]]
1950 >>> np.ma.notmasked_contiguous(ma, axis=1)
1951 [[slice(0, 1, None), slice(2, 4, None)], [slice(3, 4, None)], [slice(0, 1, None), slice(3, 4, None)]]
1953 """
1954 a = asarray(a)
1955 nd = a.ndim
1956 if nd > 2:
1957 raise NotImplementedError("Currently limited to at most 2D array.")
1958 if axis is None or nd == 1:
1959 return flatnotmasked_contiguous(a)
1960 #
1961 result = []
1962 #
1963 other = (axis + 1) % 2
1964 idx = [0, 0]
1965 idx[axis] = slice(None, None)
1966 #
1967 for i in range(a.shape[other]):
1968 idx[other] = i
1969 result.append(flatnotmasked_contiguous(a[tuple(idx)]))
1970 return result
1973def _ezclump(mask):
1974 """
1975 Finds the clumps (groups of data with the same values) for a 1D bool array.
1977 Returns a series of slices.
1978 """
1979 if mask.ndim > 1:
1980 mask = mask.ravel()
1981 idx = (mask[1:] ^ mask[:-1]).nonzero()
1982 idx = idx[0] + 1
1984 if mask[0]:
1985 if len(idx) == 0:
1986 return [slice(0, mask.size)]
1988 r = [slice(0, idx[0])]
1989 r.extend((slice(left, right)
1990 for left, right in zip(idx[1:-1:2], idx[2::2])))
1991 else:
1992 if len(idx) == 0:
1993 return []
1995 r = [slice(left, right) for left, right in zip(idx[:-1:2], idx[1::2])]
1997 if mask[-1]:
1998 r.append(slice(idx[-1], mask.size))
1999 return r
2002def clump_unmasked(a):
2003 """
2004 Return list of slices corresponding to the unmasked clumps of a 1-D array.
2005 (A "clump" is defined as a contiguous region of the array).
2007 Parameters
2008 ----------
2009 a : ndarray
2010 A one-dimensional masked array.
2012 Returns
2013 -------
2014 slices : list of slice
2015 The list of slices, one for each continuous region of unmasked
2016 elements in `a`.
2018 Notes
2019 -----
2020 .. versionadded:: 1.4.0
2022 See Also
2023 --------
2024 flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
2025 notmasked_contiguous, clump_masked
2027 Examples
2028 --------
2029 >>> a = np.ma.masked_array(np.arange(10))
2030 >>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked
2031 >>> np.ma.clump_unmasked(a)
2032 [slice(3, 6, None), slice(7, 8, None)]
2034 """
2035 mask = getattr(a, '_mask', nomask)
2036 if mask is nomask:
2037 return [slice(0, a.size)]
2038 return _ezclump(~mask)
2041def clump_masked(a):
2042 """
2043 Returns a list of slices corresponding to the masked clumps of a 1-D array.
2044 (A "clump" is defined as a contiguous region of the array).
2046 Parameters
2047 ----------
2048 a : ndarray
2049 A one-dimensional masked array.
2051 Returns
2052 -------
2053 slices : list of slice
2054 The list of slices, one for each continuous region of masked elements
2055 in `a`.
2057 Notes
2058 -----
2059 .. versionadded:: 1.4.0
2061 See Also
2062 --------
2063 flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
2064 notmasked_contiguous, clump_unmasked
2066 Examples
2067 --------
2068 >>> a = np.ma.masked_array(np.arange(10))
2069 >>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked
2070 >>> np.ma.clump_masked(a)
2071 [slice(0, 3, None), slice(6, 7, None), slice(8, 10, None)]
2073 """
2074 mask = ma.getmask(a)
2075 if mask is nomask:
2076 return []
2077 return _ezclump(mask)
2080###############################################################################
2081# Polynomial fit #
2082###############################################################################
2085def vander(x, n=None):
2086 """
2087 Masked values in the input array result in rows of zeros.
2089 """
2090 _vander = np.vander(x, n)
2091 m = getmask(x)
2092 if m is not nomask:
2093 _vander[m] = 0
2094 return _vander
2096vander.__doc__ = ma.doc_note(np.vander.__doc__, vander.__doc__)
2099def polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False):
2100 """
2101 Any masked values in x is propagated in y, and vice-versa.
2103 """
2104 x = asarray(x)
2105 y = asarray(y)
2107 m = getmask(x)
2108 if y.ndim == 1:
2109 m = mask_or(m, getmask(y))
2110 elif y.ndim == 2:
2111 my = getmask(mask_rows(y))
2112 if my is not nomask:
2113 m = mask_or(m, my[:, 0])
2114 else:
2115 raise TypeError("Expected a 1D or 2D array for y!")
2117 if w is not None:
2118 w = asarray(w)
2119 if w.ndim != 1:
2120 raise TypeError("expected a 1-d array for weights")
2121 if w.shape[0] != y.shape[0]:
2122 raise TypeError("expected w and y to have the same length")
2123 m = mask_or(m, getmask(w))
2125 if m is not nomask:
2126 not_m = ~m
2127 if w is not None:
2128 w = w[not_m]
2129 return np.polyfit(x[not_m], y[not_m], deg, rcond, full, w, cov)
2130 else:
2131 return np.polyfit(x, y, deg, rcond, full, w, cov)
2133polyfit.__doc__ = ma.doc_note(np.polyfit.__doc__, polyfit.__doc__)