Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/numpy/ma/extras.py: 17%
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
9"""
10__all__ = [
11 'apply_along_axis', 'apply_over_axes', 'atleast_1d', 'atleast_2d',
12 'atleast_3d', 'average', 'clump_masked', 'clump_unmasked', 'column_stack',
13 'compress_cols', 'compress_nd', 'compress_rowcols', 'compress_rows',
14 'count_masked', 'corrcoef', 'cov', 'diagflat', 'dot', 'dstack', 'ediff1d',
15 'flatnotmasked_contiguous', 'flatnotmasked_edges', 'hsplit', 'hstack',
16 'isin', 'in1d', 'intersect1d', 'mask_cols', 'mask_rowcols', 'mask_rows',
17 'masked_all', 'masked_all_like', 'median', 'mr_', 'ndenumerate',
18 'notmasked_contiguous', 'notmasked_edges', 'polyfit', 'row_stack',
19 'setdiff1d', 'setxor1d', 'stack', 'unique', 'union1d', 'vander', 'vstack',
20 ]
22import functools
23import itertools
24import warnings
26import numpy as np
27from numpy import array as nxarray, ndarray
28from numpy.lib._function_base_impl import _ureduce
29from numpy.lib._index_tricks_impl import AxisConcatenator
30from numpy.lib.array_utils import normalize_axis_index, normalize_axis_tuple
32from . import core as ma
33from .core import ( # noqa: F401
34 MAError,
35 MaskedArray,
36 add,
37 array,
38 asarray,
39 concatenate,
40 count,
41 dot,
42 filled,
43 get_masked_subclass,
44 getdata,
45 getmask,
46 getmaskarray,
47 make_mask_descr,
48 mask_or,
49 masked,
50 masked_array,
51 nomask,
52 ones,
53 sort,
54 zeros,
55)
58def issequence(seq):
59 """
60 Is seq a sequence (ndarray, list or tuple)?
62 """
63 return isinstance(seq, (ndarray, tuple, list))
66def count_masked(arr, axis=None):
67 """
68 Count the number of masked elements along the given axis.
70 Parameters
71 ----------
72 arr : array_like
73 An array with (possibly) masked elements.
74 axis : int, optional
75 Axis along which to count. If None (default), a flattened
76 version of the array is used.
78 Returns
79 -------
80 count : int, ndarray
81 The total number of masked elements (axis=None) or the number
82 of masked elements along each slice of the given axis.
84 See Also
85 --------
86 MaskedArray.count : Count non-masked elements.
88 Examples
89 --------
90 >>> import numpy as np
91 >>> a = np.arange(9).reshape((3,3))
92 >>> a = np.ma.array(a)
93 >>> a[1, 0] = np.ma.masked
94 >>> a[1, 2] = np.ma.masked
95 >>> a[2, 1] = np.ma.masked
96 >>> a
97 masked_array(
98 data=[[0, 1, 2],
99 [--, 4, --],
100 [6, --, 8]],
101 mask=[[False, False, False],
102 [ True, False, True],
103 [False, True, False]],
104 fill_value=999999)
105 >>> np.ma.count_masked(a)
106 3
108 When the `axis` keyword is used an array is returned.
110 >>> np.ma.count_masked(a, axis=0)
111 array([1, 1, 1])
112 >>> np.ma.count_masked(a, axis=1)
113 array([0, 2, 1])
115 """
116 m = getmaskarray(arr)
117 return m.sum(axis)
120def masked_all(shape, dtype=float):
121 """
122 Empty masked array with all elements masked.
124 Return an empty masked array of the given shape and dtype, where all the
125 data are masked.
127 Parameters
128 ----------
129 shape : int or tuple of ints
130 Shape of the required MaskedArray, e.g., ``(2, 3)`` or ``2``.
131 dtype : dtype, optional
132 Data type of the output.
134 Returns
135 -------
136 a : MaskedArray
137 A masked array with all data masked.
139 See Also
140 --------
141 masked_all_like : Empty masked array modelled on an existing array.
143 Notes
144 -----
145 Unlike other masked array creation functions (e.g. `numpy.ma.zeros`,
146 `numpy.ma.ones`, `numpy.ma.full`), `masked_all` does not initialize the
147 values of the array, and may therefore be marginally faster. However,
148 the values stored in the newly allocated array are arbitrary. For
149 reproducible behavior, be sure to set each element of the array before
150 reading.
152 Examples
153 --------
154 >>> import numpy as np
155 >>> np.ma.masked_all((3, 3))
156 masked_array(
157 data=[[--, --, --],
158 [--, --, --],
159 [--, --, --]],
160 mask=[[ True, True, True],
161 [ True, True, True],
162 [ True, True, True]],
163 fill_value=1e+20,
164 dtype=float64)
166 The `dtype` parameter defines the underlying data type.
168 >>> a = np.ma.masked_all((3, 3))
169 >>> a.dtype
170 dtype('float64')
171 >>> a = np.ma.masked_all((3, 3), dtype=np.int32)
172 >>> a.dtype
173 dtype('int32')
175 """
176 a = masked_array(np.empty(shape, dtype),
177 mask=np.ones(shape, make_mask_descr(dtype)))
178 return a
181def masked_all_like(arr):
182 """
183 Empty masked array with the properties of an existing array.
185 Return an empty masked array of the same shape and dtype as
186 the array `arr`, where all the data are masked.
188 Parameters
189 ----------
190 arr : ndarray
191 An array describing the shape and dtype of the required MaskedArray.
193 Returns
194 -------
195 a : MaskedArray
196 A masked array with all data masked.
198 Raises
199 ------
200 AttributeError
201 If `arr` doesn't have a shape attribute (i.e. not an ndarray)
203 See Also
204 --------
205 masked_all : Empty masked array with all elements masked.
207 Notes
208 -----
209 Unlike other masked array creation functions (e.g. `numpy.ma.zeros_like`,
210 `numpy.ma.ones_like`, `numpy.ma.full_like`), `masked_all_like` does not
211 initialize the values of the array, and may therefore be marginally
212 faster. However, the values stored in the newly allocated array are
213 arbitrary. For reproducible behavior, be sure to set each element of the
214 array before reading.
216 Examples
217 --------
218 >>> import numpy as np
219 >>> arr = np.zeros((2, 3), dtype=np.float32)
220 >>> arr
221 array([[0., 0., 0.],
222 [0., 0., 0.]], dtype=float32)
223 >>> np.ma.masked_all_like(arr)
224 masked_array(
225 data=[[--, --, --],
226 [--, --, --]],
227 mask=[[ True, True, True],
228 [ True, True, True]],
229 fill_value=np.float64(1e+20),
230 dtype=float32)
232 The dtype of the masked array matches the dtype of `arr`.
234 >>> arr.dtype
235 dtype('float32')
236 >>> np.ma.masked_all_like(arr).dtype
237 dtype('float32')
239 """
240 a = np.empty_like(arr).view(MaskedArray)
241 a._mask = np.ones(a.shape, dtype=make_mask_descr(a.dtype))
242 return a
245#####--------------------------------------------------------------------------
246#---- --- Standard functions ---
247#####--------------------------------------------------------------------------
249def _fromnxfunction_function(_fromnxfunction):
250 """
251 Decorator to wrap a "_fromnxfunction" function, wrapping a numpy function as a
252 masked array function, with proper docstring and name.
254 Parameters
255 ----------
256 _fromnxfunction : ({params}) -> ndarray, {params}) -> masked_array
257 Wrapper function that calls the wrapped numpy function
259 Returns
260 -------
261 decorator : (f: ({params}) -> ndarray) -> ({params}) -> masked_array
262 Function that accepts a numpy function and returns a masked array function
264 """
265 def decorator(npfunc, /):
266 def wrapper(*args, **kwargs):
267 return _fromnxfunction(npfunc, *args, **kwargs)
269 functools.update_wrapper(wrapper, npfunc, assigned=("__name__", "__qualname__"))
270 wrapper.__doc__ = ma.doc_note(
271 npfunc.__doc__,
272 "The function is applied to both the ``_data`` and the ``_mask``, if any.",
273 )
274 return wrapper
276 return decorator
279@_fromnxfunction_function
280def _fromnxfunction_single(npfunc, a, /, *args, **kwargs):
281 """
282 Wraps a NumPy function that can be called with a single array argument followed by
283 auxiliary args that are passed verbatim for both the data and mask calls.
284 """
285 return masked_array(
286 data=npfunc(np.asarray(a), *args, **kwargs),
287 mask=npfunc(getmaskarray(a), *args, **kwargs),
288 )
291@_fromnxfunction_function
292def _fromnxfunction_seq(npfunc, arys, /, *args, **kwargs):
293 """
294 Wraps a NumPy function that can be called with a single sequence of arrays followed
295 by auxiliary args that are passed verbatim for both the data and mask calls.
296 """
297 return masked_array(
298 data=npfunc(tuple(np.asarray(a) for a in arys), *args, **kwargs),
299 mask=npfunc(tuple(getmaskarray(a) for a in arys), *args, **kwargs),
300 )
302@_fromnxfunction_function
303def _fromnxfunction_allargs(npfunc, /, *arys, **kwargs):
304 """
305 Wraps a NumPy function that can be called with multiple array arguments.
306 All args are converted to arrays even if they are not so already.
307 This makes it possible to process scalars as 1-D arrays.
308 Only keyword arguments are passed through verbatim for the data and mask calls.
309 Arrays arguments are processed independently and the results are returned in a list.
310 If only one arg is present, the return value is just the processed array instead of
311 a list.
312 """
313 out = tuple(
314 masked_array(
315 data=npfunc(np.asarray(a), **kwargs),
316 mask=npfunc(getmaskarray(a), **kwargs),
317 )
318 for a in arys
319 )
320 return out[0] if len(out) == 1 else out
323atleast_1d = _fromnxfunction_allargs(np.atleast_1d)
324atleast_2d = _fromnxfunction_allargs(np.atleast_2d)
325atleast_3d = _fromnxfunction_allargs(np.atleast_3d)
327vstack = row_stack = _fromnxfunction_seq(np.vstack)
328hstack = _fromnxfunction_seq(np.hstack)
329column_stack = _fromnxfunction_seq(np.column_stack)
330dstack = _fromnxfunction_seq(np.dstack)
331stack = _fromnxfunction_seq(np.stack)
333hsplit = _fromnxfunction_single(np.hsplit)
334diagflat = _fromnxfunction_single(np.diagflat)
337#####--------------------------------------------------------------------------
338#----
339#####--------------------------------------------------------------------------
340def flatten_inplace(seq):
341 """Flatten a sequence in place."""
342 k = 0
343 while (k != len(seq)):
344 while hasattr(seq[k], '__iter__'):
345 seq[k:(k + 1)] = seq[k]
346 k += 1
347 return seq
350def apply_along_axis(func1d, axis, arr, *args, **kwargs):
351 """
352 (This docstring should be overwritten)
353 """
354 arr = array(arr, copy=False, subok=True)
355 nd = arr.ndim
356 axis = normalize_axis_index(axis, nd)
357 ind = [0] * (nd - 1)
358 i = np.zeros(nd, 'O')
359 indlist = list(range(nd))
360 indlist.remove(axis)
361 i[axis] = slice(None, None)
362 outshape = np.asarray(arr.shape).take(indlist)
363 i.put(indlist, ind)
364 res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
365 # if res is a number, then we have a smaller output array
366 asscalar = np.isscalar(res)
367 if not asscalar:
368 try:
369 len(res)
370 except TypeError:
371 asscalar = True
372 # Note: we shouldn't set the dtype of the output from the first result
373 # so we force the type to object, and build a list of dtypes. We'll
374 # just take the largest, to avoid some downcasting
375 dtypes = []
376 if asscalar:
377 dtypes.append(np.asarray(res).dtype)
378 outarr = zeros(outshape, object)
379 outarr[tuple(ind)] = res
380 Ntot = np.prod(outshape)
381 k = 1
382 while k < Ntot:
383 # increment the index
384 ind[-1] += 1
385 n = -1
386 while (ind[n] >= outshape[n]) and (n > (1 - nd)):
387 ind[n - 1] += 1
388 ind[n] = 0
389 n -= 1
390 i.put(indlist, ind)
391 res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
392 outarr[tuple(ind)] = res
393 dtypes.append(asarray(res).dtype)
394 k += 1
395 else:
396 res = array(res, copy=False, subok=True)
397 j = i.copy()
398 j[axis] = ([slice(None, None)] * res.ndim)
399 j.put(indlist, ind)
400 Ntot = np.prod(outshape)
401 holdshape = outshape
402 outshape = list(arr.shape)
403 outshape[axis] = res.shape
404 dtypes.append(asarray(res).dtype)
405 outshape = flatten_inplace(outshape)
406 outarr = zeros(outshape, object)
407 outarr[tuple(flatten_inplace(j.tolist()))] = res
408 k = 1
409 while k < Ntot:
410 # increment the index
411 ind[-1] += 1
412 n = -1
413 while (ind[n] >= holdshape[n]) and (n > (1 - nd)):
414 ind[n - 1] += 1
415 ind[n] = 0
416 n -= 1
417 i.put(indlist, ind)
418 j.put(indlist, ind)
419 res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
420 outarr[tuple(flatten_inplace(j.tolist()))] = res
421 dtypes.append(asarray(res).dtype)
422 k += 1
423 max_dtypes = np.dtype(np.asarray(dtypes).max())
424 if not hasattr(arr, '_mask'):
425 result = np.asarray(outarr, dtype=max_dtypes)
426 else:
427 result = asarray(outarr, dtype=max_dtypes)
428 result.fill_value = ma.default_fill_value(result)
429 return result
432apply_along_axis.__doc__ = np.apply_along_axis.__doc__
435def apply_over_axes(func, a, axes):
436 """
437 (This docstring will be overwritten)
438 """
439 val = asarray(a)
440 N = a.ndim
441 if array(axes).ndim == 0:
442 axes = (axes,)
443 for axis in axes:
444 if axis < 0:
445 axis = N + axis
446 args = (val, axis)
447 res = func(*args)
448 if res.ndim == val.ndim:
449 val = res
450 else:
451 res = ma.expand_dims(res, axis)
452 if res.ndim == val.ndim:
453 val = res
454 else:
455 raise ValueError("function is not returning "
456 "an array of the correct shape")
457 return val
460if apply_over_axes.__doc__ is not None:
461 apply_over_axes.__doc__ = np.apply_over_axes.__doc__[
462 :np.apply_over_axes.__doc__.find('Notes')].rstrip() + \
463 """
465 Examples
466 --------
467 >>> import numpy as np
468 >>> a = np.ma.arange(24).reshape(2,3,4)
469 >>> a[:,0,1] = np.ma.masked
470 >>> a[:,1,:] = np.ma.masked
471 >>> a
472 masked_array(
473 data=[[[0, --, 2, 3],
474 [--, --, --, --],
475 [8, 9, 10, 11]],
476 [[12, --, 14, 15],
477 [--, --, --, --],
478 [20, 21, 22, 23]]],
479 mask=[[[False, True, False, False],
480 [ True, True, True, True],
481 [False, False, False, False]],
482 [[False, True, False, False],
483 [ True, True, True, True],
484 [False, False, False, False]]],
485 fill_value=999999)
486 >>> np.ma.apply_over_axes(np.ma.sum, a, [0,2])
487 masked_array(
488 data=[[[46],
489 [--],
490 [124]]],
491 mask=[[[False],
492 [ True],
493 [False]]],
494 fill_value=999999)
496 Tuple axis arguments to ufuncs are equivalent:
498 >>> np.ma.sum(a, axis=(0,2)).reshape((1,-1,1))
499 masked_array(
500 data=[[[46],
501 [--],
502 [124]]],
503 mask=[[[False],
504 [ True],
505 [False]]],
506 fill_value=999999)
507 """
510def average(a, axis=None, weights=None, returned=False, *,
511 keepdims=np._NoValue):
512 """
513 Return the weighted average of array over the given axis.
515 Parameters
516 ----------
517 a : array_like
518 Data to be averaged.
519 Masked entries are not taken into account in the computation.
520 axis : None or int or tuple of ints, optional
521 Axis or axes along which to average `a`. The default,
522 `axis=None`, will average over all of the elements of the input array.
523 If axis is a tuple of ints, averaging is performed on all of the axes
524 specified in the tuple instead of a single axis or all the axes as
525 before.
526 weights : array_like, optional
527 An array of weights associated with the values in `a`. Each value in
528 `a` contributes to the average according to its associated weight.
529 The array of weights must be the same shape as `a` if no axis is
530 specified, otherwise the weights must have dimensions and shape
531 consistent with `a` along the specified axis.
532 If `weights=None`, then all data in `a` are assumed to have a
533 weight equal to one.
534 The calculation is::
536 avg = sum(a * weights) / sum(weights)
538 where the sum is over all included elements.
539 The only constraint on the values of `weights` is that `sum(weights)`
540 must not be 0.
541 returned : bool, optional
542 Flag indicating whether a tuple ``(result, sum of weights)``
543 should be returned as output (True), or just the result (False).
544 Default is False.
545 keepdims : bool, optional
546 If this is set to True, the axes which are reduced are left
547 in the result as dimensions with size one. With this option,
548 the result will broadcast correctly against the original `a`.
549 *Note:* `keepdims` will not work with instances of `numpy.matrix`
550 or other classes whose methods do not support `keepdims`.
552 .. versionadded:: 1.23.0
554 Returns
555 -------
556 average, [sum_of_weights] : (tuple of) scalar or MaskedArray
557 The average along the specified axis. When returned is `True`,
558 return a tuple with the average as the first element and the sum
559 of the weights as the second element. The return type is `np.float64`
560 if `a` is of integer type and floats smaller than `float64`, or the
561 input data-type, otherwise. If returned, `sum_of_weights` is always
562 `float64`.
564 Raises
565 ------
566 ZeroDivisionError
567 When all weights along axis are zero. See `numpy.ma.average` for a
568 version robust to this type of error.
569 TypeError
570 When `weights` does not have the same shape as `a`, and `axis=None`.
571 ValueError
572 When `weights` does not have dimensions and shape consistent with `a`
573 along specified `axis`.
575 Examples
576 --------
577 >>> import numpy as np
578 >>> a = np.ma.array([1., 2., 3., 4.], mask=[False, False, True, True])
579 >>> np.ma.average(a, weights=[3, 1, 0, 0])
580 1.25
582 >>> x = np.ma.arange(6.).reshape(3, 2)
583 >>> x
584 masked_array(
585 data=[[0., 1.],
586 [2., 3.],
587 [4., 5.]],
588 mask=False,
589 fill_value=1e+20)
590 >>> data = np.arange(8).reshape((2, 2, 2))
591 >>> data
592 array([[[0, 1],
593 [2, 3]],
594 [[4, 5],
595 [6, 7]]])
596 >>> np.ma.average(data, axis=(0, 1), weights=[[1./4, 3./4], [1., 1./2]])
597 masked_array(data=[3.4, 4.4],
598 mask=[False, False],
599 fill_value=1e+20)
600 >>> np.ma.average(data, axis=0, weights=[[1./4, 3./4], [1., 1./2]])
601 Traceback (most recent call last):
602 ...
603 ValueError: Shape of weights must be consistent
604 with shape of a along specified axis.
606 >>> avg, sumweights = np.ma.average(x, axis=0, weights=[1, 2, 3],
607 ... returned=True)
608 >>> avg
609 masked_array(data=[2.6666666666666665, 3.6666666666666665],
610 mask=[False, False],
611 fill_value=1e+20)
613 With ``keepdims=True``, the following result has shape (3, 1).
615 >>> np.ma.average(x, axis=1, keepdims=True)
616 masked_array(
617 data=[[0.5],
618 [2.5],
619 [4.5]],
620 mask=False,
621 fill_value=1e+20)
622 """
623 a = asarray(a)
624 m = getmask(a)
626 if axis is not None:
627 axis = normalize_axis_tuple(axis, a.ndim, argname="axis")
629 if keepdims is np._NoValue:
630 # Don't pass on the keepdims argument if one wasn't given.
631 keepdims_kw = {}
632 else:
633 keepdims_kw = {'keepdims': keepdims}
635 if weights is None:
636 avg = a.mean(axis, **keepdims_kw)
637 scl = avg.dtype.type(a.count(axis))
638 else:
639 wgt = asarray(weights)
641 if issubclass(a.dtype.type, (np.integer, np.bool)):
642 result_dtype = np.result_type(a.dtype, wgt.dtype, 'f8')
643 else:
644 result_dtype = np.result_type(a.dtype, wgt.dtype)
646 # Sanity checks
647 if a.shape != wgt.shape:
648 if axis is None:
649 raise TypeError(
650 "Axis must be specified when shapes of a and weights "
651 "differ.")
652 if wgt.shape != tuple(a.shape[ax] for ax in axis):
653 raise ValueError(
654 "Shape of weights must be consistent with "
655 "shape of a along specified axis.")
657 # setup wgt to broadcast along axis
658 wgt = wgt.transpose(np.argsort(axis))
659 wgt = wgt.reshape(tuple((s if ax in axis else 1)
660 for ax, s in enumerate(a.shape)))
662 if m is not nomask:
663 wgt = wgt * (~a.mask)
664 wgt.mask |= a.mask
666 scl = wgt.sum(axis=axis, dtype=result_dtype, **keepdims_kw)
667 avg = np.multiply(a, wgt,
668 dtype=result_dtype).sum(axis, **keepdims_kw) / scl
670 if returned:
671 if scl.shape != avg.shape:
672 scl = np.broadcast_to(scl, avg.shape).copy()
673 return avg, scl
674 else:
675 return avg
678def median(a, axis=None, out=None, overwrite_input=False, keepdims=False):
679 """
680 Compute the median along the specified axis.
682 Returns the median of the array elements.
684 Parameters
685 ----------
686 a : array_like
687 Input array or object that can be converted to an array.
688 axis : int, optional
689 Axis along which the medians are computed. The default (None) is
690 to compute the median along a flattened version of the array.
691 out : ndarray, optional
692 Alternative output array in which to place the result. It must
693 have the same shape and buffer length as the expected output
694 but the type will be cast if necessary.
695 overwrite_input : bool, optional
696 If True, then allow use of memory of input array (a) for
697 calculations. The input array will be modified by the call to
698 median. This will save memory when you do not need to preserve
699 the contents of the input array. Treat the input as undefined,
700 but it will probably be fully or partially sorted. Default is
701 False. Note that, if `overwrite_input` is True, and the input
702 is not already an `ndarray`, an error will be raised.
703 keepdims : bool, optional
704 If this is set to True, the axes which are reduced are left
705 in the result as dimensions with size one. With this option,
706 the result will broadcast correctly against the input array.
708 Returns
709 -------
710 median : ndarray
711 A new array holding the result is returned unless out is
712 specified, in which case a reference to out is returned.
713 Return data-type is `float64` for integers and floats smaller than
714 `float64`, or the input data-type, otherwise.
716 See Also
717 --------
718 mean
720 Notes
721 -----
722 Given a vector ``V`` with ``N`` non masked values, the median of ``V``
723 is the middle value of a sorted copy of ``V`` (``Vs``) - i.e.
724 ``Vs[(N-1)/2]``, when ``N`` is odd, or ``{Vs[N/2 - 1] + Vs[N/2]}/2``
725 when ``N`` is even.
727 Examples
728 --------
729 >>> import numpy as np
730 >>> x = np.ma.array(np.arange(8), mask=[0]*4 + [1]*4)
731 >>> np.ma.median(x)
732 1.5
734 >>> x = np.ma.array(np.arange(10).reshape(2, 5), mask=[0]*6 + [1]*4)
735 >>> np.ma.median(x)
736 2.5
737 >>> np.ma.median(x, axis=-1, overwrite_input=True)
738 masked_array(data=[2.0, 5.0],
739 mask=[False, False],
740 fill_value=1e+20)
742 """
743 if not hasattr(a, 'mask'):
744 m = np.median(getdata(a, subok=True), axis=axis,
745 out=out, overwrite_input=overwrite_input,
746 keepdims=keepdims)
747 if isinstance(m, np.ndarray) and 1 <= m.ndim:
748 return masked_array(m, copy=False)
749 else:
750 return m
752 return _ureduce(a, func=_median, keepdims=keepdims, axis=axis, out=out,
753 overwrite_input=overwrite_input)
756def _median(a, axis=None, out=None, overwrite_input=False):
757 # when an unmasked NaN is present return it, so we need to sort the NaN
758 # values behind the mask
759 if np.issubdtype(a.dtype, np.inexact):
760 fill_value = np.inf
761 else:
762 fill_value = None
763 if overwrite_input:
764 if axis is None:
765 asorted = a.ravel()
766 asorted.sort(fill_value=fill_value)
767 else:
768 a.sort(axis=axis, fill_value=fill_value)
769 asorted = a
770 else:
771 asorted = sort(a, axis=axis, fill_value=fill_value)
773 if axis is None:
774 axis = 0
775 else:
776 axis = normalize_axis_index(axis, asorted.ndim)
778 if asorted.shape[axis] == 0:
779 # for empty axis integer indices fail so use slicing to get same result
780 # as median (which is mean of empty slice = nan)
781 indexer = [slice(None)] * asorted.ndim
782 indexer[axis] = slice(0, 0)
783 indexer = tuple(indexer)
784 return np.ma.mean(asorted[indexer], axis=axis, out=out)
786 if asorted.ndim == 1:
787 idx, odd = divmod(count(asorted), 2)
788 mid = asorted[idx + odd - 1:idx + 1]
789 if np.issubdtype(asorted.dtype, np.inexact) and asorted.size > 0:
790 # avoid inf / x = masked
791 s = mid.sum(out=out)
792 if not odd:
793 s = np.true_divide(s, 2., casting='safe', out=out)
794 s = np.lib._utils_impl._median_nancheck(asorted, s, axis)
795 else:
796 s = mid.mean(out=out)
798 # if result is masked either the input contained enough
799 # minimum_fill_value so that it would be the median or all values
800 # masked
801 if np.ma.is_masked(s) and not np.all(asorted.mask):
802 return np.ma.minimum_fill_value(asorted)
803 return s
805 counts = count(asorted, axis=axis, keepdims=True)
806 h = counts // 2
808 # duplicate high if odd number of elements so mean does nothing
809 odd = counts % 2 == 1
810 l = np.where(odd, h, h - 1)
812 lh = np.concatenate([l, h], axis=axis)
814 # get low and high median
815 low_high = np.take_along_axis(asorted, lh, axis=axis)
817 def replace_masked(s):
818 # Replace masked entries with minimum_full_value unless it all values
819 # are masked. This is required as the sort order of values equal or
820 # larger than the fill value is undefined and a valid value placed
821 # elsewhere, e.g. [4, --, inf].
822 if np.ma.is_masked(s):
823 rep = (~np.all(asorted.mask, axis=axis, keepdims=True)) & s.mask
824 s.data[rep] = np.ma.minimum_fill_value(asorted)
825 s.mask[rep] = False
827 replace_masked(low_high)
829 if np.issubdtype(asorted.dtype, np.inexact):
830 # avoid inf / x = masked
831 s = np.ma.sum(low_high, axis=axis, out=out)
832 np.true_divide(s.data, 2., casting='unsafe', out=s.data)
834 s = np.lib._utils_impl._median_nancheck(asorted, s, axis)
835 else:
836 s = np.ma.mean(low_high, axis=axis, out=out)
838 return s
841def compress_nd(x, axis=None):
842 """Suppress slices from multiple dimensions which contain masked values.
844 Parameters
845 ----------
846 x : array_like, MaskedArray
847 The array to operate on. If not a MaskedArray instance (or if no array
848 elements are masked), `x` is interpreted as a MaskedArray with `mask`
849 set to `nomask`.
850 axis : tuple of ints or int, optional
851 Which dimensions to suppress slices from can be configured with this
852 parameter.
853 - If axis is a tuple of ints, those are the axes to suppress slices from.
854 - If axis is an int, then that is the only axis to suppress slices from.
855 - If axis is None, all axis are selected.
857 Returns
858 -------
859 compress_array : ndarray
860 The compressed array.
862 Examples
863 --------
864 >>> import numpy as np
865 >>> arr = [[1, 2], [3, 4]]
866 >>> mask = [[0, 1], [0, 0]]
867 >>> x = np.ma.array(arr, mask=mask)
868 >>> np.ma.compress_nd(x, axis=0)
869 array([[3, 4]])
870 >>> np.ma.compress_nd(x, axis=1)
871 array([[1],
872 [3]])
873 >>> np.ma.compress_nd(x)
874 array([[3]])
876 """
877 x = asarray(x)
878 m = getmask(x)
879 # Set axis to tuple of ints
880 if axis is None:
881 axis = tuple(range(x.ndim))
882 else:
883 axis = normalize_axis_tuple(axis, x.ndim)
885 # Nothing is masked: return x
886 if m is nomask or not m.any():
887 return x._data
888 # All is masked: return empty
889 if m.all():
890 return nxarray([])
891 # Filter elements through boolean indexing
892 data = x._data
893 for ax in axis:
894 axes = tuple(list(range(ax)) + list(range(ax + 1, x.ndim)))
895 data = data[(slice(None),) * ax + (~m.any(axis=axes),)]
896 return data
899def compress_rowcols(x, axis=None):
900 """
901 Suppress the rows and/or columns of a 2-D array that contain
902 masked values.
904 The suppression behavior is selected with the `axis` parameter.
906 - If axis is None, both rows and columns are suppressed.
907 - If axis is 0, only rows are suppressed.
908 - If axis is 1 or -1, only columns are suppressed.
910 Parameters
911 ----------
912 x : array_like, MaskedArray
913 The array to operate on. If not a MaskedArray instance (or if no array
914 elements are masked), `x` is interpreted as a MaskedArray with
915 `mask` set to `nomask`. Must be a 2D array.
916 axis : int, optional
917 Axis along which to perform the operation. Default is None.
919 Returns
920 -------
921 compressed_array : ndarray
922 The compressed array.
924 Examples
925 --------
926 >>> import numpy as np
927 >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0],
928 ... [1, 0, 0],
929 ... [0, 0, 0]])
930 >>> x
931 masked_array(
932 data=[[--, 1, 2],
933 [--, 4, 5],
934 [6, 7, 8]],
935 mask=[[ True, False, False],
936 [ True, False, False],
937 [False, False, False]],
938 fill_value=999999)
940 >>> np.ma.compress_rowcols(x)
941 array([[7, 8]])
942 >>> np.ma.compress_rowcols(x, 0)
943 array([[6, 7, 8]])
944 >>> np.ma.compress_rowcols(x, 1)
945 array([[1, 2],
946 [4, 5],
947 [7, 8]])
949 """
950 if asarray(x).ndim != 2:
951 raise NotImplementedError("compress_rowcols works for 2D arrays only.")
952 return compress_nd(x, axis=axis)
955def compress_rows(a):
956 """
957 Suppress whole rows of a 2-D array that contain masked values.
959 This is equivalent to ``np.ma.compress_rowcols(a, 0)``, see
960 `compress_rowcols` for details.
962 Parameters
963 ----------
964 x : array_like, MaskedArray
965 The array to operate on. If not a MaskedArray instance (or if no array
966 elements are masked), `x` is interpreted as a MaskedArray with
967 `mask` set to `nomask`. Must be a 2D array.
969 Returns
970 -------
971 compressed_array : ndarray
972 The compressed array.
974 See Also
975 --------
976 compress_rowcols
978 Examples
979 --------
980 >>> import numpy as np
981 >>> a = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0],
982 ... [1, 0, 0],
983 ... [0, 0, 0]])
984 >>> np.ma.compress_rows(a)
985 array([[6, 7, 8]])
987 """
988 a = asarray(a)
989 if a.ndim != 2:
990 raise NotImplementedError("compress_rows works for 2D arrays only.")
991 return compress_rowcols(a, 0)
994def compress_cols(a):
995 """
996 Suppress whole columns of a 2-D array that contain masked values.
998 This is equivalent to ``np.ma.compress_rowcols(a, 1)``, see
999 `compress_rowcols` for details.
1001 Parameters
1002 ----------
1003 x : array_like, MaskedArray
1004 The array to operate on. If not a MaskedArray instance (or if no array
1005 elements are masked), `x` is interpreted as a MaskedArray with
1006 `mask` set to `nomask`. Must be a 2D array.
1008 Returns
1009 -------
1010 compressed_array : ndarray
1011 The compressed array.
1013 See Also
1014 --------
1015 compress_rowcols
1017 Examples
1018 --------
1019 >>> import numpy as np
1020 >>> a = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0],
1021 ... [1, 0, 0],
1022 ... [0, 0, 0]])
1023 >>> np.ma.compress_cols(a)
1024 array([[1, 2],
1025 [4, 5],
1026 [7, 8]])
1028 """
1029 a = asarray(a)
1030 if a.ndim != 2:
1031 raise NotImplementedError("compress_cols works for 2D arrays only.")
1032 return compress_rowcols(a, 1)
1035def mask_rowcols(a, axis=None):
1036 """
1037 Mask rows and/or columns of a 2D array that contain masked values.
1039 Mask whole rows and/or columns of a 2D array that contain
1040 masked values. The masking behavior is selected using the
1041 `axis` parameter.
1043 - If `axis` is None, rows *and* columns are masked.
1044 - If `axis` is 0, only rows are masked.
1045 - If `axis` is 1 or -1, only columns are masked.
1047 Parameters
1048 ----------
1049 a : array_like, MaskedArray
1050 The array to mask. If not a MaskedArray instance (or if no array
1051 elements are masked), the result is a MaskedArray with `mask` set
1052 to `nomask` (False). Must be a 2D array.
1053 axis : int, optional
1054 Axis along which to perform the operation. If None, applies to a
1055 flattened version of the array.
1057 Returns
1058 -------
1059 a : MaskedArray
1060 A modified version of the input array, masked depending on the value
1061 of the `axis` parameter.
1063 Raises
1064 ------
1065 NotImplementedError
1066 If input array `a` is not 2D.
1068 See Also
1069 --------
1070 mask_rows : Mask rows of a 2D array that contain masked values.
1071 mask_cols : Mask cols of a 2D array that contain masked values.
1072 masked_where : Mask where a condition is met.
1074 Notes
1075 -----
1076 The input array's mask is modified by this function.
1078 Examples
1079 --------
1080 >>> import numpy as np
1081 >>> a = np.zeros((3, 3), dtype=int)
1082 >>> a[1, 1] = 1
1083 >>> a
1084 array([[0, 0, 0],
1085 [0, 1, 0],
1086 [0, 0, 0]])
1087 >>> a = np.ma.masked_equal(a, 1)
1088 >>> a
1089 masked_array(
1090 data=[[0, 0, 0],
1091 [0, --, 0],
1092 [0, 0, 0]],
1093 mask=[[False, False, False],
1094 [False, True, False],
1095 [False, False, False]],
1096 fill_value=1)
1097 >>> np.ma.mask_rowcols(a)
1098 masked_array(
1099 data=[[0, --, 0],
1100 [--, --, --],
1101 [0, --, 0]],
1102 mask=[[False, True, False],
1103 [ True, True, True],
1104 [False, True, False]],
1105 fill_value=1)
1107 """
1108 a = array(a, subok=False)
1109 if a.ndim != 2:
1110 raise NotImplementedError("mask_rowcols works for 2D arrays only.")
1111 m = getmask(a)
1112 # Nothing is masked: return a
1113 if m is nomask or not m.any():
1114 return a
1115 maskedval = m.nonzero()
1116 a._mask = a._mask.copy()
1117 if not axis:
1118 a[np.unique(maskedval[0])] = masked
1119 if axis in [None, 1, -1]:
1120 a[:, np.unique(maskedval[1])] = masked
1121 return a
1124def mask_rows(a, axis=np._NoValue):
1125 """
1126 Mask rows of a 2D array that contain masked values.
1128 This function is a shortcut to ``mask_rowcols`` with `axis` equal to 0.
1130 See Also
1131 --------
1132 mask_rowcols : Mask rows and/or columns of a 2D array.
1133 masked_where : Mask where a condition is met.
1135 Examples
1136 --------
1137 >>> import numpy as np
1138 >>> a = np.zeros((3, 3), dtype=int)
1139 >>> a[1, 1] = 1
1140 >>> a
1141 array([[0, 0, 0],
1142 [0, 1, 0],
1143 [0, 0, 0]])
1144 >>> a = np.ma.masked_equal(a, 1)
1145 >>> a
1146 masked_array(
1147 data=[[0, 0, 0],
1148 [0, --, 0],
1149 [0, 0, 0]],
1150 mask=[[False, False, False],
1151 [False, True, False],
1152 [False, False, False]],
1153 fill_value=1)
1155 >>> np.ma.mask_rows(a)
1156 masked_array(
1157 data=[[0, 0, 0],
1158 [--, --, --],
1159 [0, 0, 0]],
1160 mask=[[False, False, False],
1161 [ True, True, True],
1162 [False, False, False]],
1163 fill_value=1)
1165 """
1166 if axis is not np._NoValue:
1167 # remove the axis argument when this deprecation expires
1168 # NumPy 1.18.0, 2019-11-28
1169 warnings.warn(
1170 "The axis argument has always been ignored, in future passing it "
1171 "will raise TypeError", DeprecationWarning, stacklevel=2)
1172 return mask_rowcols(a, 0)
1175def mask_cols(a, axis=np._NoValue):
1176 """
1177 Mask columns of a 2D array that contain masked values.
1179 This function is a shortcut to ``mask_rowcols`` with `axis` equal to 1.
1181 See Also
1182 --------
1183 mask_rowcols : Mask rows and/or columns of a 2D array.
1184 masked_where : Mask where a condition is met.
1186 Examples
1187 --------
1188 >>> import numpy as np
1189 >>> a = np.zeros((3, 3), dtype=int)
1190 >>> a[1, 1] = 1
1191 >>> a
1192 array([[0, 0, 0],
1193 [0, 1, 0],
1194 [0, 0, 0]])
1195 >>> a = np.ma.masked_equal(a, 1)
1196 >>> a
1197 masked_array(
1198 data=[[0, 0, 0],
1199 [0, --, 0],
1200 [0, 0, 0]],
1201 mask=[[False, False, False],
1202 [False, True, False],
1203 [False, False, False]],
1204 fill_value=1)
1205 >>> np.ma.mask_cols(a)
1206 masked_array(
1207 data=[[0, --, 0],
1208 [0, --, 0],
1209 [0, --, 0]],
1210 mask=[[False, True, False],
1211 [False, True, False],
1212 [False, True, False]],
1213 fill_value=1)
1215 """
1216 if axis is not np._NoValue:
1217 # remove the axis argument when this deprecation expires
1218 # NumPy 1.18.0, 2019-11-28
1219 warnings.warn(
1220 "The axis argument has always been ignored, in future passing it "
1221 "will raise TypeError", DeprecationWarning, stacklevel=2)
1222 return mask_rowcols(a, 1)
1225#####--------------------------------------------------------------------------
1226#---- --- arraysetops ---
1227#####--------------------------------------------------------------------------
1229def ediff1d(arr, to_end=None, to_begin=None):
1230 """
1231 Compute the differences between consecutive elements of an array.
1233 This function is the equivalent of `numpy.ediff1d` that takes masked
1234 values into account, see `numpy.ediff1d` for details.
1236 See Also
1237 --------
1238 numpy.ediff1d : Equivalent function for ndarrays.
1240 Examples
1241 --------
1242 >>> import numpy as np
1243 >>> arr = np.ma.array([1, 2, 4, 7, 0])
1244 >>> np.ma.ediff1d(arr)
1245 masked_array(data=[ 1, 2, 3, -7],
1246 mask=False,
1247 fill_value=999999)
1249 """
1250 arr = ma.asanyarray(arr).flat
1251 ed = arr[1:] - arr[:-1]
1252 arrays = [ed]
1253 #
1254 if to_begin is not None:
1255 arrays.insert(0, to_begin)
1256 if to_end is not None:
1257 arrays.append(to_end)
1258 #
1259 if len(arrays) != 1:
1260 # We'll save ourselves a copy of a potentially large array in the common
1261 # case where neither to_begin or to_end was given.
1262 ed = hstack(arrays)
1263 #
1264 return ed
1267def unique(ar1, return_index=False, return_inverse=False):
1268 """
1269 Finds the unique elements of an array.
1271 Masked values are considered the same element (masked). The output array
1272 is always a masked array. See `numpy.unique` for more details.
1274 See Also
1275 --------
1276 numpy.unique : Equivalent function for ndarrays.
1278 Examples
1279 --------
1280 >>> import numpy as np
1281 >>> a = [1, 2, 1000, 2, 3]
1282 >>> mask = [0, 0, 1, 0, 0]
1283 >>> masked_a = np.ma.masked_array(a, mask)
1284 >>> masked_a
1285 masked_array(data=[1, 2, --, 2, 3],
1286 mask=[False, False, True, False, False],
1287 fill_value=999999)
1288 >>> np.ma.unique(masked_a)
1289 masked_array(data=[1, 2, 3, --],
1290 mask=[False, False, False, True],
1291 fill_value=999999)
1292 >>> np.ma.unique(masked_a, return_index=True)
1293 (masked_array(data=[1, 2, 3, --],
1294 mask=[False, False, False, True],
1295 fill_value=999999), array([0, 1, 4, 2]))
1296 >>> np.ma.unique(masked_a, return_inverse=True)
1297 (masked_array(data=[1, 2, 3, --],
1298 mask=[False, False, False, True],
1299 fill_value=999999), array([0, 1, 3, 1, 2]))
1300 >>> np.ma.unique(masked_a, return_index=True, return_inverse=True)
1301 (masked_array(data=[1, 2, 3, --],
1302 mask=[False, False, False, True],
1303 fill_value=999999), array([0, 1, 4, 2]), array([0, 1, 3, 1, 2]))
1304 """
1305 output = np.unique(ar1,
1306 return_index=return_index,
1307 return_inverse=return_inverse)
1308 if isinstance(output, tuple):
1309 output = list(output)
1310 output[0] = output[0].view(MaskedArray)
1311 output = tuple(output)
1312 else:
1313 output = output.view(MaskedArray)
1314 return output
1317def intersect1d(ar1, ar2, assume_unique=False):
1318 """
1319 Returns the unique elements common to both arrays.
1321 Masked values are considered equal one to the other.
1322 The output is always a masked array.
1324 See `numpy.intersect1d` for more details.
1326 See Also
1327 --------
1328 numpy.intersect1d : Equivalent function for ndarrays.
1330 Examples
1331 --------
1332 >>> import numpy as np
1333 >>> x = np.ma.array([1, 3, 3, 3], mask=[0, 0, 0, 1])
1334 >>> y = np.ma.array([3, 1, 1, 1], mask=[0, 0, 0, 1])
1335 >>> np.ma.intersect1d(x, y)
1336 masked_array(data=[1, 3, --],
1337 mask=[False, False, True],
1338 fill_value=999999)
1340 """
1341 if assume_unique:
1342 aux = ma.concatenate((ar1, ar2))
1343 else:
1344 # Might be faster than unique( intersect1d( ar1, ar2 ) )?
1345 aux = ma.concatenate((unique(ar1), unique(ar2)))
1346 aux.sort()
1347 return aux[:-1][aux[1:] == aux[:-1]]
1350def setxor1d(ar1, ar2, assume_unique=False):
1351 """
1352 Set exclusive-or of 1-D arrays with unique elements.
1354 The output is always a masked array. See `numpy.setxor1d` for more details.
1356 See Also
1357 --------
1358 numpy.setxor1d : Equivalent function for ndarrays.
1360 Examples
1361 --------
1362 >>> import numpy as np
1363 >>> ar1 = np.ma.array([1, 2, 3, 2, 4])
1364 >>> ar2 = np.ma.array([2, 3, 5, 7, 5])
1365 >>> np.ma.setxor1d(ar1, ar2)
1366 masked_array(data=[1, 4, 5, 7],
1367 mask=False,
1368 fill_value=999999)
1370 """
1371 if not assume_unique:
1372 ar1 = unique(ar1)
1373 ar2 = unique(ar2)
1375 aux = ma.concatenate((ar1, ar2), axis=None)
1376 if aux.size == 0:
1377 return aux
1378 aux.sort()
1379 auxf = aux.filled()
1380# flag = ediff1d( aux, to_end = 1, to_begin = 1 ) == 0
1381 flag = ma.concatenate(([True], (auxf[1:] != auxf[:-1]), [True]))
1382# flag2 = ediff1d( flag ) == 0
1383 flag2 = (flag[1:] == flag[:-1])
1384 return aux[flag2]
1387def in1d(ar1, ar2, assume_unique=False, invert=False):
1388 """
1389 Test whether each element of an array is also present in a second
1390 array.
1392 The output is always a masked array.
1394 We recommend using :func:`isin` instead of `in1d` for new code.
1396 See Also
1397 --------
1398 isin : Version of this function that preserves the shape of ar1.
1400 Examples
1401 --------
1402 >>> import numpy as np
1403 >>> ar1 = np.ma.array([0, 1, 2, 5, 0])
1404 >>> ar2 = [0, 2]
1405 >>> np.ma.in1d(ar1, ar2)
1406 masked_array(data=[ True, False, True, False, True],
1407 mask=False,
1408 fill_value=True)
1410 """
1411 if not assume_unique:
1412 ar1, rev_idx = unique(ar1, return_inverse=True)
1413 ar2 = unique(ar2)
1415 ar = ma.concatenate((ar1, ar2))
1416 # We need this to be a stable sort, so always use 'mergesort'
1417 # here. The values from the first array should always come before
1418 # the values from the second array.
1419 order = ar.argsort(kind='mergesort')
1420 sar = ar[order]
1421 if invert:
1422 bool_ar = (sar[1:] != sar[:-1])
1423 else:
1424 bool_ar = (sar[1:] == sar[:-1])
1425 flag = ma.concatenate((bool_ar, [invert]))
1426 indx = order.argsort(kind='mergesort')[:len(ar1)]
1428 if assume_unique:
1429 return flag[indx]
1430 else:
1431 return flag[indx][rev_idx]
1434def isin(element, test_elements, assume_unique=False, invert=False):
1435 """
1436 Calculates `element in test_elements`, broadcasting over
1437 `element` only.
1439 The output is always a masked array of the same shape as `element`.
1440 See `numpy.isin` for more details.
1442 See Also
1443 --------
1444 in1d : Flattened version of this function.
1445 numpy.isin : Equivalent function for ndarrays.
1447 Examples
1448 --------
1449 >>> import numpy as np
1450 >>> element = np.ma.array([1, 2, 3, 4, 5, 6])
1451 >>> test_elements = [0, 2]
1452 >>> np.ma.isin(element, test_elements)
1453 masked_array(data=[False, True, False, False, False, False],
1454 mask=False,
1455 fill_value=True)
1457 """
1458 element = ma.asarray(element)
1459 return in1d(element, test_elements, assume_unique=assume_unique,
1460 invert=invert).reshape(element.shape)
1463def union1d(ar1, ar2):
1464 """
1465 Union of two arrays.
1467 The output is always a masked array. See `numpy.union1d` for more details.
1469 See Also
1470 --------
1471 numpy.union1d : Equivalent function for ndarrays.
1473 Examples
1474 --------
1475 >>> import numpy as np
1476 >>> ar1 = np.ma.array([1, 2, 3, 4])
1477 >>> ar2 = np.ma.array([3, 4, 5, 6])
1478 >>> np.ma.union1d(ar1, ar2)
1479 masked_array(data=[1, 2, 3, 4, 5, 6],
1480 mask=False,
1481 fill_value=999999)
1483 """
1484 return unique(ma.concatenate((ar1, ar2), axis=None))
1487def setdiff1d(ar1, ar2, assume_unique=False):
1488 """
1489 Set difference of 1D arrays with unique elements.
1491 The output is always a masked array. See `numpy.setdiff1d` for more
1492 details.
1494 See Also
1495 --------
1496 numpy.setdiff1d : Equivalent function for ndarrays.
1498 Examples
1499 --------
1500 >>> import numpy as np
1501 >>> x = np.ma.array([1, 2, 3, 4], mask=[0, 1, 0, 1])
1502 >>> np.ma.setdiff1d(x, [1, 2])
1503 masked_array(data=[3, --],
1504 mask=[False, True],
1505 fill_value=999999)
1507 """
1508 if assume_unique:
1509 ar1 = ma.asarray(ar1).ravel()
1510 else:
1511 ar1 = unique(ar1)
1512 ar2 = unique(ar2)
1513 return ar1[in1d(ar1, ar2, assume_unique=True, invert=True)]
1516###############################################################################
1517# Covariance #
1518###############################################################################
1521def _covhelper(x, y=None, rowvar=True, allow_masked=True):
1522 """
1523 Private function for the computation of covariance and correlation
1524 coefficients.
1526 """
1527 x = ma.array(x, ndmin=2, copy=True, dtype=float)
1528 xmask = ma.getmaskarray(x)
1529 # Quick exit if we can't process masked data
1530 if not allow_masked and xmask.any():
1531 raise ValueError("Cannot process masked data.")
1532 #
1533 if x.shape[0] == 1:
1534 rowvar = True
1535 # Make sure that rowvar is either 0 or 1
1536 rowvar = int(bool(rowvar))
1537 axis = 1 - rowvar
1538 if rowvar:
1539 tup = (slice(None), None)
1540 else:
1541 tup = (None, slice(None))
1542 #
1543 if y is None:
1544 # Check if we can guarantee that the integers in the (N - ddof)
1545 # normalisation can be accurately represented with single-precision
1546 # before computing the dot product.
1547 if x.shape[0] > 2 ** 24 or x.shape[1] > 2 ** 24:
1548 xnm_dtype = np.float64
1549 else:
1550 xnm_dtype = np.float32
1551 xnotmask = np.logical_not(xmask).astype(xnm_dtype)
1552 else:
1553 y = array(y, copy=False, ndmin=2, dtype=float)
1554 ymask = ma.getmaskarray(y)
1555 if not allow_masked and ymask.any():
1556 raise ValueError("Cannot process masked data.")
1557 if xmask.any() or ymask.any():
1558 if y.shape == x.shape:
1559 # Define some common mask
1560 common_mask = np.logical_or(xmask, ymask)
1561 if common_mask is not nomask:
1562 xmask = x._mask = y._mask = ymask = common_mask
1563 x._sharedmask = False
1564 y._sharedmask = False
1565 x = ma.concatenate((x, y), axis)
1566 # Check if we can guarantee that the integers in the (N - ddof)
1567 # normalisation can be accurately represented with single-precision
1568 # before computing the dot product.
1569 if x.shape[0] > 2 ** 24 or x.shape[1] > 2 ** 24:
1570 xnm_dtype = np.float64
1571 else:
1572 xnm_dtype = np.float32
1573 xnotmask = np.logical_not(np.concatenate((xmask, ymask), axis)).astype(
1574 xnm_dtype
1575 )
1576 x -= x.mean(axis=rowvar)[tup]
1577 return (x, xnotmask, rowvar)
1580def cov(x, y=None, rowvar=True, bias=False, allow_masked=True, ddof=None):
1581 """
1582 Estimate the covariance matrix.
1584 Except for the handling of missing data this function does the same as
1585 `numpy.cov`. For more details and examples, see `numpy.cov`.
1587 By default, masked values are recognized as such. If `x` and `y` have the
1588 same shape, a common mask is allocated: if ``x[i,j]`` is masked, then
1589 ``y[i,j]`` will also be masked.
1590 Setting `allow_masked` to False will raise an exception if values are
1591 missing in either of the input arrays.
1593 Parameters
1594 ----------
1595 x : array_like
1596 A 1-D or 2-D array containing multiple variables and observations.
1597 Each row of `x` represents a variable, and each column a single
1598 observation of all those variables. Also see `rowvar` below.
1599 y : array_like, optional
1600 An additional set of variables and observations. `y` has the same
1601 shape as `x`.
1602 rowvar : bool, optional
1603 If `rowvar` is True (default), then each row represents a
1604 variable, with observations in the columns. Otherwise, the relationship
1605 is transposed: each column represents a variable, while the rows
1606 contain observations.
1607 bias : bool, optional
1608 Default normalization (False) is by ``(N-1)``, where ``N`` is the
1609 number of observations given (unbiased estimate). If `bias` is True,
1610 then normalization is by ``N``. This keyword can be overridden by
1611 the keyword ``ddof`` in numpy versions >= 1.5.
1612 allow_masked : bool, optional
1613 If True, masked values are propagated pair-wise: if a value is masked
1614 in `x`, the corresponding value is masked in `y`.
1615 If False, raises a `ValueError` exception when some values are missing.
1616 ddof : {None, int}, optional
1617 If not ``None`` normalization is by ``(N - ddof)``, where ``N`` is
1618 the number of observations; this overrides the value implied by
1619 ``bias``. The default value is ``None``.
1621 Raises
1622 ------
1623 ValueError
1624 Raised if some values are missing and `allow_masked` is False.
1626 See Also
1627 --------
1628 numpy.cov
1630 Examples
1631 --------
1632 >>> import numpy as np
1633 >>> x = np.ma.array([[0, 1], [1, 1]], mask=[0, 1, 0, 1])
1634 >>> y = np.ma.array([[1, 0], [0, 1]], mask=[0, 0, 1, 1])
1635 >>> np.ma.cov(x, y)
1636 masked_array(
1637 data=[[--, --, --, --],
1638 [--, --, --, --],
1639 [--, --, --, --],
1640 [--, --, --, --]],
1641 mask=[[ True, True, True, True],
1642 [ True, True, True, True],
1643 [ True, True, True, True],
1644 [ True, True, True, True]],
1645 fill_value=1e+20,
1646 dtype=float64)
1648 """
1649 # Check inputs
1650 if ddof is not None and ddof != int(ddof):
1651 raise ValueError("ddof must be an integer")
1652 # Set up ddof
1653 if ddof is None:
1654 if bias:
1655 ddof = 0
1656 else:
1657 ddof = 1
1659 (x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked)
1660 if not rowvar:
1661 fact = np.dot(xnotmask.T, xnotmask) - ddof
1662 mask = np.less_equal(fact, 0, dtype=bool)
1663 with np.errstate(divide="ignore", invalid="ignore"):
1664 data = np.dot(filled(x.T, 0), filled(x.conj(), 0)) / fact
1665 result = ma.array(data, mask=mask).squeeze()
1666 else:
1667 fact = np.dot(xnotmask, xnotmask.T) - ddof
1668 mask = np.less_equal(fact, 0, dtype=bool)
1669 with np.errstate(divide="ignore", invalid="ignore"):
1670 data = np.dot(filled(x, 0), filled(x.T.conj(), 0)) / fact
1671 result = ma.array(data, mask=mask).squeeze()
1672 return result
1675def corrcoef(x, y=None, rowvar=True, allow_masked=True,
1676 ):
1677 """
1678 Return Pearson product-moment correlation coefficients.
1680 Except for the handling of missing data this function does the same as
1681 `numpy.corrcoef`. For more details and examples, see `numpy.corrcoef`.
1683 Parameters
1684 ----------
1685 x : array_like
1686 A 1-D or 2-D array containing multiple variables and observations.
1687 Each row of `x` represents a variable, and each column a single
1688 observation of all those variables. Also see `rowvar` below.
1689 y : array_like, optional
1690 An additional set of variables and observations. `y` has the same
1691 shape as `x`.
1692 rowvar : bool, optional
1693 If `rowvar` is True (default), then each row represents a
1694 variable, with observations in the columns. Otherwise, the relationship
1695 is transposed: each column represents a variable, while the rows
1696 contain observations.
1697 allow_masked : bool, optional
1698 If True, masked values are propagated pair-wise: if a value is masked
1699 in `x`, the corresponding value is masked in `y`.
1700 If False, raises an exception. Because `bias` is deprecated, this
1701 argument needs to be treated as keyword only to avoid a warning.
1703 See Also
1704 --------
1705 numpy.corrcoef : Equivalent function in top-level NumPy module.
1706 cov : Estimate the covariance matrix.
1708 Examples
1709 --------
1710 >>> import numpy as np
1711 >>> x = np.ma.array([[0, 1], [1, 1]], mask=[0, 1, 0, 1])
1712 >>> np.ma.corrcoef(x)
1713 masked_array(
1714 data=[[--, --],
1715 [--, --]],
1716 mask=[[ True, True],
1717 [ True, True]],
1718 fill_value=1e+20,
1719 dtype=float64)
1721 """
1722 # Estimate the covariance matrix.
1723 corr = cov(x, y, rowvar, allow_masked=allow_masked)
1724 # The non-masked version returns a masked value for a scalar.
1725 try:
1726 std = ma.sqrt(ma.diagonal(corr))
1727 except ValueError:
1728 return ma.MaskedConstant()
1729 corr /= ma.multiply.outer(std, std)
1730 return corr
1732#####--------------------------------------------------------------------------
1733#---- --- Concatenation helpers ---
1734#####--------------------------------------------------------------------------
1736class MAxisConcatenator(AxisConcatenator):
1737 """
1738 Translate slice objects to concatenation along an axis.
1740 For documentation on usage, see `mr_class`.
1742 See Also
1743 --------
1744 mr_class
1746 """
1747 __slots__ = ()
1749 concatenate = staticmethod(concatenate)
1751 @classmethod
1752 def makemat(cls, arr):
1753 # There used to be a view as np.matrix here, but we may eventually
1754 # deprecate that class. In preparation, we use the unmasked version
1755 # to construct the matrix (with copy=False for backwards compatibility
1756 # with the .view)
1757 data = super().makemat(arr.data, copy=False)
1758 return array(data, mask=arr.mask)
1760 def __getitem__(self, key):
1761 # matrix builder syntax, like 'a, b; c, d'
1762 if isinstance(key, str):
1763 raise MAError("Unavailable for masked array.")
1765 return super().__getitem__(key)
1768class mr_class(MAxisConcatenator):
1769 """
1770 Translate slice objects to concatenation along the first axis.
1772 This is the masked array version of `r_`.
1774 See Also
1775 --------
1776 r_
1778 Examples
1779 --------
1780 >>> import numpy as np
1781 >>> np.ma.mr_[np.ma.array([1,2,3]), 0, 0, np.ma.array([4,5,6])]
1782 masked_array(data=[1, 2, 3, ..., 4, 5, 6],
1783 mask=False,
1784 fill_value=999999)
1786 """
1787 __slots__ = ()
1789 def __init__(self):
1790 MAxisConcatenator.__init__(self, 0)
1793mr_ = mr_class()
1796#####--------------------------------------------------------------------------
1797#---- Find unmasked data ---
1798#####--------------------------------------------------------------------------
1800def ndenumerate(a, compressed=True):
1801 """
1802 Multidimensional index iterator.
1804 Return an iterator yielding pairs of array coordinates and values,
1805 skipping elements that are masked. With `compressed=False`,
1806 `ma.masked` is yielded as the value of masked elements. This
1807 behavior differs from that of `numpy.ndenumerate`, which yields the
1808 value of the underlying data array.
1810 Notes
1811 -----
1812 .. versionadded:: 1.23.0
1814 Parameters
1815 ----------
1816 a : array_like
1817 An array with (possibly) masked elements.
1818 compressed : bool, optional
1819 If True (default), masked elements are skipped.
1821 See Also
1822 --------
1823 numpy.ndenumerate : Equivalent function ignoring any mask.
1825 Examples
1826 --------
1827 >>> import numpy as np
1828 >>> a = np.ma.arange(9).reshape((3, 3))
1829 >>> a[1, 0] = np.ma.masked
1830 >>> a[1, 2] = np.ma.masked
1831 >>> a[2, 1] = np.ma.masked
1832 >>> a
1833 masked_array(
1834 data=[[0, 1, 2],
1835 [--, 4, --],
1836 [6, --, 8]],
1837 mask=[[False, False, False],
1838 [ True, False, True],
1839 [False, True, False]],
1840 fill_value=999999)
1841 >>> for index, x in np.ma.ndenumerate(a):
1842 ... print(index, x)
1843 (0, 0) 0
1844 (0, 1) 1
1845 (0, 2) 2
1846 (1, 1) 4
1847 (2, 0) 6
1848 (2, 2) 8
1850 >>> for index, x in np.ma.ndenumerate(a, compressed=False):
1851 ... print(index, x)
1852 (0, 0) 0
1853 (0, 1) 1
1854 (0, 2) 2
1855 (1, 0) --
1856 (1, 1) 4
1857 (1, 2) --
1858 (2, 0) 6
1859 (2, 1) --
1860 (2, 2) 8
1861 """
1862 for it, mask in zip(np.ndenumerate(a), getmaskarray(a).flat):
1863 if not mask:
1864 yield it
1865 elif not compressed:
1866 yield it[0], masked
1869def flatnotmasked_edges(a):
1870 """
1871 Find the indices of the first and last unmasked values.
1873 Expects a 1-D `MaskedArray`, returns None if all values are masked.
1875 Parameters
1876 ----------
1877 a : array_like
1878 Input 1-D `MaskedArray`
1880 Returns
1881 -------
1882 edges : ndarray or None
1883 The indices of first and last non-masked value in the array.
1884 Returns None if all values are masked.
1886 See Also
1887 --------
1888 flatnotmasked_contiguous, notmasked_contiguous, notmasked_edges
1889 clump_masked, clump_unmasked
1891 Notes
1892 -----
1893 Only accepts 1-D arrays.
1895 Examples
1896 --------
1897 >>> import numpy as np
1898 >>> a = np.ma.arange(10)
1899 >>> np.ma.flatnotmasked_edges(a)
1900 array([0, 9])
1902 >>> mask = (a < 3) | (a > 8) | (a == 5)
1903 >>> a[mask] = np.ma.masked
1904 >>> np.array(a[~a.mask])
1905 array([3, 4, 6, 7, 8])
1907 >>> np.ma.flatnotmasked_edges(a)
1908 array([3, 8])
1910 >>> a[:] = np.ma.masked
1911 >>> print(np.ma.flatnotmasked_edges(a))
1912 None
1914 """
1915 m = getmask(a)
1916 if m is nomask or not np.any(m):
1917 return np.array([0, a.size - 1])
1918 unmasked = np.flatnonzero(~m)
1919 if len(unmasked) > 0:
1920 return unmasked[[0, -1]]
1921 else:
1922 return None
1925def notmasked_edges(a, axis=None):
1926 """
1927 Find the indices of the first and last unmasked values along an axis.
1929 If all values are masked, return None. Otherwise, return a list
1930 of two tuples, corresponding to the indices of the first and last
1931 unmasked values respectively.
1933 Parameters
1934 ----------
1935 a : array_like
1936 The input array.
1937 axis : int, optional
1938 Axis along which to perform the operation.
1939 If None (default), applies to a flattened version of the array.
1941 Returns
1942 -------
1943 edges : ndarray or list
1944 An array of start and end indexes if there are any masked data in
1945 the array. If there are no masked data in the array, `edges` is a
1946 list of the first and last index.
1948 See Also
1949 --------
1950 flatnotmasked_contiguous, flatnotmasked_edges, notmasked_contiguous
1951 clump_masked, clump_unmasked
1953 Examples
1954 --------
1955 >>> import numpy as np
1956 >>> a = np.arange(9).reshape((3, 3))
1957 >>> m = np.zeros_like(a)
1958 >>> m[1:, 1:] = 1
1960 >>> am = np.ma.array(a, mask=m)
1961 >>> np.array(am[~am.mask])
1962 array([0, 1, 2, 3, 6])
1964 >>> np.ma.notmasked_edges(am)
1965 array([0, 6])
1967 """
1968 a = asarray(a)
1969 if axis is None or a.ndim == 1:
1970 return flatnotmasked_edges(a)
1971 m = getmaskarray(a)
1972 idx = array(np.indices(a.shape), mask=np.asarray([m] * a.ndim))
1973 return [tuple(idx[i].min(axis).compressed() for i in range(a.ndim)),
1974 tuple(idx[i].max(axis).compressed() for i in range(a.ndim)), ]
1977def flatnotmasked_contiguous(a):
1978 """
1979 Find contiguous unmasked data in a masked array.
1981 Parameters
1982 ----------
1983 a : array_like
1984 The input array.
1986 Returns
1987 -------
1988 slice_list : list
1989 A sorted sequence of `slice` objects (start index, end index).
1991 See Also
1992 --------
1993 flatnotmasked_edges, notmasked_contiguous, notmasked_edges
1994 clump_masked, clump_unmasked
1996 Notes
1997 -----
1998 Only accepts 2-D arrays at most.
2000 Examples
2001 --------
2002 >>> import numpy as np
2003 >>> a = np.ma.arange(10)
2004 >>> np.ma.flatnotmasked_contiguous(a)
2005 [slice(0, 10, None)]
2007 >>> mask = (a < 3) | (a > 8) | (a == 5)
2008 >>> a[mask] = np.ma.masked
2009 >>> np.array(a[~a.mask])
2010 array([3, 4, 6, 7, 8])
2012 >>> np.ma.flatnotmasked_contiguous(a)
2013 [slice(3, 5, None), slice(6, 9, None)]
2014 >>> a[:] = np.ma.masked
2015 >>> np.ma.flatnotmasked_contiguous(a)
2016 []
2018 """
2019 m = getmask(a)
2020 if m is nomask:
2021 return [slice(0, a.size)]
2022 i = 0
2023 result = []
2024 for (k, g) in itertools.groupby(m.ravel()):
2025 n = len(list(g))
2026 if not k:
2027 result.append(slice(i, i + n))
2028 i += n
2029 return result
2032def notmasked_contiguous(a, axis=None):
2033 """
2034 Find contiguous unmasked data in a masked array along the given axis.
2036 Parameters
2037 ----------
2038 a : array_like
2039 The input array.
2040 axis : int, optional
2041 Axis along which to perform the operation.
2042 If None (default), applies to a flattened version of the array, and this
2043 is the same as `flatnotmasked_contiguous`.
2045 Returns
2046 -------
2047 endpoints : list
2048 A list of slices (start and end indexes) of unmasked indexes
2049 in the array.
2051 If the input is 2d and axis is specified, the result is a list of lists.
2053 See Also
2054 --------
2055 flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
2056 clump_masked, clump_unmasked
2058 Notes
2059 -----
2060 Only accepts 2-D arrays at most.
2062 Examples
2063 --------
2064 >>> import numpy as np
2065 >>> a = np.arange(12).reshape((3, 4))
2066 >>> mask = np.zeros_like(a)
2067 >>> mask[1:, :-1] = 1; mask[0, 1] = 1; mask[-1, 0] = 0
2068 >>> ma = np.ma.array(a, mask=mask)
2069 >>> ma
2070 masked_array(
2071 data=[[0, --, 2, 3],
2072 [--, --, --, 7],
2073 [8, --, --, 11]],
2074 mask=[[False, True, False, False],
2075 [ True, True, True, False],
2076 [False, True, True, False]],
2077 fill_value=999999)
2078 >>> np.array(ma[~ma.mask])
2079 array([ 0, 2, 3, 7, 8, 11])
2081 >>> np.ma.notmasked_contiguous(ma)
2082 [slice(0, 1, None), slice(2, 4, None), slice(7, 9, None), slice(11, 12, None)]
2084 >>> np.ma.notmasked_contiguous(ma, axis=0)
2085 [[slice(0, 1, None), slice(2, 3, None)], [], [slice(0, 1, None)], [slice(0, 3, None)]]
2087 >>> np.ma.notmasked_contiguous(ma, axis=1)
2088 [[slice(0, 1, None), slice(2, 4, None)], [slice(3, 4, None)], [slice(0, 1, None), slice(3, 4, None)]]
2090 """ # noqa: E501
2091 a = asarray(a)
2092 nd = a.ndim
2093 if nd > 2:
2094 raise NotImplementedError("Currently limited to at most 2D array.")
2095 if axis is None or nd == 1:
2096 return flatnotmasked_contiguous(a)
2097 #
2098 result = []
2099 #
2100 other = (axis + 1) % 2
2101 idx = [0, 0]
2102 idx[axis] = slice(None, None)
2103 #
2104 for i in range(a.shape[other]):
2105 idx[other] = i
2106 result.append(flatnotmasked_contiguous(a[tuple(idx)]))
2107 return result
2110def _ezclump(mask):
2111 """
2112 Finds the clumps (groups of data with the same values) for a 1D bool array.
2114 Returns a series of slices.
2115 """
2116 if mask.ndim > 1:
2117 mask = mask.ravel()
2118 idx = (mask[1:] ^ mask[:-1]).nonzero()
2119 idx = idx[0] + 1
2121 if mask[0]:
2122 if len(idx) == 0:
2123 return [slice(0, mask.size)]
2125 r = [slice(0, idx[0])]
2126 r.extend((slice(left, right)
2127 for left, right in zip(idx[1:-1:2], idx[2::2])))
2128 else:
2129 if len(idx) == 0:
2130 return []
2132 r = [slice(left, right) for left, right in zip(idx[:-1:2], idx[1::2])]
2134 if mask[-1]:
2135 r.append(slice(idx[-1], mask.size))
2136 return r
2139def clump_unmasked(a):
2140 """
2141 Return list of slices corresponding to the unmasked clumps of a 1-D array.
2142 (A "clump" is defined as a contiguous region of the array).
2144 Parameters
2145 ----------
2146 a : ndarray
2147 A one-dimensional masked array.
2149 Returns
2150 -------
2151 slices : list of slice
2152 The list of slices, one for each continuous region of unmasked
2153 elements in `a`.
2155 See Also
2156 --------
2157 flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
2158 notmasked_contiguous, clump_masked
2160 Examples
2161 --------
2162 >>> import numpy as np
2163 >>> a = np.ma.masked_array(np.arange(10))
2164 >>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked
2165 >>> np.ma.clump_unmasked(a)
2166 [slice(3, 6, None), slice(7, 8, None)]
2168 """
2169 mask = getattr(a, '_mask', nomask)
2170 if mask is nomask:
2171 return [slice(0, a.size)]
2172 return _ezclump(~mask)
2175def clump_masked(a):
2176 """
2177 Returns a list of slices corresponding to the masked clumps of a 1-D array.
2178 (A "clump" is defined as a contiguous region of the array).
2180 Parameters
2181 ----------
2182 a : ndarray
2183 A one-dimensional masked array.
2185 Returns
2186 -------
2187 slices : list of slice
2188 The list of slices, one for each continuous region of masked elements
2189 in `a`.
2191 See Also
2192 --------
2193 flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
2194 notmasked_contiguous, clump_unmasked
2196 Examples
2197 --------
2198 >>> import numpy as np
2199 >>> a = np.ma.masked_array(np.arange(10))
2200 >>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked
2201 >>> np.ma.clump_masked(a)
2202 [slice(0, 3, None), slice(6, 7, None), slice(8, 10, None)]
2204 """
2205 mask = ma.getmask(a)
2206 if mask is nomask:
2207 return []
2208 return _ezclump(mask)
2211###############################################################################
2212# Polynomial fit #
2213###############################################################################
2216def vander(x, n=None):
2217 """
2218 Masked values in the input array result in rows of zeros.
2220 """
2221 _vander = np.vander(x, n)
2222 m = getmask(x)
2223 if m is not nomask:
2224 _vander[m] = 0
2225 return _vander
2228vander.__doc__ = ma.doc_note(np.vander.__doc__, vander.__doc__)
2231def polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False):
2232 """
2233 Any masked values in x is propagated in y, and vice-versa.
2235 """
2236 x = asarray(x)
2237 y = asarray(y)
2239 m = getmask(x)
2240 if y.ndim == 1:
2241 m = mask_or(m, getmask(y))
2242 elif y.ndim == 2:
2243 my = getmask(mask_rows(y))
2244 if my is not nomask:
2245 m = mask_or(m, my[:, 0])
2246 else:
2247 raise TypeError("Expected a 1D or 2D array for y!")
2249 if w is not None:
2250 w = asarray(w)
2251 if w.ndim != 1:
2252 raise TypeError("expected a 1-d array for weights")
2253 if w.shape[0] != y.shape[0]:
2254 raise TypeError("expected w and y to have the same length")
2255 m = mask_or(m, getmask(w))
2257 if m is not nomask:
2258 not_m = ~m
2259 if w is not None:
2260 w = w[not_m]
2261 return np.polyfit(x[not_m], y[not_m], deg, rcond, full, w, cov)
2262 else:
2263 return np.polyfit(x, y, deg, rcond, full, w, cov)
2266polyfit.__doc__ = ma.doc_note(np.polyfit.__doc__, polyfit.__doc__)