Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/numpy/ma/core.py: 27%
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"""
2numpy.ma : a package to handle missing or invalid values.
4This package was initially written for numarray by Paul F. Dubois
5at Lawrence Livermore National Laboratory.
6In 2006, the package was completely rewritten by Pierre Gerard-Marchant
7(University of Georgia) to make the MaskedArray class a subclass of ndarray,
8and to improve support of structured arrays.
11Copyright 1999, 2000, 2001 Regents of the University of California.
12Released for unlimited redistribution.
14* Adapted for numpy_core 2005 by Travis Oliphant and (mainly) Paul Dubois.
15* Subclassing of the base `ndarray` 2006 by Pierre Gerard-Marchant
16 (pgmdevlist_AT_gmail_DOT_com)
17* Improvements suggested by Reggie Dugard (reggie_AT_merfinllc_DOT_com)
19.. moduleauthor:: Pierre Gerard-Marchant
21"""
22import builtins
23import functools
24import inspect
25import operator
26import re
27import textwrap
28import warnings
30import numpy as np
31import numpy._core.numerictypes as ntypes
32import numpy._core.umath as umath
33from numpy import (
34 _NoValue,
35 amax,
36 amin,
37 angle,
38 array as narray, # noqa: F401
39 bool_,
40 expand_dims,
41 finfo, # noqa: F401
42 iinfo, # noqa: F401
43 iscomplexobj,
44 ndarray,
45)
46from numpy._core import multiarray as mu
47from numpy._core.numeric import normalize_axis_tuple
48from numpy._utils import set_module
50__all__ = [
51 'MAError', 'MaskError', 'MaskType', 'MaskedArray', 'abs', 'absolute',
52 'add', 'all', 'allclose', 'allequal', 'alltrue', 'amax', 'amin',
53 'angle', 'anom', 'anomalies', 'any', 'append', 'arange', 'arccos',
54 'arccosh', 'arcsin', 'arcsinh', 'arctan', 'arctan2', 'arctanh',
55 'argmax', 'argmin', 'argsort', 'around', 'array', 'asanyarray',
56 'asarray', 'bitwise_and', 'bitwise_or', 'bitwise_xor', 'bool_', 'ceil',
57 'choose', 'clip', 'common_fill_value', 'compress', 'compressed',
58 'concatenate', 'conjugate', 'convolve', 'copy', 'correlate', 'cos', 'cosh',
59 'count', 'cumprod', 'cumsum', 'default_fill_value', 'diag', 'diagonal',
60 'diff', 'divide', 'empty', 'empty_like', 'equal', 'exp',
61 'expand_dims', 'fabs', 'filled', 'fix_invalid', 'flatten_mask',
62 'flatten_structured_array', 'floor', 'floor_divide', 'fmod',
63 'frombuffer', 'fromflex', 'fromfunction', 'getdata', 'getmask',
64 'getmaskarray', 'greater', 'greater_equal', 'harden_mask', 'hypot',
65 'identity', 'ids', 'indices', 'inner', 'innerproduct', 'isMA',
66 'isMaskedArray', 'is_mask', 'is_masked', 'isarray', 'left_shift',
67 'less', 'less_equal', 'log', 'log10', 'log2',
68 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'make_mask',
69 'make_mask_descr', 'make_mask_none', 'mask_or', 'masked',
70 'masked_array', 'masked_equal', 'masked_greater',
71 'masked_greater_equal', 'masked_inside', 'masked_invalid',
72 'masked_less', 'masked_less_equal', 'masked_not_equal',
73 'masked_object', 'masked_outside', 'masked_print_option',
74 'masked_singleton', 'masked_values', 'masked_where', 'max', 'maximum',
75 'maximum_fill_value', 'mean', 'min', 'minimum', 'minimum_fill_value',
76 'mod', 'multiply', 'mvoid', 'ndim', 'negative', 'nomask', 'nonzero',
77 'not_equal', 'ones', 'ones_like', 'outer', 'outerproduct', 'power', 'prod',
78 'product', 'ptp', 'put', 'putmask', 'ravel', 'remainder',
79 'repeat', 'reshape', 'resize', 'right_shift', 'round', 'round_',
80 'set_fill_value', 'shape', 'sin', 'sinh', 'size', 'soften_mask',
81 'sometrue', 'sort', 'sqrt', 'squeeze', 'std', 'subtract', 'sum',
82 'swapaxes', 'take', 'tan', 'tanh', 'trace', 'transpose', 'true_divide',
83 'var', 'where', 'zeros', 'zeros_like',
84 ]
86MaskType = np.bool
87nomask = MaskType(0)
89class MaskedArrayFutureWarning(FutureWarning):
90 pass
92def _deprecate_argsort_axis(arr):
93 """
94 Adjust the axis passed to argsort, warning if necessary
96 Parameters
97 ----------
98 arr
99 The array which argsort was called on
101 np.ma.argsort has a long-term bug where the default of the axis argument
102 is wrong (gh-8701), which now must be kept for backwards compatibility.
103 Thankfully, this only makes a difference when arrays are 2- or more-
104 dimensional, so we only need a warning then.
105 """
106 if arr.ndim <= 1:
107 # no warning needed - but switch to -1 anyway, to avoid surprising
108 # subclasses, which are more likely to implement scalar axes.
109 return -1
110 else:
111 # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default
112 warnings.warn(
113 "In the future the default for argsort will be axis=-1, not the "
114 "current None, to match its documentation and np.argsort. "
115 "Explicitly pass -1 or None to silence this warning.",
116 MaskedArrayFutureWarning, stacklevel=3)
117 return None
120def doc_note(initialdoc, note):
121 """
122 Adds a Notes section to an existing docstring.
124 """
125 if initialdoc is None:
126 return
127 if note is None:
128 return initialdoc
130 notesplit = re.split(r'\n\s*?Notes\n\s*?-----', inspect.cleandoc(initialdoc))
131 notedoc = f"\n\nNotes\n-----\n{inspect.cleandoc(note)}\n"
133 return ''.join(notesplit[:1] + [notedoc] + notesplit[1:])
136###############################################################################
137# Exceptions #
138###############################################################################
141class MAError(Exception):
142 """
143 Class for masked array related errors.
145 """
146 pass
149class MaskError(MAError):
150 """
151 Class for mask related errors.
153 """
154 pass
157###############################################################################
158# Filling options #
159###############################################################################
162# b: boolean - c: complex - f: floats - i: integer - O: object - S: string
163default_filler = {'b': True,
164 'c': 1.e20 + 0.0j,
165 'f': 1.e20,
166 'i': 999999,
167 'O': '?',
168 'S': b'N/A',
169 'u': 999999,
170 'V': b'???',
171 'U': 'N/A',
172 'T': 'N/A'
173 }
175# Add datetime64 and timedelta64 types
176for v in ["Y", "M", "W", "D", "h", "m", "s", "ms", "us", "ns", "ps",
177 "fs", "as"]:
178 default_filler["M8[" + v + "]"] = np.datetime64("NaT", v)
179 default_filler["m8[" + v + "]"] = np.timedelta64("NaT", v)
181float_types_list = [np.half, np.single, np.double, np.longdouble,
182 np.csingle, np.cdouble, np.clongdouble]
184_minvals: dict[type, int] = {}
185_maxvals: dict[type, int] = {}
187for sctype in ntypes.sctypeDict.values():
188 scalar_dtype = np.dtype(sctype)
190 if scalar_dtype.kind in "Mm":
191 info = np.iinfo(np.int64)
192 min_val, max_val = info.min + 1, info.max
193 elif np.issubdtype(scalar_dtype, np.integer):
194 info = np.iinfo(sctype)
195 min_val, max_val = info.min, info.max
196 elif np.issubdtype(scalar_dtype, np.floating):
197 info = np.finfo(sctype)
198 min_val, max_val = info.min, info.max
199 elif scalar_dtype.kind == "b":
200 min_val, max_val = 0, 1
201 else:
202 min_val, max_val = None, None
204 _minvals[sctype] = min_val
205 _maxvals[sctype] = max_val
207max_filler = _minvals
208max_filler.update([(k, -np.inf) for k in float_types_list[:4]])
209max_filler.update([(k, complex(-np.inf, -np.inf)) for k in float_types_list[-3:]])
211min_filler = _maxvals
212min_filler.update([(k, +np.inf) for k in float_types_list[:4]])
213min_filler.update([(k, complex(+np.inf, +np.inf)) for k in float_types_list[-3:]])
215del float_types_list
217def _recursive_fill_value(dtype, f):
218 """
219 Recursively produce a fill value for `dtype`, calling f on scalar dtypes
220 """
221 if dtype.names is not None:
222 # We wrap into `array` here, which ensures we use NumPy cast rules
223 # for integer casts, this allows the use of 99999 as a fill value
224 # for int8.
225 # TODO: This is probably a mess, but should best preserve behavior?
226 vals = tuple(
227 np.array(_recursive_fill_value(dtype[name], f))
228 for name in dtype.names)
229 return np.array(vals, dtype=dtype)[()] # decay to void scalar from 0d
230 elif dtype.subdtype:
231 subtype, shape = dtype.subdtype
232 subval = _recursive_fill_value(subtype, f)
233 return np.full(shape, subval)
234 else:
235 return f(dtype)
238def _get_dtype_of(obj):
239 """ Convert the argument for *_fill_value into a dtype """
240 if isinstance(obj, np.dtype):
241 return obj
242 elif hasattr(obj, 'dtype'):
243 return obj.dtype
244 else:
245 return np.asanyarray(obj).dtype
248def default_fill_value(obj):
249 """
250 Return the default fill value for the argument object.
252 The default filling value depends on the datatype of the input
253 array or the type of the input scalar:
255 =========== ========
256 datatype default
257 =========== ========
258 bool True
259 int 999999
260 float 1.e20
261 complex 1.e20+0j
262 object '?'
263 string 'N/A'
264 StringDType 'N/A'
265 =========== ========
267 For structured types, a structured scalar is returned, with each field the
268 default fill value for its type.
270 For subarray types, the fill value is an array of the same size containing
271 the default scalar fill value.
273 Parameters
274 ----------
275 obj : ndarray, dtype or scalar
276 The array data-type or scalar for which the default fill value
277 is returned.
279 Returns
280 -------
281 fill_value : scalar
282 The default fill value.
284 Examples
285 --------
286 >>> import numpy as np
287 >>> np.ma.default_fill_value(1)
288 999999
289 >>> np.ma.default_fill_value(np.array([1.1, 2., np.pi]))
290 1e+20
291 >>> np.ma.default_fill_value(np.dtype(complex))
292 (1e+20+0j)
294 """
295 def _scalar_fill_value(dtype):
296 if dtype.kind in 'Mm':
297 return default_filler.get(dtype.str[1:], '?')
298 else:
299 return default_filler.get(dtype.kind, '?')
301 dtype = _get_dtype_of(obj)
302 return _recursive_fill_value(dtype, _scalar_fill_value)
305def _extremum_fill_value(obj, extremum, extremum_name):
307 def _scalar_fill_value(dtype):
308 try:
309 return extremum[dtype.type]
310 except KeyError as e:
311 raise TypeError(
312 f"Unsuitable type {dtype} for calculating {extremum_name}."
313 ) from None
315 dtype = _get_dtype_of(obj)
316 return _recursive_fill_value(dtype, _scalar_fill_value)
319def minimum_fill_value(obj):
320 """
321 Return the maximum value that can be represented by the dtype of an object.
323 This function is useful for calculating a fill value suitable for
324 taking the minimum of an array with a given dtype.
326 Parameters
327 ----------
328 obj : ndarray, dtype or scalar
329 An object that can be queried for it's numeric type.
331 Returns
332 -------
333 val : scalar
334 The maximum representable value.
336 Raises
337 ------
338 TypeError
339 If `obj` isn't a suitable numeric type.
341 See Also
342 --------
343 maximum_fill_value : The inverse function.
344 set_fill_value : Set the filling value of a masked array.
345 MaskedArray.fill_value : Return current fill value.
347 Examples
348 --------
349 >>> import numpy as np
350 >>> import numpy.ma as ma
351 >>> a = np.int8()
352 >>> ma.minimum_fill_value(a)
353 127
354 >>> a = np.int32()
355 >>> ma.minimum_fill_value(a)
356 2147483647
358 An array of numeric data can also be passed.
360 >>> a = np.array([1, 2, 3], dtype=np.int8)
361 >>> ma.minimum_fill_value(a)
362 127
363 >>> a = np.array([1, 2, 3], dtype=np.float32)
364 >>> ma.minimum_fill_value(a)
365 inf
367 """
368 return _extremum_fill_value(obj, min_filler, "minimum")
371def maximum_fill_value(obj):
372 """
373 Return the minimum value that can be represented by the dtype of an object.
375 This function is useful for calculating a fill value suitable for
376 taking the maximum of an array with a given dtype.
378 Parameters
379 ----------
380 obj : ndarray, dtype or scalar
381 An object that can be queried for it's numeric type.
383 Returns
384 -------
385 val : scalar
386 The minimum representable value.
388 Raises
389 ------
390 TypeError
391 If `obj` isn't a suitable numeric type.
393 See Also
394 --------
395 minimum_fill_value : The inverse function.
396 set_fill_value : Set the filling value of a masked array.
397 MaskedArray.fill_value : Return current fill value.
399 Examples
400 --------
401 >>> import numpy as np
402 >>> import numpy.ma as ma
403 >>> a = np.int8()
404 >>> ma.maximum_fill_value(a)
405 -128
406 >>> a = np.int32()
407 >>> ma.maximum_fill_value(a)
408 -2147483648
410 An array of numeric data can also be passed.
412 >>> a = np.array([1, 2, 3], dtype=np.int8)
413 >>> ma.maximum_fill_value(a)
414 -128
415 >>> a = np.array([1, 2, 3], dtype=np.float32)
416 >>> ma.maximum_fill_value(a)
417 -inf
419 """
420 return _extremum_fill_value(obj, max_filler, "maximum")
423def _recursive_set_fill_value(fillvalue, dt):
424 """
425 Create a fill value for a structured dtype.
427 Parameters
428 ----------
429 fillvalue : scalar or array_like
430 Scalar or array representing the fill value. If it is of shorter
431 length than the number of fields in dt, it will be resized.
432 dt : dtype
433 The structured dtype for which to create the fill value.
435 Returns
436 -------
437 val : tuple
438 A tuple of values corresponding to the structured fill value.
440 """
441 fillvalue = np.resize(fillvalue, len(dt.names))
442 output_value = []
443 for (fval, name) in zip(fillvalue, dt.names):
444 cdtype = dt[name]
445 if cdtype.subdtype:
446 cdtype = cdtype.subdtype[0]
448 if cdtype.names is not None:
449 output_value.append(tuple(_recursive_set_fill_value(fval, cdtype)))
450 else:
451 output_value.append(np.array(fval, dtype=cdtype).item())
452 return tuple(output_value)
455def _check_fill_value(fill_value, ndtype):
456 """
457 Private function validating the given `fill_value` for the given dtype.
459 If fill_value is None, it is set to the default corresponding to the dtype.
461 If fill_value is not None, its value is forced to the given dtype.
463 The result is always a 0d array.
465 """
466 ndtype = np.dtype(ndtype)
467 if fill_value is None:
468 fill_value = default_fill_value(ndtype)
469 # TODO: It seems better to always store a valid fill_value, the oddity
470 # about is that `_fill_value = None` would behave even more
471 # different then.
472 # (e.g. this allows arr_uint8.astype(int64) to have the default
473 # fill value again...)
474 # The one thing that changed in 2.0/2.1 around cast safety is that the
475 # default `int(99...)` is not a same-kind cast anymore, so if we
476 # have a uint, use the default uint.
477 if ndtype.kind == "u":
478 fill_value = np.uint(fill_value)
479 elif ndtype.names is not None:
480 if isinstance(fill_value, (ndarray, np.void)):
481 try:
482 fill_value = np.asarray(fill_value, dtype=ndtype)
483 except ValueError as e:
484 err_msg = "Unable to transform %s to dtype %s"
485 raise ValueError(err_msg % (fill_value, ndtype)) from e
486 else:
487 fill_value = np.asarray(fill_value, dtype=object)
488 fill_value = np.array(_recursive_set_fill_value(fill_value, ndtype),
489 dtype=ndtype)
490 elif isinstance(fill_value, str) and (ndtype.char not in 'OSTVU'):
491 # Note this check doesn't work if fill_value is not a scalar
492 err_msg = "Cannot set fill value of string with array of dtype %s"
493 raise TypeError(err_msg % ndtype)
494 else:
495 # In case we want to convert 1e20 to int.
496 # Also in case of converting string arrays.
497 try:
498 fill_value = np.asarray(fill_value, dtype=ndtype)
499 except (OverflowError, ValueError) as e:
500 # Raise TypeError instead of OverflowError or ValueError.
501 # OverflowError is seldom used, and the real problem here is
502 # that the passed fill_value is not compatible with the ndtype.
503 err_msg = "Cannot convert fill_value %s to dtype %s"
504 raise TypeError(err_msg % (fill_value, ndtype)) from e
505 return np.array(fill_value)
508def set_fill_value(a, fill_value):
509 """
510 Set the filling value of a, if a is a masked array.
512 This function changes the fill value of the masked array `a` in place.
513 If `a` is not a masked array, the function returns silently, without
514 doing anything.
516 Parameters
517 ----------
518 a : array_like
519 Input array.
520 fill_value : dtype
521 Filling value. A consistency test is performed to make sure
522 the value is compatible with the dtype of `a`.
524 Returns
525 -------
526 None
527 Nothing returned by this function.
529 See Also
530 --------
531 maximum_fill_value : Return the default fill value for a dtype.
532 MaskedArray.fill_value : Return current fill value.
533 MaskedArray.set_fill_value : Equivalent method.
535 Examples
536 --------
537 >>> import numpy as np
538 >>> import numpy.ma as ma
539 >>> a = np.arange(5)
540 >>> a
541 array([0, 1, 2, 3, 4])
542 >>> a = ma.masked_where(a < 3, a)
543 >>> a
544 masked_array(data=[--, --, --, 3, 4],
545 mask=[ True, True, True, False, False],
546 fill_value=999999)
547 >>> ma.set_fill_value(a, -999)
548 >>> a
549 masked_array(data=[--, --, --, 3, 4],
550 mask=[ True, True, True, False, False],
551 fill_value=-999)
553 Nothing happens if `a` is not a masked array.
555 >>> a = list(range(5))
556 >>> a
557 [0, 1, 2, 3, 4]
558 >>> ma.set_fill_value(a, 100)
559 >>> a
560 [0, 1, 2, 3, 4]
561 >>> a = np.arange(5)
562 >>> a
563 array([0, 1, 2, 3, 4])
564 >>> ma.set_fill_value(a, 100)
565 >>> a
566 array([0, 1, 2, 3, 4])
568 """
569 if isinstance(a, MaskedArray):
570 a.set_fill_value(fill_value)
573def get_fill_value(a):
574 """
575 Return the filling value of a, if any. Otherwise, returns the
576 default filling value for that type.
578 """
579 if isinstance(a, MaskedArray):
580 result = a.fill_value
581 else:
582 result = default_fill_value(a)
583 return result
586def common_fill_value(a, b):
587 """
588 Return the common filling value of two masked arrays, if any.
590 If ``a.fill_value == b.fill_value``, return the fill value,
591 otherwise return None.
593 Parameters
594 ----------
595 a, b : MaskedArray
596 The masked arrays for which to compare fill values.
598 Returns
599 -------
600 fill_value : scalar or None
601 The common fill value, or None.
603 Examples
604 --------
605 >>> import numpy as np
606 >>> x = np.ma.array([0, 1.], fill_value=3)
607 >>> y = np.ma.array([0, 1.], fill_value=3)
608 >>> np.ma.common_fill_value(x, y)
609 3.0
611 """
612 t1 = get_fill_value(a)
613 t2 = get_fill_value(b)
614 if t1 == t2:
615 return t1
616 return None
619def filled(a, fill_value=None):
620 """
621 Return input as an `~numpy.ndarray`, with masked values replaced by
622 `fill_value`.
624 If `a` is not a `MaskedArray`, `a` itself is returned.
625 If `a` is a `MaskedArray` with no masked values, then ``a.data`` is
626 returned.
627 If `a` is a `MaskedArray` and `fill_value` is None, `fill_value` is set to
628 ``a.fill_value``.
630 Parameters
631 ----------
632 a : MaskedArray or array_like
633 An input object.
634 fill_value : array_like, optional.
635 Can be scalar or non-scalar. If non-scalar, the
636 resulting filled array should be broadcastable
637 over input array. Default is None.
639 Returns
640 -------
641 a : ndarray
642 The filled array.
644 See Also
645 --------
646 compressed
648 Examples
649 --------
650 >>> import numpy as np
651 >>> import numpy.ma as ma
652 >>> x = ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0],
653 ... [1, 0, 0],
654 ... [0, 0, 0]])
655 >>> x.filled()
656 array([[999999, 1, 2],
657 [999999, 4, 5],
658 [ 6, 7, 8]])
659 >>> x.filled(fill_value=333)
660 array([[333, 1, 2],
661 [333, 4, 5],
662 [ 6, 7, 8]])
663 >>> x.filled(fill_value=np.arange(3))
664 array([[0, 1, 2],
665 [0, 4, 5],
666 [6, 7, 8]])
668 """
669 if hasattr(a, 'filled'):
670 return a.filled(fill_value)
672 elif isinstance(a, ndarray):
673 # Should we check for contiguity ? and a.flags['CONTIGUOUS']:
674 return a
675 elif isinstance(a, dict):
676 return np.array(a, 'O')
677 else:
678 return np.array(a)
681def get_masked_subclass(*arrays):
682 """
683 Return the youngest subclass of MaskedArray from a list of (masked) arrays.
685 In case of siblings, the first listed takes over.
687 """
688 if len(arrays) == 1:
689 arr = arrays[0]
690 if isinstance(arr, MaskedArray):
691 rcls = type(arr)
692 else:
693 rcls = MaskedArray
694 else:
695 arrcls = [type(a) for a in arrays]
696 rcls = arrcls[0]
697 if not issubclass(rcls, MaskedArray):
698 rcls = MaskedArray
699 for cls in arrcls[1:]:
700 if issubclass(cls, rcls):
701 rcls = cls
702 # Don't return MaskedConstant as result: revert to MaskedArray
703 if rcls.__name__ == 'MaskedConstant':
704 return MaskedArray
705 return rcls
708def getdata(a, subok=True):
709 """
710 Return the data of a masked array as an ndarray.
712 Return the data of `a` (if any) as an ndarray if `a` is a ``MaskedArray``,
713 else return `a` as a ndarray or subclass (depending on `subok`) if not.
715 Parameters
716 ----------
717 a : array_like
718 Input ``MaskedArray``, alternatively a ndarray or a subclass thereof.
719 subok : bool
720 Whether to force the output to be a `pure` ndarray (False) or to
721 return a subclass of ndarray if appropriate (True, default).
723 See Also
724 --------
725 getmask : Return the mask of a masked array, or nomask.
726 getmaskarray : Return the mask of a masked array, or full array of False.
728 Examples
729 --------
730 >>> import numpy as np
731 >>> import numpy.ma as ma
732 >>> a = ma.masked_equal([[1,2],[3,4]], 2)
733 >>> a
734 masked_array(
735 data=[[1, --],
736 [3, 4]],
737 mask=[[False, True],
738 [False, False]],
739 fill_value=2)
740 >>> ma.getdata(a)
741 array([[1, 2],
742 [3, 4]])
744 Equivalently use the ``MaskedArray`` `data` attribute.
746 >>> a.data
747 array([[1, 2],
748 [3, 4]])
750 """
751 try:
752 data = a._data
753 except AttributeError:
754 data = np.array(a, copy=None, subok=subok)
755 if not subok:
756 return data.view(ndarray)
757 return data
760get_data = getdata
763def fix_invalid(a, mask=nomask, copy=True, fill_value=None):
764 """
765 Return input with invalid data masked and replaced by a fill value.
767 Invalid data means values of `nan`, `inf`, etc.
769 Parameters
770 ----------
771 a : array_like
772 Input array, a (subclass of) ndarray.
773 mask : sequence, optional
774 Mask. Must be convertible to an array of booleans with the same
775 shape as `data`. True indicates a masked (i.e. invalid) data.
776 copy : bool, optional
777 Whether to use a copy of `a` (True) or to fix `a` in place (False).
778 Default is True.
779 fill_value : scalar, optional
780 Value used for fixing invalid data. Default is None, in which case
781 the ``a.fill_value`` is used.
783 Returns
784 -------
785 b : MaskedArray
786 The input array with invalid entries fixed.
788 Notes
789 -----
790 A copy is performed by default.
792 Examples
793 --------
794 >>> import numpy as np
795 >>> x = np.ma.array([1., -1, np.nan, np.inf], mask=[1] + [0]*3)
796 >>> x
797 masked_array(data=[--, -1.0, nan, inf],
798 mask=[ True, False, False, False],
799 fill_value=1e+20)
800 >>> np.ma.fix_invalid(x)
801 masked_array(data=[--, -1.0, --, --],
802 mask=[ True, False, True, True],
803 fill_value=1e+20)
805 >>> fixed = np.ma.fix_invalid(x)
806 >>> fixed.data
807 array([ 1.e+00, -1.e+00, 1.e+20, 1.e+20])
808 >>> x.data
809 array([ 1., -1., nan, inf])
811 """
812 a = masked_array(a, copy=copy, mask=mask, subok=True)
813 invalid = np.logical_not(np.isfinite(a._data))
814 if not invalid.any():
815 return a
816 a._mask |= invalid
817 if fill_value is None:
818 fill_value = a.fill_value
819 a._data[invalid] = fill_value
820 return a
822def is_string_or_list_of_strings(val):
823 return (isinstance(val, str) or
824 (isinstance(val, list) and val and
825 builtins.all(isinstance(s, str) for s in val)))
827###############################################################################
828# Ufuncs #
829###############################################################################
832ufunc_domain = {}
833ufunc_fills = {}
836class _DomainCheckInterval:
837 """
838 Define a valid interval, so that :
840 ``domain_check_interval(a,b)(x) == True`` where
841 ``x < a`` or ``x > b``.
843 """
845 def __init__(self, a, b):
846 "domain_check_interval(a,b)(x) = true where x < a or y > b"
847 if a > b:
848 (a, b) = (b, a)
849 self.a = a
850 self.b = b
852 def __call__(self, x):
853 "Execute the call behavior."
854 # nans at masked positions cause RuntimeWarnings, even though
855 # they are masked. To avoid this we suppress warnings.
856 with np.errstate(invalid='ignore'):
857 return umath.logical_or(umath.greater(x, self.b),
858 umath.less(x, self.a))
861class _DomainTan:
862 """
863 Define a valid interval for the `tan` function, so that:
865 ``domain_tan(eps) = True`` where ``abs(cos(x)) < eps``
867 """
869 def __init__(self, eps):
870 "domain_tan(eps) = true where abs(cos(x)) < eps)"
871 self.eps = eps
873 def __call__(self, x):
874 "Executes the call behavior."
875 with np.errstate(invalid='ignore'):
876 return umath.less(umath.absolute(umath.cos(x)), self.eps)
879class _DomainSafeDivide:
880 """
881 Define a domain for safe division.
883 """
885 def __init__(self, tolerance=None):
886 self.tolerance = tolerance
888 def __call__(self, a, b):
889 # Delay the selection of the tolerance to here in order to reduce numpy
890 # import times. The calculation of these parameters is a substantial
891 # component of numpy's import time.
892 if self.tolerance is None:
893 self.tolerance = np.finfo(float).tiny
894 # don't call ma ufuncs from __array_wrap__ which would fail for scalars
895 a, b = np.asarray(a), np.asarray(b)
896 with np.errstate(all='ignore'):
897 return umath.absolute(a) * self.tolerance >= umath.absolute(b)
900class _DomainGreater:
901 """
902 DomainGreater(v)(x) is True where x <= v.
904 """
906 def __init__(self, critical_value):
907 "DomainGreater(v)(x) = true where x <= v"
908 self.critical_value = critical_value
910 def __call__(self, x):
911 "Executes the call behavior."
912 with np.errstate(invalid='ignore'):
913 return umath.less_equal(x, self.critical_value)
916class _DomainGreaterEqual:
917 """
918 DomainGreaterEqual(v)(x) is True where x < v.
920 """
922 def __init__(self, critical_value):
923 "DomainGreaterEqual(v)(x) = true where x < v"
924 self.critical_value = critical_value
926 def __call__(self, x):
927 "Executes the call behavior."
928 with np.errstate(invalid='ignore'):
929 return umath.less(x, self.critical_value)
932class _MaskedUFunc:
933 def __init__(self, ufunc):
934 self.f = ufunc
935 self.__doc__ = ufunc.__doc__
936 self.__name__ = ufunc.__name__
937 self.__qualname__ = ufunc.__qualname__
939 def __str__(self):
940 return f"Masked version of {self.f}"
943class _MaskedUnaryOperation(_MaskedUFunc):
944 """
945 Defines masked version of unary operations, where invalid values are
946 pre-masked.
948 Parameters
949 ----------
950 mufunc : callable
951 The function for which to define a masked version. Made available
952 as ``_MaskedUnaryOperation.f``.
953 fill : scalar, optional
954 Filling value, default is 0.
955 domain : class instance
956 Domain for the function. Should be one of the ``_Domain*``
957 classes. Default is None.
959 """
961 def __init__(self, mufunc, fill=0, domain=None):
962 super().__init__(mufunc)
963 self.fill = fill
964 self.domain = domain
965 ufunc_domain[mufunc] = domain
966 ufunc_fills[mufunc] = fill
968 def __call__(self, a, *args, **kwargs):
969 """
970 Execute the call behavior.
972 """
973 d = getdata(a)
974 # Deal with domain
975 if self.domain is not None:
976 # Case 1.1. : Domained function
977 # nans at masked positions cause RuntimeWarnings, even though
978 # they are masked. To avoid this we suppress warnings.
979 with np.errstate(divide='ignore', invalid='ignore'):
980 result = self.f(d, *args, **kwargs)
981 # Make a mask
982 m = ~umath.isfinite(result)
983 m |= self.domain(d)
984 m |= getmask(a)
985 else:
986 # Case 1.2. : Function without a domain
987 # Get the result and the mask
988 with np.errstate(divide='ignore', invalid='ignore'):
989 result = self.f(d, *args, **kwargs)
990 m = getmask(a)
992 if not result.ndim:
993 # Case 2.1. : The result is scalarscalar
994 if m:
995 return masked
996 return result
998 if m is not nomask:
999 # Case 2.2. The result is an array
1000 # We need to fill the invalid data back w/ the input Now,
1001 # that's plain silly: in C, we would just skip the element and
1002 # keep the original, but we do have to do it that way in Python
1004 # In case result has a lower dtype than the inputs (as in
1005 # equal)
1006 try:
1007 np.copyto(result, d, where=m)
1008 except TypeError:
1009 pass
1010 # Transform to
1011 masked_result = result.view(get_masked_subclass(a))
1012 masked_result._mask = m
1013 masked_result._update_from(a)
1014 return masked_result
1017class _MaskedBinaryOperation(_MaskedUFunc):
1018 """
1019 Define masked version of binary operations, where invalid
1020 values are pre-masked.
1022 Parameters
1023 ----------
1024 mbfunc : function
1025 The function for which to define a masked version. Made available
1026 as ``_MaskedBinaryOperation.f``.
1027 domain : class instance
1028 Default domain for the function. Should be one of the ``_Domain*``
1029 classes. Default is None.
1030 fillx : scalar, optional
1031 Filling value for the first argument, default is 0.
1032 filly : scalar, optional
1033 Filling value for the second argument, default is 0.
1035 """
1037 def __init__(self, mbfunc, fillx=0, filly=0):
1038 """
1039 abfunc(fillx, filly) must be defined.
1041 abfunc(x, filly) = x for all x to enable reduce.
1043 """
1044 super().__init__(mbfunc)
1045 self.fillx = fillx
1046 self.filly = filly
1047 ufunc_domain[mbfunc] = None
1048 ufunc_fills[mbfunc] = (fillx, filly)
1050 def __call__(self, a, b, *args, **kwargs):
1051 """
1052 Execute the call behavior.
1054 """
1055 # Get the data, as ndarray
1056 (da, db) = (getdata(a), getdata(b))
1057 # Get the result
1058 with np.errstate():
1059 np.seterr(divide='ignore', invalid='ignore')
1060 result = self.f(da, db, *args, **kwargs)
1061 # Get the mask for the result
1062 (ma, mb) = (getmask(a), getmask(b))
1063 if ma is nomask:
1064 if mb is nomask:
1065 m = nomask
1066 else:
1067 m = umath.logical_or(getmaskarray(a), mb)
1068 elif mb is nomask:
1069 m = umath.logical_or(ma, getmaskarray(b))
1070 else:
1071 m = umath.logical_or(ma, mb)
1073 # Case 1. : scalar
1074 if not result.ndim:
1075 if m:
1076 return masked
1077 return result
1079 # Case 2. : array
1080 # Revert result to da where masked
1081 if m is not nomask and m.any():
1082 # any errors, just abort; impossible to guarantee masked values
1083 try:
1084 np.copyto(result, da, casting='unsafe', where=m)
1085 except Exception:
1086 pass
1088 # Transforms to a (subclass of) MaskedArray
1089 masked_result = result.view(get_masked_subclass(a, b))
1090 masked_result._mask = m
1091 if isinstance(a, MaskedArray):
1092 masked_result._update_from(a)
1093 elif isinstance(b, MaskedArray):
1094 masked_result._update_from(b)
1095 return masked_result
1097 def reduce(self, target, axis=0, dtype=None):
1098 """
1099 Reduce `target` along the given `axis`.
1101 """
1102 tclass = get_masked_subclass(target)
1103 m = getmask(target)
1104 t = filled(target, self.filly)
1105 if t.shape == ():
1106 t = t.reshape(1)
1107 if m is not nomask:
1108 m = make_mask(m, copy=True)
1109 m.shape = (1,)
1111 if m is nomask:
1112 tr = self.f.reduce(t, axis)
1113 mr = nomask
1114 else:
1115 tr = self.f.reduce(t, axis, dtype=dtype)
1116 mr = umath.logical_and.reduce(m, axis)
1118 if not tr.shape:
1119 if mr:
1120 return masked
1121 else:
1122 return tr
1123 masked_tr = tr.view(tclass)
1124 masked_tr._mask = mr
1125 return masked_tr
1127 def outer(self, a, b):
1128 """
1129 Return the function applied to the outer product of a and b.
1131 """
1132 (da, db) = (getdata(a), getdata(b))
1133 d = self.f.outer(da, db)
1134 ma = getmask(a)
1135 mb = getmask(b)
1136 if ma is nomask and mb is nomask:
1137 m = nomask
1138 else:
1139 ma = getmaskarray(a)
1140 mb = getmaskarray(b)
1141 m = umath.logical_or.outer(ma, mb)
1142 if (not m.ndim) and m:
1143 return masked
1144 if m is not nomask:
1145 np.copyto(d, da, where=m)
1146 if not d.shape:
1147 return d
1148 masked_d = d.view(get_masked_subclass(a, b))
1149 masked_d._mask = m
1150 return masked_d
1152 def accumulate(self, target, axis=0):
1153 """Accumulate `target` along `axis` after filling with y fill
1154 value.
1156 """
1157 tclass = get_masked_subclass(target)
1158 t = filled(target, self.filly)
1159 result = self.f.accumulate(t, axis)
1160 masked_result = result.view(tclass)
1161 return masked_result
1164class _DomainedBinaryOperation(_MaskedUFunc):
1165 """
1166 Define binary operations that have a domain, like divide.
1168 They have no reduce, outer or accumulate.
1170 Parameters
1171 ----------
1172 mbfunc : function
1173 The function for which to define a masked version. Made available
1174 as ``_DomainedBinaryOperation.f``.
1175 domain : class instance
1176 Default domain for the function. Should be one of the ``_Domain*``
1177 classes.
1178 fillx : scalar, optional
1179 Filling value for the first argument, default is 0.
1180 filly : scalar, optional
1181 Filling value for the second argument, default is 0.
1183 """
1185 def __init__(self, dbfunc, domain, fillx=0, filly=0):
1186 """abfunc(fillx, filly) must be defined.
1187 abfunc(x, filly) = x for all x to enable reduce.
1188 """
1189 super().__init__(dbfunc)
1190 self.domain = domain
1191 self.fillx = fillx
1192 self.filly = filly
1193 ufunc_domain[dbfunc] = domain
1194 ufunc_fills[dbfunc] = (fillx, filly)
1196 def __call__(self, a, b, *args, **kwargs):
1197 "Execute the call behavior."
1198 # Get the data
1199 (da, db) = (getdata(a), getdata(b))
1200 # Get the result
1201 with np.errstate(divide='ignore', invalid='ignore'):
1202 result = self.f(da, db, *args, **kwargs)
1203 # Get the mask as a combination of the source masks and invalid
1204 m = ~umath.isfinite(result)
1205 m |= getmask(a)
1206 m |= getmask(b)
1207 # Apply the domain
1208 domain = ufunc_domain.get(self.f, None)
1209 if domain is not None:
1210 m |= domain(da, db)
1211 # Take care of the scalar case first
1212 if not m.ndim:
1213 if m:
1214 return masked
1215 else:
1216 return result
1217 # When the mask is True, put back da if possible
1218 # any errors, just abort; impossible to guarantee masked values
1219 try:
1220 np.copyto(result, 0, casting='unsafe', where=m)
1221 # avoid using "*" since this may be overlaid
1222 masked_da = umath.multiply(m, da)
1223 # only add back if it can be cast safely
1224 if np.can_cast(masked_da.dtype, result.dtype, casting='safe'):
1225 result += masked_da
1226 except Exception:
1227 pass
1229 # Transforms to a (subclass of) MaskedArray
1230 masked_result = result.view(get_masked_subclass(a, b))
1231 masked_result._mask = m
1232 if isinstance(a, MaskedArray):
1233 masked_result._update_from(a)
1234 elif isinstance(b, MaskedArray):
1235 masked_result._update_from(b)
1236 return masked_result
1239# Unary ufuncs
1240exp = _MaskedUnaryOperation(umath.exp)
1241conjugate = _MaskedUnaryOperation(umath.conjugate)
1242sin = _MaskedUnaryOperation(umath.sin)
1243cos = _MaskedUnaryOperation(umath.cos)
1244arctan = _MaskedUnaryOperation(umath.arctan)
1245arcsinh = _MaskedUnaryOperation(umath.arcsinh)
1246sinh = _MaskedUnaryOperation(umath.sinh)
1247cosh = _MaskedUnaryOperation(umath.cosh)
1248tanh = _MaskedUnaryOperation(umath.tanh)
1249abs = absolute = _MaskedUnaryOperation(umath.absolute)
1250angle = _MaskedUnaryOperation(angle)
1251fabs = _MaskedUnaryOperation(umath.fabs)
1252negative = _MaskedUnaryOperation(umath.negative)
1253floor = _MaskedUnaryOperation(umath.floor)
1254ceil = _MaskedUnaryOperation(umath.ceil)
1255around = _MaskedUnaryOperation(np.around)
1256logical_not = _MaskedUnaryOperation(umath.logical_not)
1258# Domained unary ufuncs
1259sqrt = _MaskedUnaryOperation(umath.sqrt, 0.0,
1260 _DomainGreaterEqual(0.0))
1261log = _MaskedUnaryOperation(umath.log, 1.0,
1262 _DomainGreater(0.0))
1263log2 = _MaskedUnaryOperation(umath.log2, 1.0,
1264 _DomainGreater(0.0))
1265log10 = _MaskedUnaryOperation(umath.log10, 1.0,
1266 _DomainGreater(0.0))
1267tan = _MaskedUnaryOperation(umath.tan, 0.0,
1268 _DomainTan(1e-35))
1269arcsin = _MaskedUnaryOperation(umath.arcsin, 0.0,
1270 _DomainCheckInterval(-1.0, 1.0))
1271arccos = _MaskedUnaryOperation(umath.arccos, 0.0,
1272 _DomainCheckInterval(-1.0, 1.0))
1273arccosh = _MaskedUnaryOperation(umath.arccosh, 1.0,
1274 _DomainGreaterEqual(1.0))
1275arctanh = _MaskedUnaryOperation(umath.arctanh, 0.0,
1276 _DomainCheckInterval(-1.0 + 1e-15, 1.0 - 1e-15))
1278# Binary ufuncs
1279add = _MaskedBinaryOperation(umath.add)
1280subtract = _MaskedBinaryOperation(umath.subtract)
1281multiply = _MaskedBinaryOperation(umath.multiply, 1, 1)
1282arctan2 = _MaskedBinaryOperation(umath.arctan2, 0.0, 1.0)
1283equal = _MaskedBinaryOperation(umath.equal)
1284equal.reduce = None
1285not_equal = _MaskedBinaryOperation(umath.not_equal)
1286not_equal.reduce = None
1287less_equal = _MaskedBinaryOperation(umath.less_equal)
1288less_equal.reduce = None
1289greater_equal = _MaskedBinaryOperation(umath.greater_equal)
1290greater_equal.reduce = None
1291less = _MaskedBinaryOperation(umath.less)
1292less.reduce = None
1293greater = _MaskedBinaryOperation(umath.greater)
1294greater.reduce = None
1295logical_and = _MaskedBinaryOperation(umath.logical_and)
1296alltrue = _MaskedBinaryOperation(umath.logical_and, 1, 1).reduce
1297logical_or = _MaskedBinaryOperation(umath.logical_or)
1298sometrue = logical_or.reduce
1299logical_xor = _MaskedBinaryOperation(umath.logical_xor)
1300bitwise_and = _MaskedBinaryOperation(umath.bitwise_and)
1301bitwise_or = _MaskedBinaryOperation(umath.bitwise_or)
1302bitwise_xor = _MaskedBinaryOperation(umath.bitwise_xor)
1303hypot = _MaskedBinaryOperation(umath.hypot)
1305# Domained binary ufuncs
1306divide = _DomainedBinaryOperation(umath.divide, _DomainSafeDivide(), 0, 1)
1307true_divide = divide # Just an alias for divide.
1308floor_divide = _DomainedBinaryOperation(umath.floor_divide,
1309 _DomainSafeDivide(), 0, 1)
1310remainder = _DomainedBinaryOperation(umath.remainder,
1311 _DomainSafeDivide(), 0, 1)
1312fmod = _DomainedBinaryOperation(umath.fmod, _DomainSafeDivide(), 0, 1)
1313mod = remainder
1315###############################################################################
1316# Mask creation functions #
1317###############################################################################
1320def _replace_dtype_fields_recursive(dtype, primitive_dtype):
1321 "Private function allowing recursion in _replace_dtype_fields."
1322 _recurse = _replace_dtype_fields_recursive
1324 # Do we have some name fields ?
1325 if dtype.names is not None:
1326 descr = []
1327 for name in dtype.names:
1328 field = dtype.fields[name]
1329 if len(field) == 3:
1330 # Prepend the title to the name
1331 name = (field[-1], name)
1332 descr.append((name, _recurse(field[0], primitive_dtype)))
1333 new_dtype = np.dtype(descr)
1335 # Is this some kind of composite a la (float,2)
1336 elif dtype.subdtype:
1337 descr = list(dtype.subdtype)
1338 descr[0] = _recurse(dtype.subdtype[0], primitive_dtype)
1339 new_dtype = np.dtype(tuple(descr))
1341 # this is a primitive type, so do a direct replacement
1342 else:
1343 new_dtype = primitive_dtype
1345 # preserve identity of dtypes
1346 if new_dtype == dtype:
1347 new_dtype = dtype
1349 return new_dtype
1352def _replace_dtype_fields(dtype, primitive_dtype):
1353 """
1354 Construct a dtype description list from a given dtype.
1356 Returns a new dtype object, with all fields and subtypes in the given type
1357 recursively replaced with `primitive_dtype`.
1359 Arguments are coerced to dtypes first.
1360 """
1361 dtype = np.dtype(dtype)
1362 primitive_dtype = np.dtype(primitive_dtype)
1363 return _replace_dtype_fields_recursive(dtype, primitive_dtype)
1366def make_mask_descr(ndtype):
1367 """
1368 Construct a dtype description list from a given dtype.
1370 Returns a new dtype object, with the type of all fields in `ndtype` to a
1371 boolean type. Field names are not altered.
1373 Parameters
1374 ----------
1375 ndtype : dtype
1376 The dtype to convert.
1378 Returns
1379 -------
1380 result : dtype
1381 A dtype that looks like `ndtype`, the type of all fields is boolean.
1383 Examples
1384 --------
1385 >>> import numpy as np
1386 >>> import numpy.ma as ma
1387 >>> dtype = np.dtype({'names':['foo', 'bar'],
1388 ... 'formats':[np.float32, np.int64]})
1389 >>> dtype
1390 dtype([('foo', '<f4'), ('bar', '<i8')])
1391 >>> ma.make_mask_descr(dtype)
1392 dtype([('foo', '|b1'), ('bar', '|b1')])
1393 >>> ma.make_mask_descr(np.float32)
1394 dtype('bool')
1396 """
1397 return _replace_dtype_fields(ndtype, MaskType)
1400def getmask(a):
1401 """
1402 Return the mask of a masked array, or nomask.
1404 Return the mask of `a` as an ndarray if `a` is a `MaskedArray` and the
1405 mask is not `nomask`, else return `nomask`. To guarantee a full array
1406 of booleans of the same shape as a, use `getmaskarray`.
1408 Parameters
1409 ----------
1410 a : array_like
1411 Input `MaskedArray` for which the mask is required.
1413 See Also
1414 --------
1415 getdata : Return the data of a masked array as an ndarray.
1416 getmaskarray : Return the mask of a masked array, or full array of False.
1418 Examples
1419 --------
1420 >>> import numpy as np
1421 >>> import numpy.ma as ma
1422 >>> a = ma.masked_equal([[1,2],[3,4]], 2)
1423 >>> a
1424 masked_array(
1425 data=[[1, --],
1426 [3, 4]],
1427 mask=[[False, True],
1428 [False, False]],
1429 fill_value=2)
1430 >>> ma.getmask(a)
1431 array([[False, True],
1432 [False, False]])
1434 Equivalently use the `MaskedArray` `mask` attribute.
1436 >>> a.mask
1437 array([[False, True],
1438 [False, False]])
1440 Result when mask == `nomask`
1442 >>> b = ma.masked_array([[1,2],[3,4]])
1443 >>> b
1444 masked_array(
1445 data=[[1, 2],
1446 [3, 4]],
1447 mask=False,
1448 fill_value=999999)
1449 >>> ma.nomask
1450 False
1451 >>> ma.getmask(b) == ma.nomask
1452 True
1453 >>> b.mask == ma.nomask
1454 True
1456 """
1457 return getattr(a, '_mask', nomask)
1460get_mask = getmask
1463def getmaskarray(arr):
1464 """
1465 Return the mask of a masked array, or full boolean array of False.
1467 Return the mask of `arr` as an ndarray if `arr` is a `MaskedArray` and
1468 the mask is not `nomask`, else return a full boolean array of False of
1469 the same shape as `arr`.
1471 Parameters
1472 ----------
1473 arr : array_like
1474 Input `MaskedArray` for which the mask is required.
1476 See Also
1477 --------
1478 getmask : Return the mask of a masked array, or nomask.
1479 getdata : Return the data of a masked array as an ndarray.
1481 Examples
1482 --------
1483 >>> import numpy as np
1484 >>> import numpy.ma as ma
1485 >>> a = ma.masked_equal([[1,2],[3,4]], 2)
1486 >>> a
1487 masked_array(
1488 data=[[1, --],
1489 [3, 4]],
1490 mask=[[False, True],
1491 [False, False]],
1492 fill_value=2)
1493 >>> ma.getmaskarray(a)
1494 array([[False, True],
1495 [False, False]])
1497 Result when mask == ``nomask``
1499 >>> b = ma.masked_array([[1,2],[3,4]])
1500 >>> b
1501 masked_array(
1502 data=[[1, 2],
1503 [3, 4]],
1504 mask=False,
1505 fill_value=999999)
1506 >>> ma.getmaskarray(b)
1507 array([[False, False],
1508 [False, False]])
1510 """
1511 mask = getmask(arr)
1512 if mask is nomask:
1513 mask = make_mask_none(np.shape(arr), getattr(arr, 'dtype', None))
1514 return mask
1517def is_mask(m):
1518 """
1519 Return True if m is a valid, standard mask.
1521 This function does not check the contents of the input, only that the
1522 type is MaskType. In particular, this function returns False if the
1523 mask has a flexible dtype.
1525 Parameters
1526 ----------
1527 m : array_like
1528 Array to test.
1530 Returns
1531 -------
1532 result : bool
1533 True if `m.dtype.type` is MaskType, False otherwise.
1535 See Also
1536 --------
1537 ma.isMaskedArray : Test whether input is an instance of MaskedArray.
1539 Examples
1540 --------
1541 >>> import numpy as np
1542 >>> import numpy.ma as ma
1543 >>> m = ma.masked_equal([0, 1, 0, 2, 3], 0)
1544 >>> m
1545 masked_array(data=[--, 1, --, 2, 3],
1546 mask=[ True, False, True, False, False],
1547 fill_value=0)
1548 >>> ma.is_mask(m)
1549 False
1550 >>> ma.is_mask(m.mask)
1551 True
1553 Input must be an ndarray (or have similar attributes)
1554 for it to be considered a valid mask.
1556 >>> m = [False, True, False]
1557 >>> ma.is_mask(m)
1558 False
1559 >>> m = np.array([False, True, False])
1560 >>> m
1561 array([False, True, False])
1562 >>> ma.is_mask(m)
1563 True
1565 Arrays with complex dtypes don't return True.
1567 >>> dtype = np.dtype({'names':['monty', 'pithon'],
1568 ... 'formats':[bool, bool]})
1569 >>> dtype
1570 dtype([('monty', '|b1'), ('pithon', '|b1')])
1571 >>> m = np.array([(True, False), (False, True), (True, False)],
1572 ... dtype=dtype)
1573 >>> m
1574 array([( True, False), (False, True), ( True, False)],
1575 dtype=[('monty', '?'), ('pithon', '?')])
1576 >>> ma.is_mask(m)
1577 False
1579 """
1580 try:
1581 return m.dtype.type is MaskType
1582 except AttributeError:
1583 return False
1586def _shrink_mask(m):
1587 """
1588 Shrink a mask to nomask if possible
1589 """
1590 if m.dtype.names is None and not m.any():
1591 return nomask
1592 else:
1593 return m
1596def make_mask(m, copy=False, shrink=True, dtype=MaskType):
1597 """
1598 Create a boolean mask from an array.
1600 Return `m` as a boolean mask, creating a copy if necessary or requested.
1601 The function can accept any sequence that is convertible to integers,
1602 or ``nomask``. Does not require that contents must be 0s and 1s, values
1603 of 0 are interpreted as False, everything else as True.
1605 Parameters
1606 ----------
1607 m : array_like
1608 Potential mask.
1609 copy : bool, optional
1610 Whether to return a copy of `m` (True) or `m` itself (False).
1611 shrink : bool, optional
1612 Whether to shrink `m` to ``nomask`` if all its values are False.
1613 dtype : dtype, optional
1614 Data-type of the output mask. By default, the output mask has a
1615 dtype of MaskType (bool). If the dtype is flexible, each field has
1616 a boolean dtype. This is ignored when `m` is ``nomask``, in which
1617 case ``nomask`` is always returned.
1619 Returns
1620 -------
1621 result : ndarray
1622 A boolean mask derived from `m`.
1624 Examples
1625 --------
1626 >>> import numpy as np
1627 >>> import numpy.ma as ma
1628 >>> m = [True, False, True, True]
1629 >>> ma.make_mask(m)
1630 array([ True, False, True, True])
1631 >>> m = [1, 0, 1, 1]
1632 >>> ma.make_mask(m)
1633 array([ True, False, True, True])
1634 >>> m = [1, 0, 2, -3]
1635 >>> ma.make_mask(m)
1636 array([ True, False, True, True])
1638 Effect of the `shrink` parameter.
1640 >>> m = np.zeros(4)
1641 >>> m
1642 array([0., 0., 0., 0.])
1643 >>> ma.make_mask(m)
1644 False
1645 >>> ma.make_mask(m, shrink=False)
1646 array([False, False, False, False])
1648 Using a flexible `dtype`.
1650 >>> m = [1, 0, 1, 1]
1651 >>> n = [0, 1, 0, 0]
1652 >>> arr = []
1653 >>> for man, mouse in zip(m, n):
1654 ... arr.append((man, mouse))
1655 >>> arr
1656 [(1, 0), (0, 1), (1, 0), (1, 0)]
1657 >>> dtype = np.dtype({'names':['man', 'mouse'],
1658 ... 'formats':[np.int64, np.int64]})
1659 >>> arr = np.array(arr, dtype=dtype)
1660 >>> arr
1661 array([(1, 0), (0, 1), (1, 0), (1, 0)],
1662 dtype=[('man', '<i8'), ('mouse', '<i8')])
1663 >>> ma.make_mask(arr, dtype=dtype)
1664 array([(True, False), (False, True), (True, False), (True, False)],
1665 dtype=[('man', '|b1'), ('mouse', '|b1')])
1667 """
1668 if m is nomask:
1669 return nomask
1671 # Make sure the input dtype is valid.
1672 dtype = make_mask_descr(dtype)
1674 # legacy boolean special case: "existence of fields implies true"
1675 if isinstance(m, ndarray) and m.dtype.fields and dtype == np.bool:
1676 return np.ones(m.shape, dtype=dtype)
1678 # Fill the mask in case there are missing data; turn it into an ndarray.
1679 copy = None if not copy else True
1680 result = np.array(filled(m, True), copy=copy, dtype=dtype, subok=True)
1681 # Bas les masques !
1682 if shrink:
1683 result = _shrink_mask(result)
1684 return result
1687def make_mask_none(newshape, dtype=None):
1688 """
1689 Return a boolean mask of the given shape, filled with False.
1691 This function returns a boolean ndarray with all entries False, that can
1692 be used in common mask manipulations. If a complex dtype is specified, the
1693 type of each field is converted to a boolean type.
1695 Parameters
1696 ----------
1697 newshape : tuple
1698 A tuple indicating the shape of the mask.
1699 dtype : {None, dtype}, optional
1700 If None, use a MaskType instance. Otherwise, use a new datatype with
1701 the same fields as `dtype`, converted to boolean types.
1703 Returns
1704 -------
1705 result : ndarray
1706 An ndarray of appropriate shape and dtype, filled with False.
1708 See Also
1709 --------
1710 make_mask : Create a boolean mask from an array.
1711 make_mask_descr : Construct a dtype description list from a given dtype.
1713 Examples
1714 --------
1715 >>> import numpy as np
1716 >>> import numpy.ma as ma
1717 >>> ma.make_mask_none((3,))
1718 array([False, False, False])
1720 Defining a more complex dtype.
1722 >>> dtype = np.dtype({'names':['foo', 'bar'],
1723 ... 'formats':[np.float32, np.int64]})
1724 >>> dtype
1725 dtype([('foo', '<f4'), ('bar', '<i8')])
1726 >>> ma.make_mask_none((3,), dtype=dtype)
1727 array([(False, False), (False, False), (False, False)],
1728 dtype=[('foo', '|b1'), ('bar', '|b1')])
1730 """
1731 if dtype is None:
1732 result = np.zeros(newshape, dtype=MaskType)
1733 else:
1734 result = np.zeros(newshape, dtype=make_mask_descr(dtype))
1735 return result
1738def _recursive_mask_or(m1, m2, newmask):
1739 names = m1.dtype.names
1740 for name in names:
1741 current1 = m1[name]
1742 if current1.dtype.names is not None:
1743 _recursive_mask_or(current1, m2[name], newmask[name])
1744 else:
1745 umath.logical_or(current1, m2[name], newmask[name])
1748def mask_or(m1, m2, copy=False, shrink=True):
1749 """
1750 Combine two masks with the ``logical_or`` operator.
1752 The result may be a view on `m1` or `m2` if the other is `nomask`
1753 (i.e. False).
1755 Parameters
1756 ----------
1757 m1, m2 : array_like
1758 Input masks.
1759 copy : bool, optional
1760 If copy is False and one of the inputs is `nomask`, return a view
1761 of the other input mask. Defaults to False.
1762 shrink : bool, optional
1763 Whether to shrink the output to `nomask` if all its values are
1764 False. Defaults to True.
1766 Returns
1767 -------
1768 mask : output mask
1769 The result masks values that are masked in either `m1` or `m2`.
1771 Raises
1772 ------
1773 ValueError
1774 If `m1` and `m2` have different flexible dtypes.
1776 Examples
1777 --------
1778 >>> import numpy as np
1779 >>> m1 = np.ma.make_mask([0, 1, 1, 0])
1780 >>> m2 = np.ma.make_mask([1, 0, 0, 0])
1781 >>> np.ma.mask_or(m1, m2)
1782 array([ True, True, True, False])
1784 """
1786 if (m1 is nomask) or (m1 is False):
1787 dtype = getattr(m2, 'dtype', MaskType)
1788 return make_mask(m2, copy=copy, shrink=shrink, dtype=dtype)
1789 if (m2 is nomask) or (m2 is False):
1790 dtype = getattr(m1, 'dtype', MaskType)
1791 return make_mask(m1, copy=copy, shrink=shrink, dtype=dtype)
1792 if m1 is m2 and is_mask(m1):
1793 return _shrink_mask(m1) if shrink else m1
1794 (dtype1, dtype2) = (getattr(m1, 'dtype', None), getattr(m2, 'dtype', None))
1795 if dtype1 != dtype2:
1796 raise ValueError(f"Incompatible dtypes '{dtype1}'<>'{dtype2}'")
1797 if dtype1.names is not None:
1798 # Allocate an output mask array with the properly broadcast shape.
1799 newmask = np.empty(np.broadcast(m1, m2).shape, dtype1)
1800 _recursive_mask_or(m1, m2, newmask)
1801 return newmask
1802 return make_mask(umath.logical_or(m1, m2), copy=copy, shrink=shrink)
1805def flatten_mask(mask):
1806 """
1807 Returns a completely flattened version of the mask, where nested fields
1808 are collapsed.
1810 Parameters
1811 ----------
1812 mask : array_like
1813 Input array, which will be interpreted as booleans.
1815 Returns
1816 -------
1817 flattened_mask : ndarray of bools
1818 The flattened input.
1820 Examples
1821 --------
1822 >>> import numpy as np
1823 >>> mask = np.array([0, 0, 1])
1824 >>> np.ma.flatten_mask(mask)
1825 array([False, False, True])
1827 >>> mask = np.array([(0, 0), (0, 1)], dtype=[('a', bool), ('b', bool)])
1828 >>> np.ma.flatten_mask(mask)
1829 array([False, False, False, True])
1831 >>> mdtype = [('a', bool), ('b', [('ba', bool), ('bb', bool)])]
1832 >>> mask = np.array([(0, (0, 0)), (0, (0, 1))], dtype=mdtype)
1833 >>> np.ma.flatten_mask(mask)
1834 array([False, False, False, False, False, True])
1836 """
1838 def _flatmask(mask):
1839 "Flatten the mask and returns a (maybe nested) sequence of booleans."
1840 mnames = mask.dtype.names
1841 if mnames is not None:
1842 return [flatten_mask(mask[name]) for name in mnames]
1843 else:
1844 return mask
1846 def _flatsequence(sequence):
1847 "Generates a flattened version of the sequence."
1848 try:
1849 for element in sequence:
1850 if hasattr(element, '__iter__'):
1851 yield from _flatsequence(element)
1852 else:
1853 yield element
1854 except TypeError:
1855 yield sequence
1857 mask = np.asarray(mask)
1858 flattened = _flatsequence(_flatmask(mask))
1859 return np.array(list(flattened), dtype=bool)
1862def _check_mask_axis(mask, axis, keepdims=np._NoValue):
1863 "Check whether there are masked values along the given axis"
1864 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
1865 if mask is not nomask:
1866 return mask.all(axis=axis, **kwargs)
1867 return nomask
1870###############################################################################
1871# Masking functions #
1872###############################################################################
1874def masked_where(condition, a, copy=True):
1875 """
1876 Mask an array where a condition is met.
1878 Return `a` as an array masked where `condition` is True.
1879 Any masked values of `a` or `condition` are also masked in the output.
1881 Parameters
1882 ----------
1883 condition : array_like
1884 Masking condition. When `condition` tests floating point values for
1885 equality, consider using ``masked_values`` instead.
1886 a : array_like
1887 Array to mask.
1888 copy : bool
1889 If True (default) make a copy of `a` in the result. If False modify
1890 `a` in place and return a view.
1892 Returns
1893 -------
1894 result : MaskedArray
1895 The result of masking `a` where `condition` is True.
1897 See Also
1898 --------
1899 masked_values : Mask using floating point equality.
1900 masked_equal : Mask where equal to a given value.
1901 masked_not_equal : Mask where *not* equal to a given value.
1902 masked_less_equal : Mask where less than or equal to a given value.
1903 masked_greater_equal : Mask where greater than or equal to a given value.
1904 masked_less : Mask where less than a given value.
1905 masked_greater : Mask where greater than a given value.
1906 masked_inside : Mask inside a given interval.
1907 masked_outside : Mask outside a given interval.
1908 masked_invalid : Mask invalid values (NaNs or infs).
1910 Examples
1911 --------
1912 >>> import numpy as np
1913 >>> import numpy.ma as ma
1914 >>> a = np.arange(4)
1915 >>> a
1916 array([0, 1, 2, 3])
1917 >>> ma.masked_where(a <= 2, a)
1918 masked_array(data=[--, --, --, 3],
1919 mask=[ True, True, True, False],
1920 fill_value=999999)
1922 Mask array `b` conditional on `a`.
1924 >>> b = ['a', 'b', 'c', 'd']
1925 >>> ma.masked_where(a == 2, b)
1926 masked_array(data=['a', 'b', --, 'd'],
1927 mask=[False, False, True, False],
1928 fill_value='N/A',
1929 dtype='<U1')
1931 Effect of the `copy` argument.
1933 >>> c = ma.masked_where(a <= 2, a)
1934 >>> c
1935 masked_array(data=[--, --, --, 3],
1936 mask=[ True, True, True, False],
1937 fill_value=999999)
1938 >>> c[0] = 99
1939 >>> c
1940 masked_array(data=[99, --, --, 3],
1941 mask=[False, True, True, False],
1942 fill_value=999999)
1943 >>> a
1944 array([0, 1, 2, 3])
1945 >>> c = ma.masked_where(a <= 2, a, copy=False)
1946 >>> c[0] = 99
1947 >>> c
1948 masked_array(data=[99, --, --, 3],
1949 mask=[False, True, True, False],
1950 fill_value=999999)
1951 >>> a
1952 array([99, 1, 2, 3])
1954 When `condition` or `a` contain masked values.
1956 >>> a = np.arange(4)
1957 >>> a = ma.masked_where(a == 2, a)
1958 >>> a
1959 masked_array(data=[0, 1, --, 3],
1960 mask=[False, False, True, False],
1961 fill_value=999999)
1962 >>> b = np.arange(4)
1963 >>> b = ma.masked_where(b == 0, b)
1964 >>> b
1965 masked_array(data=[--, 1, 2, 3],
1966 mask=[ True, False, False, False],
1967 fill_value=999999)
1968 >>> ma.masked_where(a == 3, b)
1969 masked_array(data=[--, 1, --, --],
1970 mask=[ True, False, True, True],
1971 fill_value=999999)
1973 """
1974 # Make sure that condition is a valid standard-type mask.
1975 cond = make_mask(condition, shrink=False)
1976 a = np.array(a, copy=copy, subok=True)
1978 (cshape, ashape) = (cond.shape, a.shape)
1979 if cshape and cshape != ashape:
1980 raise IndexError("Inconsistent shape between the condition and the input"
1981 " (got %s and %s)" % (cshape, ashape))
1982 if hasattr(a, '_mask'):
1983 cond = mask_or(cond, a._mask)
1984 cls = type(a)
1985 else:
1986 cls = MaskedArray
1987 result = a.view(cls)
1988 # Assign to *.mask so that structured masks are handled correctly.
1989 result.mask = _shrink_mask(cond)
1990 # There is no view of a boolean so when 'a' is a MaskedArray with nomask
1991 # the update to the result's mask has no effect.
1992 if not copy and hasattr(a, '_mask') and getmask(a) is nomask:
1993 a._mask = result._mask.view()
1994 return result
1997def masked_greater(x, value, copy=True):
1998 """
1999 Mask an array where greater than a given value.
2001 This function is a shortcut to ``masked_where``, with
2002 `condition` = (x > value).
2004 See Also
2005 --------
2006 masked_where : Mask where a condition is met.
2008 Examples
2009 --------
2010 >>> import numpy as np
2011 >>> import numpy.ma as ma
2012 >>> a = np.arange(4)
2013 >>> a
2014 array([0, 1, 2, 3])
2015 >>> ma.masked_greater(a, 2)
2016 masked_array(data=[0, 1, 2, --],
2017 mask=[False, False, False, True],
2018 fill_value=999999)
2020 """
2021 return masked_where(greater(x, value), x, copy=copy)
2024def masked_greater_equal(x, value, copy=True):
2025 """
2026 Mask an array where greater than or equal to a given value.
2028 This function is a shortcut to ``masked_where``, with
2029 `condition` = (x >= value).
2031 See Also
2032 --------
2033 masked_where : Mask where a condition is met.
2035 Examples
2036 --------
2037 >>> import numpy as np
2038 >>> import numpy.ma as ma
2039 >>> a = np.arange(4)
2040 >>> a
2041 array([0, 1, 2, 3])
2042 >>> ma.masked_greater_equal(a, 2)
2043 masked_array(data=[0, 1, --, --],
2044 mask=[False, False, True, True],
2045 fill_value=999999)
2047 """
2048 return masked_where(greater_equal(x, value), x, copy=copy)
2051def masked_less(x, value, copy=True):
2052 """
2053 Mask an array where less than a given value.
2055 This function is a shortcut to ``masked_where``, with
2056 `condition` = (x < value).
2058 See Also
2059 --------
2060 masked_where : Mask where a condition is met.
2062 Examples
2063 --------
2064 >>> import numpy as np
2065 >>> import numpy.ma as ma
2066 >>> a = np.arange(4)
2067 >>> a
2068 array([0, 1, 2, 3])
2069 >>> ma.masked_less(a, 2)
2070 masked_array(data=[--, --, 2, 3],
2071 mask=[ True, True, False, False],
2072 fill_value=999999)
2074 """
2075 return masked_where(less(x, value), x, copy=copy)
2078def masked_less_equal(x, value, copy=True):
2079 """
2080 Mask an array where less than or equal to a given value.
2082 This function is a shortcut to ``masked_where``, with
2083 `condition` = (x <= value).
2085 See Also
2086 --------
2087 masked_where : Mask where a condition is met.
2089 Examples
2090 --------
2091 >>> import numpy as np
2092 >>> import numpy.ma as ma
2093 >>> a = np.arange(4)
2094 >>> a
2095 array([0, 1, 2, 3])
2096 >>> ma.masked_less_equal(a, 2)
2097 masked_array(data=[--, --, --, 3],
2098 mask=[ True, True, True, False],
2099 fill_value=999999)
2101 """
2102 return masked_where(less_equal(x, value), x, copy=copy)
2105def masked_not_equal(x, value, copy=True):
2106 """
2107 Mask an array where *not* equal to a given value.
2109 This function is a shortcut to ``masked_where``, with
2110 `condition` = (x != value).
2112 See Also
2113 --------
2114 masked_where : Mask where a condition is met.
2116 Examples
2117 --------
2118 >>> import numpy as np
2119 >>> import numpy.ma as ma
2120 >>> a = np.arange(4)
2121 >>> a
2122 array([0, 1, 2, 3])
2123 >>> ma.masked_not_equal(a, 2)
2124 masked_array(data=[--, --, 2, --],
2125 mask=[ True, True, False, True],
2126 fill_value=999999)
2128 """
2129 return masked_where(not_equal(x, value), x, copy=copy)
2132def masked_equal(x, value, copy=True):
2133 """
2134 Mask an array where equal to a given value.
2136 Return a MaskedArray, masked where the data in array `x` are
2137 equal to `value`. The fill_value of the returned MaskedArray
2138 is set to `value`.
2140 For floating point arrays, consider using ``masked_values(x, value)``.
2142 See Also
2143 --------
2144 masked_where : Mask where a condition is met.
2145 masked_values : Mask using floating point equality.
2147 Examples
2148 --------
2149 >>> import numpy as np
2150 >>> import numpy.ma as ma
2151 >>> a = np.arange(4)
2152 >>> a
2153 array([0, 1, 2, 3])
2154 >>> ma.masked_equal(a, 2)
2155 masked_array(data=[0, 1, --, 3],
2156 mask=[False, False, True, False],
2157 fill_value=2)
2159 """
2160 output = masked_where(equal(x, value), x, copy=copy)
2161 output.fill_value = value
2162 return output
2165def masked_inside(x, v1, v2, copy=True):
2166 """
2167 Mask an array inside a given interval.
2169 Shortcut to ``masked_where``, where `condition` is True for `x` inside
2170 the interval [v1,v2] (v1 <= x <= v2). The boundaries `v1` and `v2`
2171 can be given in either order.
2173 See Also
2174 --------
2175 masked_where : Mask where a condition is met.
2177 Notes
2178 -----
2179 The array `x` is prefilled with its filling value.
2181 Examples
2182 --------
2183 >>> import numpy as np
2184 >>> import numpy.ma as ma
2185 >>> x = [0.31, 1.2, 0.01, 0.2, -0.4, -1.1]
2186 >>> ma.masked_inside(x, -0.3, 0.3)
2187 masked_array(data=[0.31, 1.2, --, --, -0.4, -1.1],
2188 mask=[False, False, True, True, False, False],
2189 fill_value=1e+20)
2191 The order of `v1` and `v2` doesn't matter.
2193 >>> ma.masked_inside(x, 0.3, -0.3)
2194 masked_array(data=[0.31, 1.2, --, --, -0.4, -1.1],
2195 mask=[False, False, True, True, False, False],
2196 fill_value=1e+20)
2198 """
2199 if v2 < v1:
2200 (v1, v2) = (v2, v1)
2201 xf = filled(x)
2202 condition = (xf >= v1) & (xf <= v2)
2203 return masked_where(condition, x, copy=copy)
2206def masked_outside(x, v1, v2, copy=True):
2207 """
2208 Mask an array outside a given interval.
2210 Shortcut to ``masked_where``, where `condition` is True for `x` outside
2211 the interval [v1,v2] (x < v1)|(x > v2).
2212 The boundaries `v1` and `v2` can be given in either order.
2214 See Also
2215 --------
2216 masked_where : Mask where a condition is met.
2218 Notes
2219 -----
2220 The array `x` is prefilled with its filling value.
2222 Examples
2223 --------
2224 >>> import numpy as np
2225 >>> import numpy.ma as ma
2226 >>> x = [0.31, 1.2, 0.01, 0.2, -0.4, -1.1]
2227 >>> ma.masked_outside(x, -0.3, 0.3)
2228 masked_array(data=[--, --, 0.01, 0.2, --, --],
2229 mask=[ True, True, False, False, True, True],
2230 fill_value=1e+20)
2232 The order of `v1` and `v2` doesn't matter.
2234 >>> ma.masked_outside(x, 0.3, -0.3)
2235 masked_array(data=[--, --, 0.01, 0.2, --, --],
2236 mask=[ True, True, False, False, True, True],
2237 fill_value=1e+20)
2239 """
2240 if v2 < v1:
2241 (v1, v2) = (v2, v1)
2242 xf = filled(x)
2243 condition = (xf < v1) | (xf > v2)
2244 return masked_where(condition, x, copy=copy)
2247def masked_object(x, value, copy=True, shrink=True):
2248 """
2249 Mask the array `x` where the data are exactly equal to value.
2251 This function is similar to `masked_values`, but only suitable
2252 for object arrays: for floating point, use `masked_values` instead.
2254 Parameters
2255 ----------
2256 x : array_like
2257 Array to mask
2258 value : object
2259 Comparison value
2260 copy : {True, False}, optional
2261 Whether to return a copy of `x`.
2262 shrink : {True, False}, optional
2263 Whether to collapse a mask full of False to nomask
2265 Returns
2266 -------
2267 result : MaskedArray
2268 The result of masking `x` where equal to `value`.
2270 See Also
2271 --------
2272 masked_where : Mask where a condition is met.
2273 masked_equal : Mask where equal to a given value (integers).
2274 masked_values : Mask using floating point equality.
2276 Examples
2277 --------
2278 >>> import numpy as np
2279 >>> import numpy.ma as ma
2280 >>> food = np.array(['green_eggs', 'ham'], dtype=object)
2281 >>> # don't eat spoiled food
2282 >>> eat = ma.masked_object(food, 'green_eggs')
2283 >>> eat
2284 masked_array(data=[--, 'ham'],
2285 mask=[ True, False],
2286 fill_value='green_eggs',
2287 dtype=object)
2288 >>> # plain ol` ham is boring
2289 >>> fresh_food = np.array(['cheese', 'ham', 'pineapple'], dtype=object)
2290 >>> eat = ma.masked_object(fresh_food, 'green_eggs')
2291 >>> eat
2292 masked_array(data=['cheese', 'ham', 'pineapple'],
2293 mask=False,
2294 fill_value='green_eggs',
2295 dtype=object)
2297 Note that `mask` is set to ``nomask`` if possible.
2299 >>> eat
2300 masked_array(data=['cheese', 'ham', 'pineapple'],
2301 mask=False,
2302 fill_value='green_eggs',
2303 dtype=object)
2305 """
2306 if isMaskedArray(x):
2307 condition = umath.equal(x._data, value)
2308 mask = x._mask
2309 else:
2310 condition = umath.equal(np.asarray(x), value)
2311 mask = nomask
2312 mask = mask_or(mask, make_mask(condition, shrink=shrink))
2313 return masked_array(x, mask=mask, copy=copy, fill_value=value)
2316def masked_values(x, value, rtol=1e-5, atol=1e-8, copy=True, shrink=True):
2317 """
2318 Mask using floating point equality.
2320 Return a MaskedArray, masked where the data in array `x` are approximately
2321 equal to `value`, determined using `isclose`. The default tolerances for
2322 `masked_values` are the same as those for `isclose`.
2324 For integer types, exact equality is used, in the same way as
2325 `masked_equal`.
2327 The fill_value is set to `value` and the mask is set to ``nomask`` if
2328 possible.
2330 Parameters
2331 ----------
2332 x : array_like
2333 Array to mask.
2334 value : float
2335 Masking value.
2336 rtol, atol : float, optional
2337 Tolerance parameters passed on to `isclose`
2338 copy : bool, optional
2339 Whether to return a copy of `x`.
2340 shrink : bool, optional
2341 Whether to collapse a mask full of False to ``nomask``.
2343 Returns
2344 -------
2345 result : MaskedArray
2346 The result of masking `x` where approximately equal to `value`.
2348 See Also
2349 --------
2350 masked_where : Mask where a condition is met.
2351 masked_equal : Mask where equal to a given value (integers).
2353 Examples
2354 --------
2355 >>> import numpy as np
2356 >>> import numpy.ma as ma
2357 >>> x = np.array([1, 1.1, 2, 1.1, 3])
2358 >>> ma.masked_values(x, 1.1)
2359 masked_array(data=[1.0, --, 2.0, --, 3.0],
2360 mask=[False, True, False, True, False],
2361 fill_value=1.1)
2363 Note that `mask` is set to ``nomask`` if possible.
2365 >>> ma.masked_values(x, 2.1)
2366 masked_array(data=[1. , 1.1, 2. , 1.1, 3. ],
2367 mask=False,
2368 fill_value=2.1)
2370 Unlike `masked_equal`, `masked_values` can perform approximate equalities.
2372 >>> ma.masked_values(x, 2.1, atol=1e-1)
2373 masked_array(data=[1.0, 1.1, --, 1.1, 3.0],
2374 mask=[False, False, True, False, False],
2375 fill_value=2.1)
2377 """
2378 xnew = filled(x, value)
2379 if np.issubdtype(xnew.dtype, np.floating):
2380 mask = np.isclose(xnew, value, atol=atol, rtol=rtol)
2381 else:
2382 mask = umath.equal(xnew, value)
2383 ret = masked_array(xnew, mask=mask, copy=copy, fill_value=value)
2384 if shrink:
2385 ret.shrink_mask()
2386 return ret
2389def masked_invalid(a, copy=True):
2390 """
2391 Mask an array where invalid values occur (NaNs or infs).
2393 This function is a shortcut to ``masked_where``, with
2394 `condition` = ~(np.isfinite(a)). Any pre-existing mask is conserved.
2395 Only applies to arrays with a dtype where NaNs or infs make sense
2396 (i.e. floating point types), but accepts any array_like object.
2398 See Also
2399 --------
2400 masked_where : Mask where a condition is met.
2402 Examples
2403 --------
2404 >>> import numpy as np
2405 >>> import numpy.ma as ma
2406 >>> a = np.arange(5, dtype=float)
2407 >>> a[2] = np.nan
2408 >>> a[3] = np.inf
2409 >>> a
2410 array([ 0., 1., nan, inf, 4.])
2411 >>> ma.masked_invalid(a)
2412 masked_array(data=[0.0, 1.0, --, --, 4.0],
2413 mask=[False, False, True, True, False],
2414 fill_value=1e+20)
2416 """
2417 a = np.array(a, copy=None, subok=True)
2418 res = masked_where(~(np.isfinite(a)), a, copy=copy)
2419 # masked_invalid previously never returned nomask as a mask and doing so
2420 # threw off matplotlib (gh-22842). So use shrink=False:
2421 if res._mask is nomask:
2422 res._mask = make_mask_none(res.shape, res.dtype)
2423 return res
2425###############################################################################
2426# Printing options #
2427###############################################################################
2430class _MaskedPrintOption:
2431 """
2432 Handle the string used to represent missing data in a masked array.
2434 """
2436 def __init__(self, display):
2437 """
2438 Create the masked_print_option object.
2440 """
2441 self._display = display
2442 self._enabled = True
2444 def display(self):
2445 """
2446 Display the string to print for masked values.
2448 """
2449 return self._display
2451 def set_display(self, s):
2452 """
2453 Set the string to print for masked values.
2455 """
2456 self._display = s
2458 def enabled(self):
2459 """
2460 Is the use of the display value enabled?
2462 """
2463 return self._enabled
2465 def enable(self, shrink=1):
2466 """
2467 Set the enabling shrink to `shrink`.
2469 """
2470 self._enabled = shrink
2472 def __str__(self):
2473 return str(self._display)
2475 __repr__ = __str__
2478# if you single index into a masked location you get this object.
2479masked_print_option = _MaskedPrintOption('--')
2482def _recursive_printoption(result, mask, printopt):
2483 """
2484 Puts printoptions in result where mask is True.
2486 Private function allowing for recursion
2488 """
2489 names = result.dtype.names
2490 if names is not None:
2491 for name in names:
2492 curdata = result[name]
2493 curmask = mask[name]
2494 _recursive_printoption(curdata, curmask, printopt)
2495 else:
2496 np.copyto(result, printopt, where=mask)
2499# For better or worse, these end in a newline
2500_legacy_print_templates = {
2501 'long_std': textwrap.dedent("""\
2502 masked_%(name)s(data =
2503 %(data)s,
2504 %(nlen)s mask =
2505 %(mask)s,
2506 %(nlen)s fill_value = %(fill)s)
2507 """),
2508 'long_flx': textwrap.dedent("""\
2509 masked_%(name)s(data =
2510 %(data)s,
2511 %(nlen)s mask =
2512 %(mask)s,
2513 %(nlen)s fill_value = %(fill)s,
2514 %(nlen)s dtype = %(dtype)s)
2515 """),
2516 'short_std': textwrap.dedent("""\
2517 masked_%(name)s(data = %(data)s,
2518 %(nlen)s mask = %(mask)s,
2519 %(nlen)s fill_value = %(fill)s)
2520 """),
2521 'short_flx': textwrap.dedent("""\
2522 masked_%(name)s(data = %(data)s,
2523 %(nlen)s mask = %(mask)s,
2524 %(nlen)s fill_value = %(fill)s,
2525 %(nlen)s dtype = %(dtype)s)
2526 """)
2527}
2529###############################################################################
2530# MaskedArray class #
2531###############################################################################
2534def _recursive_filled(a, mask, fill_value):
2535 """
2536 Recursively fill `a` with `fill_value`.
2538 """
2539 names = a.dtype.names
2540 for name in names:
2541 current = a[name]
2542 if current.dtype.names is not None:
2543 _recursive_filled(current, mask[name], fill_value[name])
2544 else:
2545 np.copyto(current, fill_value[name], where=mask[name])
2548def flatten_structured_array(a):
2549 """
2550 Flatten a structured array.
2552 The data type of the output is chosen such that it can represent all of the
2553 (nested) fields.
2555 Parameters
2556 ----------
2557 a : structured array
2559 Returns
2560 -------
2561 output : masked array or ndarray
2562 A flattened masked array if the input is a masked array, otherwise a
2563 standard ndarray.
2565 Examples
2566 --------
2567 >>> import numpy as np
2568 >>> ndtype = [('a', int), ('b', float)]
2569 >>> a = np.array([(1, 1), (2, 2)], dtype=ndtype)
2570 >>> np.ma.flatten_structured_array(a)
2571 array([[1., 1.],
2572 [2., 2.]])
2574 """
2576 def flatten_sequence(iterable):
2577 """
2578 Flattens a compound of nested iterables.
2580 """
2581 for elm in iter(iterable):
2582 if hasattr(elm, "__iter__") and not isinstance(elm, (str, bytes)):
2583 yield from flatten_sequence(elm)
2584 else:
2585 yield elm
2587 a = np.asanyarray(a)
2588 inishape = a.shape
2589 a = a.ravel()
2590 if isinstance(a, MaskedArray):
2591 out = np.array([tuple(flatten_sequence(d.item())) for d in a._data])
2592 out = out.view(MaskedArray)
2593 out._mask = np.array([tuple(flatten_sequence(d.item()))
2594 for d in getmaskarray(a)])
2595 else:
2596 out = np.array([tuple(flatten_sequence(d.item())) for d in a])
2597 if len(inishape) > 1:
2598 newshape = list(out.shape)
2599 newshape[0] = inishape
2600 out.shape = tuple(flatten_sequence(newshape))
2601 return out
2604def _arraymethod(funcname, onmask=True):
2605 """
2606 Return a class method wrapper around a basic array method.
2608 Creates a class method which returns a masked array, where the new
2609 ``_data`` array is the output of the corresponding basic method called
2610 on the original ``_data``.
2612 If `onmask` is True, the new mask is the output of the method called
2613 on the initial mask. Otherwise, the new mask is just a reference
2614 to the initial mask.
2616 Parameters
2617 ----------
2618 funcname : str
2619 Name of the function to apply on data.
2620 onmask : bool
2621 Whether the mask must be processed also (True) or left
2622 alone (False). Default is True. Make available as `_onmask`
2623 attribute.
2625 Returns
2626 -------
2627 method : instancemethod
2628 Class method wrapper of the specified basic array method.
2630 """
2631 def wrapped_method(self, *args, **params):
2632 result = getattr(self._data, funcname)(*args, **params)
2633 result = result.view(type(self))
2634 result._update_from(self)
2635 mask = self._mask
2636 if not onmask:
2637 result.__setmask__(mask)
2638 elif mask is not nomask:
2639 # __setmask__ makes a copy, which we don't want
2640 result._mask = getattr(mask, funcname)(*args, **params)
2641 return result
2642 methdoc = getattr(ndarray, funcname, None) or getattr(np, funcname, None)
2643 if methdoc is not None:
2644 wrapped_method.__doc__ = methdoc.__doc__
2645 wrapped_method.__name__ = funcname
2646 return wrapped_method
2649class MaskedIterator:
2650 """
2651 Flat iterator object to iterate over masked arrays.
2653 A `MaskedIterator` iterator is returned by ``x.flat`` for any masked array
2654 `x`. It allows iterating over the array as if it were a 1-D array,
2655 either in a for-loop or by calling its `next` method.
2657 Iteration is done in C-contiguous style, with the last index varying the
2658 fastest. The iterator can also be indexed using basic slicing or
2659 advanced indexing.
2661 See Also
2662 --------
2663 MaskedArray.flat : Return a flat iterator over an array.
2664 MaskedArray.flatten : Returns a flattened copy of an array.
2666 Notes
2667 -----
2668 `MaskedIterator` is not exported by the `ma` module. Instead of
2669 instantiating a `MaskedIterator` directly, use `MaskedArray.flat`.
2671 Examples
2672 --------
2673 >>> import numpy as np
2674 >>> x = np.ma.array(arange(6).reshape(2, 3))
2675 >>> fl = x.flat
2676 >>> type(fl)
2677 <class 'numpy.ma.MaskedIterator'>
2678 >>> for item in fl:
2679 ... print(item)
2680 ...
2681 0
2682 1
2683 2
2684 3
2685 4
2686 5
2688 Extracting more than a single element b indexing the `MaskedIterator`
2689 returns a masked array:
2691 >>> fl[2:4]
2692 masked_array(data = [2 3],
2693 mask = False,
2694 fill_value = 999999)
2696 """
2698 def __init__(self, ma):
2699 self.ma = ma
2700 self.dataiter = ma._data.flat
2702 if ma._mask is nomask:
2703 self.maskiter = None
2704 else:
2705 self.maskiter = ma._mask.flat
2707 def __iter__(self):
2708 return self
2710 def __getitem__(self, indx):
2711 result = self.dataiter.__getitem__(indx).view(type(self.ma))
2712 if self.maskiter is not None:
2713 _mask = self.maskiter.__getitem__(indx)
2714 if isinstance(_mask, ndarray):
2715 # set shape to match that of data; this is needed for matrices
2716 _mask.shape = result.shape
2717 result._mask = _mask
2718 elif isinstance(_mask, np.void):
2719 return mvoid(result, mask=_mask, hardmask=self.ma._hardmask)
2720 elif _mask: # Just a scalar, masked
2721 return masked
2722 return result
2724 # This won't work if ravel makes a copy
2725 def __setitem__(self, index, value):
2726 self.dataiter[index] = getdata(value)
2727 if self.maskiter is not None:
2728 self.maskiter[index] = getmaskarray(value)
2730 def __next__(self):
2731 """
2732 Return the next value, or raise StopIteration.
2734 Examples
2735 --------
2736 >>> import numpy as np
2737 >>> x = np.ma.array([3, 2], mask=[0, 1])
2738 >>> fl = x.flat
2739 >>> next(fl)
2740 3
2741 >>> next(fl)
2742 masked
2743 >>> next(fl)
2744 Traceback (most recent call last):
2745 ...
2746 StopIteration
2748 """
2749 d = next(self.dataiter)
2750 if self.maskiter is not None:
2751 m = next(self.maskiter)
2752 if isinstance(m, np.void):
2753 return mvoid(d, mask=m, hardmask=self.ma._hardmask)
2754 elif m: # Just a scalar, masked
2755 return masked
2756 return d
2759@set_module("numpy.ma")
2760class MaskedArray(ndarray):
2761 """
2762 An array class with possibly masked values.
2764 Masked values of True exclude the corresponding element from any
2765 computation.
2767 Construction::
2769 x = MaskedArray(data, mask=nomask, dtype=None, copy=False, subok=True,
2770 ndmin=0, fill_value=None, keep_mask=True, hard_mask=None,
2771 shrink=True, order=None)
2773 Parameters
2774 ----------
2775 data : array_like
2776 Input data.
2777 mask : sequence, optional
2778 Mask. Must be convertible to an array of booleans with the same
2779 shape as `data`. True indicates a masked (i.e. invalid) data.
2780 dtype : dtype, optional
2781 Data type of the output.
2782 If `dtype` is None, the type of the data argument (``data.dtype``)
2783 is used. If `dtype` is not None and different from ``data.dtype``,
2784 a copy is performed.
2785 copy : bool, optional
2786 Whether to copy the input data (True), or to use a reference instead.
2787 Default is False.
2788 subok : bool, optional
2789 Whether to return a subclass of `MaskedArray` if possible (True) or a
2790 plain `MaskedArray`. Default is True.
2791 ndmin : int, optional
2792 Minimum number of dimensions. Default is 0.
2793 fill_value : scalar, optional
2794 Value used to fill in the masked values when necessary.
2795 If None, a default based on the data-type is used.
2796 keep_mask : bool, optional
2797 Whether to combine `mask` with the mask of the input data, if any
2798 (True), or to use only `mask` for the output (False). Default is True.
2799 hard_mask : bool, optional
2800 Whether to use a hard mask or not. With a hard mask, masked values
2801 cannot be unmasked. Default is False.
2802 shrink : bool, optional
2803 Whether to force compression of an empty mask. Default is True.
2804 order : {'C', 'F', 'A'}, optional
2805 Specify the order of the array. If order is 'C', then the array
2806 will be in C-contiguous order (last-index varies the fastest).
2807 If order is 'F', then the returned array will be in
2808 Fortran-contiguous order (first-index varies the fastest).
2809 If order is 'A' (default), then the returned array may be
2810 in any order (either C-, Fortran-contiguous, or even discontiguous),
2811 unless a copy is required, in which case it will be C-contiguous.
2813 Examples
2814 --------
2815 >>> import numpy as np
2817 The ``mask`` can be initialized with an array of boolean values
2818 with the same shape as ``data``.
2820 >>> data = np.arange(6).reshape((2, 3))
2821 >>> np.ma.MaskedArray(data, mask=[[False, True, False],
2822 ... [False, False, True]])
2823 masked_array(
2824 data=[[0, --, 2],
2825 [3, 4, --]],
2826 mask=[[False, True, False],
2827 [False, False, True]],
2828 fill_value=999999)
2830 Alternatively, the ``mask`` can be initialized to homogeneous boolean
2831 array with the same shape as ``data`` by passing in a scalar
2832 boolean value:
2834 >>> np.ma.MaskedArray(data, mask=False)
2835 masked_array(
2836 data=[[0, 1, 2],
2837 [3, 4, 5]],
2838 mask=[[False, False, False],
2839 [False, False, False]],
2840 fill_value=999999)
2842 >>> np.ma.MaskedArray(data, mask=True)
2843 masked_array(
2844 data=[[--, --, --],
2845 [--, --, --]],
2846 mask=[[ True, True, True],
2847 [ True, True, True]],
2848 fill_value=999999,
2849 dtype=int64)
2851 .. note::
2852 The recommended practice for initializing ``mask`` with a scalar
2853 boolean value is to use ``True``/``False`` rather than
2854 ``np.True_``/``np.False_``. The reason is :attr:`nomask`
2855 is represented internally as ``np.False_``.
2857 >>> np.False_ is np.ma.nomask
2858 True
2860 """
2862 __array_priority__ = 15
2863 _defaultmask = nomask
2864 _defaulthardmask = False
2865 _baseclass = ndarray
2867 # Maximum number of elements per axis used when printing an array. The
2868 # 1d case is handled separately because we need more values in this case.
2869 _print_width = 100
2870 _print_width_1d = 1500
2872 def __new__(cls, data=None, mask=nomask, dtype=None, copy=False,
2873 subok=True, ndmin=0, fill_value=None, keep_mask=True,
2874 hard_mask=None, shrink=True, order=None):
2875 """
2876 Create a new masked array from scratch.
2878 Notes
2879 -----
2880 A masked array can also be created by taking a .view(MaskedArray).
2882 """
2883 # Process data.
2884 copy = None if not copy else True
2885 _data = np.array(data, dtype=dtype, copy=copy,
2886 order=order, subok=True, ndmin=ndmin)
2887 _baseclass = getattr(data, '_baseclass', type(_data))
2888 # Check that we're not erasing the mask.
2889 if isinstance(data, MaskedArray) and (data.shape != _data.shape):
2890 copy = True
2892 # Here, we copy the _view_, so that we can attach new properties to it
2893 # we must never do .view(MaskedConstant), as that would create a new
2894 # instance of np.ma.masked, which make identity comparison fail
2895 if isinstance(data, cls) and subok and not isinstance(data, MaskedConstant):
2896 _data = ndarray.view(_data, type(data))
2897 else:
2898 _data = ndarray.view(_data, cls)
2900 # Handle the case where data is not a subclass of ndarray, but
2901 # still has the _mask attribute like MaskedArrays
2902 if hasattr(data, '_mask') and not isinstance(data, ndarray):
2903 _data._mask = data._mask
2904 # FIXME: should we set `_data._sharedmask = True`?
2905 # Process mask.
2906 # Type of the mask
2907 mdtype = make_mask_descr(_data.dtype)
2908 if mask is nomask:
2909 # Case 1. : no mask in input.
2910 # Erase the current mask ?
2911 if not keep_mask:
2912 # With a reduced version
2913 if shrink:
2914 _data._mask = nomask
2915 # With full version
2916 else:
2917 _data._mask = np.zeros(_data.shape, dtype=mdtype)
2918 # Check whether we missed something
2919 elif isinstance(data, (tuple, list)):
2920 try:
2921 # If data is a sequence of masked array
2922 mask = np.array(
2923 [getmaskarray(np.asanyarray(m, dtype=_data.dtype))
2924 for m in data], dtype=mdtype)
2925 except (ValueError, TypeError):
2926 # If data is nested
2927 mask = nomask
2928 # Force shrinking of the mask if needed (and possible)
2929 if (mdtype == MaskType) and mask.any():
2930 _data._mask = mask
2931 _data._sharedmask = False
2932 else:
2933 _data._sharedmask = not copy
2934 if copy:
2935 _data._mask = _data._mask.copy()
2936 # Reset the shape of the original mask
2937 if getmask(data) is not nomask:
2938 # gh-21022 encounters an issue here
2939 # because data._mask.shape is not writeable, but
2940 # the op was also pointless in that case, because
2941 # the shapes were the same, so we can at least
2942 # avoid that path
2943 if data._mask.shape != data.shape:
2944 data._mask.shape = data.shape
2945 else:
2946 # Case 2. : With a mask in input.
2947 # If mask is boolean, create an array of True or False
2949 # if users pass `mask=None` be forgiving here and cast it False
2950 # for speed; although the default is `mask=nomask` and can differ.
2951 if mask is None:
2952 mask = False
2954 if mask is True and mdtype == MaskType:
2955 mask = np.ones(_data.shape, dtype=mdtype)
2956 elif mask is False and mdtype == MaskType:
2957 mask = np.zeros(_data.shape, dtype=mdtype)
2958 else:
2959 # Read the mask with the current mdtype
2960 try:
2961 mask = np.array(mask, copy=copy, dtype=mdtype)
2962 # Or assume it's a sequence of bool/int
2963 except TypeError:
2964 mask = np.array([tuple([m] * len(mdtype)) for m in mask],
2965 dtype=mdtype)
2966 # Make sure the mask and the data have the same shape
2967 if mask.shape != _data.shape:
2968 (nd, nm) = (_data.size, mask.size)
2969 if nm == 1:
2970 mask = np.resize(mask, _data.shape)
2971 elif nm == nd:
2972 mask = np.reshape(mask, _data.shape)
2973 else:
2974 msg = (f"Mask and data not compatible:"
2975 f" data size is {nd}, mask size is {nm}.")
2976 raise MaskError(msg)
2977 copy = True
2978 # Set the mask to the new value
2979 if _data._mask is nomask:
2980 _data._mask = mask
2981 _data._sharedmask = not copy
2982 elif not keep_mask:
2983 _data._mask = mask
2984 _data._sharedmask = not copy
2985 else:
2986 if _data.dtype.names is not None:
2987 def _recursive_or(a, b):
2988 "do a|=b on each field of a, recursively"
2989 for name in a.dtype.names:
2990 (af, bf) = (a[name], b[name])
2991 if af.dtype.names is not None:
2992 _recursive_or(af, bf)
2993 else:
2994 af |= bf
2996 _recursive_or(_data._mask, mask)
2997 else:
2998 _data._mask = np.logical_or(mask, _data._mask)
2999 _data._sharedmask = False
3001 # Update fill_value.
3002 if fill_value is None:
3003 fill_value = getattr(data, '_fill_value', None)
3004 # But don't run the check unless we have something to check.
3005 if fill_value is not None:
3006 _data._fill_value = _check_fill_value(fill_value, _data.dtype)
3007 # Process extra options ..
3008 if hard_mask is None:
3009 _data._hardmask = getattr(data, '_hardmask', False)
3010 else:
3011 _data._hardmask = hard_mask
3012 _data._baseclass = _baseclass
3013 return _data
3015 def _update_from(self, obj):
3016 """
3017 Copies some attributes of obj to self.
3019 """
3020 if isinstance(obj, ndarray):
3021 _baseclass = type(obj)
3022 else:
3023 _baseclass = ndarray
3024 # We need to copy the _basedict to avoid backward propagation
3025 _optinfo = {}
3026 _optinfo.update(getattr(obj, '_optinfo', {}))
3027 _optinfo.update(getattr(obj, '_basedict', {}))
3028 if not isinstance(obj, MaskedArray):
3029 _optinfo.update(getattr(obj, '__dict__', {}))
3030 _dict = {'_fill_value': getattr(obj, '_fill_value', None),
3031 '_hardmask': getattr(obj, '_hardmask', False),
3032 '_sharedmask': getattr(obj, '_sharedmask', False),
3033 '_isfield': getattr(obj, '_isfield', False),
3034 '_baseclass': getattr(obj, '_baseclass', _baseclass),
3035 '_optinfo': _optinfo,
3036 '_basedict': _optinfo}
3037 self.__dict__.update(_dict)
3038 self.__dict__.update(_optinfo)
3040 def __array_finalize__(self, obj):
3041 """
3042 Finalizes the masked array.
3044 """
3045 # Get main attributes.
3046 self._update_from(obj)
3048 # We have to decide how to initialize self.mask, based on
3049 # obj.mask. This is very difficult. There might be some
3050 # correspondence between the elements in the array we are being
3051 # created from (= obj) and us. Or there might not. This method can
3052 # be called in all kinds of places for all kinds of reasons -- could
3053 # be empty_like, could be slicing, could be a ufunc, could be a view.
3054 # The numpy subclassing interface simply doesn't give us any way
3055 # to know, which means that at best this method will be based on
3056 # guesswork and heuristics. To make things worse, there isn't even any
3057 # clear consensus about what the desired behavior is. For instance,
3058 # most users think that np.empty_like(marr) -- which goes via this
3059 # method -- should return a masked array with an empty mask (see
3060 # gh-3404 and linked discussions), but others disagree, and they have
3061 # existing code which depends on empty_like returning an array that
3062 # matches the input mask.
3063 #
3064 # Historically our algorithm was: if the template object mask had the
3065 # same *number of elements* as us, then we used *it's mask object
3066 # itself* as our mask, so that writes to us would also write to the
3067 # original array. This is horribly broken in multiple ways.
3068 #
3069 # Now what we do instead is, if the template object mask has the same
3070 # number of elements as us, and we do not have the same base pointer
3071 # as the template object (b/c views like arr[...] should keep the same
3072 # mask), then we make a copy of the template object mask and use
3073 # that. This is also horribly broken but somewhat less so. Maybe.
3074 if isinstance(obj, ndarray):
3075 # XX: This looks like a bug -- shouldn't it check self.dtype
3076 # instead?
3077 if obj.dtype.names is not None:
3078 _mask = getmaskarray(obj)
3079 else:
3080 _mask = getmask(obj)
3082 # If self and obj point to exactly the same data, then probably
3083 # self is a simple view of obj (e.g., self = obj[...]), so they
3084 # should share the same mask. (This isn't 100% reliable, e.g. self
3085 # could be the first row of obj, or have strange strides, but as a
3086 # heuristic it's not bad.) In all other cases, we make a copy of
3087 # the mask, so that future modifications to 'self' do not end up
3088 # side-effecting 'obj' as well.
3089 if (_mask is not nomask and obj.__array_interface__["data"][0]
3090 != self.__array_interface__["data"][0]):
3091 # We should make a copy. But we could get here via astype,
3092 # in which case the mask might need a new dtype as well
3093 # (e.g., changing to or from a structured dtype), and the
3094 # order could have changed. So, change the mask type if
3095 # needed and use astype instead of copy.
3096 if self.dtype == obj.dtype:
3097 _mask_dtype = _mask.dtype
3098 else:
3099 _mask_dtype = make_mask_descr(self.dtype)
3101 if self.flags.c_contiguous:
3102 order = "C"
3103 elif self.flags.f_contiguous:
3104 order = "F"
3105 else:
3106 order = "K"
3108 _mask = _mask.astype(_mask_dtype, order)
3109 else:
3110 # Take a view so shape changes, etc., do not propagate back.
3111 _mask = _mask.view()
3112 else:
3113 _mask = nomask
3115 self._mask = _mask
3116 # Finalize the mask
3117 if self._mask is not nomask:
3118 try:
3119 self._mask.shape = self.shape
3120 except ValueError:
3121 self._mask = nomask
3122 except (TypeError, AttributeError):
3123 # When _mask.shape is not writable (because it's a void)
3124 pass
3126 # Finalize the fill_value
3127 if self._fill_value is not None:
3128 self._fill_value = _check_fill_value(self._fill_value, self.dtype)
3129 elif self.dtype.names is not None:
3130 # Finalize the default fill_value for structured arrays
3131 self._fill_value = _check_fill_value(None, self.dtype)
3133 def __array_wrap__(self, obj, context=None, return_scalar=False):
3134 """
3135 Special hook for ufuncs.
3137 Wraps the numpy array and sets the mask according to context.
3139 """
3140 if obj is self: # for in-place operations
3141 result = obj
3142 else:
3143 result = obj.view(type(self))
3144 result._update_from(self)
3146 if context is not None:
3147 result._mask = result._mask.copy()
3148 func, args, out_i = context
3149 # args sometimes contains outputs (gh-10459), which we don't want
3150 input_args = args[:func.nin]
3151 m = functools.reduce(mask_or, [getmaskarray(arg) for arg in input_args])
3152 # Get the domain mask
3153 domain = ufunc_domain.get(func)
3154 if domain is not None:
3155 # Take the domain, and make sure it's a ndarray
3156 with np.errstate(divide='ignore', invalid='ignore'):
3157 # The result may be masked for two (unary) domains.
3158 # That can't really be right as some domains drop
3159 # the mask and some don't behaving differently here.
3160 d = domain(*input_args).astype(bool, copy=False)
3161 d = filled(d, True)
3163 if d.any():
3164 # Fill the result where the domain is wrong
3165 try:
3166 # Binary domain: take the last value
3167 fill_value = ufunc_fills[func][-1]
3168 except TypeError:
3169 # Unary domain: just use this one
3170 fill_value = ufunc_fills[func]
3171 except KeyError:
3172 # Domain not recognized, use fill_value instead
3173 fill_value = self.fill_value
3175 np.copyto(result, fill_value, where=d)
3177 # Update the mask
3178 if m is nomask:
3179 m = d
3180 else:
3181 # Don't modify inplace, we risk back-propagation
3182 m = (m | d)
3184 # Make sure the mask has the proper size
3185 if result is not self and result.shape == () and m:
3186 return masked
3187 else:
3188 result._mask = m
3189 result._sharedmask = False
3191 return result
3193 def view(self, dtype=None, type=None, fill_value=None):
3194 """
3195 Return a view of the MaskedArray data.
3197 Parameters
3198 ----------
3199 dtype : data-type or ndarray sub-class, optional
3200 Data-type descriptor of the returned view, e.g., float32 or int16.
3201 The default, None, results in the view having the same data-type
3202 as `a`. As with ``ndarray.view``, dtype can also be specified as
3203 an ndarray sub-class, which then specifies the type of the
3204 returned object (this is equivalent to setting the ``type``
3205 parameter).
3206 type : Python type, optional
3207 Type of the returned view, either ndarray or a subclass. The
3208 default None results in type preservation.
3209 fill_value : scalar, optional
3210 The value to use for invalid entries (None by default).
3211 If None, then this argument is inferred from the passed `dtype`, or
3212 in its absence the original array, as discussed in the notes below.
3214 See Also
3215 --------
3216 numpy.ndarray.view : Equivalent method on ndarray object.
3218 Notes
3219 -----
3221 ``a.view()`` is used two different ways:
3223 ``a.view(some_dtype)`` or ``a.view(dtype=some_dtype)`` constructs a view
3224 of the array's memory with a different data-type. This can cause a
3225 reinterpretation of the bytes of memory.
3227 ``a.view(ndarray_subclass)`` or ``a.view(type=ndarray_subclass)`` just
3228 returns an instance of `ndarray_subclass` that looks at the same array
3229 (same shape, dtype, etc.) This does not cause a reinterpretation of the
3230 memory.
3232 If `fill_value` is not specified, but `dtype` is specified (and is not
3233 an ndarray sub-class), the `fill_value` of the MaskedArray will be
3234 reset. If neither `fill_value` nor `dtype` are specified (or if
3235 `dtype` is an ndarray sub-class), then the fill value is preserved.
3236 Finally, if `fill_value` is specified, but `dtype` is not, the fill
3237 value is set to the specified value.
3239 For ``a.view(some_dtype)``, if ``some_dtype`` has a different number of
3240 bytes per entry than the previous dtype (for example, converting a
3241 regular array to a structured array), then the behavior of the view
3242 cannot be predicted just from the superficial appearance of ``a`` (shown
3243 by ``print(a)``). It also depends on exactly how ``a`` is stored in
3244 memory. Therefore if ``a`` is C-ordered versus fortran-ordered, versus
3245 defined as a slice or transpose, etc., the view may give different
3246 results.
3247 """
3249 if dtype is None:
3250 if type is None:
3251 output = ndarray.view(self)
3252 else:
3253 output = ndarray.view(self, type)
3254 elif type is None:
3255 try:
3256 if issubclass(dtype, ndarray):
3257 output = ndarray.view(self, dtype)
3258 dtype = None
3259 else:
3260 output = ndarray.view(self, dtype)
3261 except TypeError:
3262 output = ndarray.view(self, dtype)
3263 else:
3264 output = ndarray.view(self, dtype, type)
3266 # also make the mask be a view (so attr changes to the view's
3267 # mask do no affect original object's mask)
3268 # (especially important to avoid affecting np.masked singleton)
3269 if getmask(output) is not nomask:
3270 output._mask = output._mask.view()
3272 # Make sure to reset the _fill_value if needed
3273 if getattr(output, '_fill_value', None) is not None:
3274 if fill_value is None:
3275 if dtype is None:
3276 pass # leave _fill_value as is
3277 else:
3278 output._fill_value = None
3279 else:
3280 output.fill_value = fill_value
3281 return output
3283 def __getitem__(self, indx):
3284 """
3285 x.__getitem__(y) <==> x[y]
3287 Return the item described by i, as a masked array.
3289 """
3290 # We could directly use ndarray.__getitem__ on self.
3291 # But then we would have to modify __array_finalize__ to prevent the
3292 # mask of being reshaped if it hasn't been set up properly yet
3293 # So it's easier to stick to the current version
3294 dout = self.data[indx]
3295 _mask = self._mask
3297 def _is_scalar(m):
3298 return not isinstance(m, np.ndarray)
3300 def _scalar_heuristic(arr, elem):
3301 """
3302 Return whether `elem` is a scalar result of indexing `arr`, or None
3303 if undecidable without promoting nomask to a full mask
3304 """
3305 # obviously a scalar
3306 if not isinstance(elem, np.ndarray):
3307 return True
3309 # object array scalar indexing can return anything
3310 elif arr.dtype.type is np.object_:
3311 if arr.dtype is not elem.dtype:
3312 # elem is an array, but dtypes do not match, so must be
3313 # an element
3314 return True
3316 # well-behaved subclass that only returns 0d arrays when
3317 # expected - this is not a scalar
3318 elif type(arr).__getitem__ == ndarray.__getitem__:
3319 return False
3321 return None
3323 if _mask is not nomask:
3324 # _mask cannot be a subclass, so it tells us whether we should
3325 # expect a scalar. It also cannot be of dtype object.
3326 mout = _mask[indx]
3327 scalar_expected = _is_scalar(mout)
3329 else:
3330 # attempt to apply the heuristic to avoid constructing a full mask
3331 mout = nomask
3332 scalar_expected = _scalar_heuristic(self.data, dout)
3333 if scalar_expected is None:
3334 # heuristics have failed
3335 # construct a full array, so we can be certain. This is costly.
3336 # we could also fall back on ndarray.__getitem__(self.data, indx)
3337 scalar_expected = _is_scalar(getmaskarray(self)[indx])
3339 # Did we extract a single item?
3340 if scalar_expected:
3341 # A record
3342 if isinstance(dout, np.void):
3343 # We should always re-cast to mvoid, otherwise users can
3344 # change masks on rows that already have masked values, but not
3345 # on rows that have no masked values, which is inconsistent.
3346 return mvoid(dout, mask=mout, hardmask=self._hardmask)
3348 # special case introduced in gh-5962
3349 elif (self.dtype.type is np.object_ and
3350 isinstance(dout, np.ndarray) and
3351 dout is not masked):
3352 # If masked, turn into a MaskedArray, with everything masked.
3353 if mout:
3354 return MaskedArray(dout, mask=True)
3355 else:
3356 return dout
3358 # Just a scalar
3359 elif mout:
3360 return masked
3361 else:
3362 return dout
3363 else:
3364 # Force dout to MA
3365 dout = dout.view(type(self))
3366 # Inherit attributes from self
3367 dout._update_from(self)
3368 # Check the fill_value
3369 if is_string_or_list_of_strings(indx):
3370 if self._fill_value is not None:
3371 dout._fill_value = self._fill_value[indx]
3373 # Something like gh-15895 has happened if this check fails.
3374 # _fill_value should always be an ndarray.
3375 if not isinstance(dout._fill_value, np.ndarray):
3376 raise RuntimeError('Internal NumPy error.')
3377 # If we're indexing a multidimensional field in a
3378 # structured array (such as dtype("(2,)i2,(2,)i1")),
3379 # dimensionality goes up (M[field].ndim == M.ndim +
3380 # M.dtype[field].ndim). That's fine for
3381 # M[field] but problematic for M[field].fill_value
3382 # which should have shape () to avoid breaking several
3383 # methods. There is no great way out, so set to
3384 # first element. See issue #6723.
3385 if dout._fill_value.ndim > 0:
3386 if not (dout._fill_value ==
3387 dout._fill_value.flat[0]).all():
3388 warnings.warn(
3389 "Upon accessing multidimensional field "
3390 f"{indx!s}, need to keep dimensionality "
3391 "of fill_value at 0. Discarding "
3392 "heterogeneous fill_value and setting "
3393 f"all to {dout._fill_value[0]!s}.",
3394 stacklevel=2)
3395 # Need to use `.flat[0:1].squeeze(...)` instead of just
3396 # `.flat[0]` to ensure the result is a 0d array and not
3397 # a scalar.
3398 dout._fill_value = dout._fill_value.flat[0:1].squeeze(axis=0)
3399 dout._isfield = True
3400 # Update the mask if needed
3401 if mout is not nomask:
3402 # set shape to match that of data; this is needed for matrices
3403 dout._mask = reshape(mout, dout.shape)
3404 dout._sharedmask = True
3405 # Note: Don't try to check for m.any(), that'll take too long
3406 return dout
3408 # setitem may put NaNs into integer arrays or occasionally overflow a
3409 # float. But this may happen in masked values, so avoid otherwise
3410 # correct warnings (as is typical also in masked calculations).
3411 @np.errstate(over='ignore', invalid='ignore')
3412 def __setitem__(self, indx, value):
3413 """
3414 x.__setitem__(i, y) <==> x[i]=y
3416 Set item described by index. If value is masked, masks those
3417 locations.
3419 """
3420 if self is masked:
3421 raise MaskError('Cannot alter the masked element.')
3422 _data = self._data
3423 _mask = self._mask
3424 if isinstance(indx, str):
3425 _data[indx] = value
3426 if _mask is nomask:
3427 self._mask = _mask = make_mask_none(self.shape, self.dtype)
3428 _mask[indx] = getmask(value)
3429 return
3431 _dtype = _data.dtype
3433 if value is masked:
3434 # The mask wasn't set: create a full version.
3435 if _mask is nomask:
3436 _mask = self._mask = make_mask_none(self.shape, _dtype)
3437 # Now, set the mask to its value.
3438 if _dtype.names is not None:
3439 _mask[indx] = tuple([True] * len(_dtype.names))
3440 else:
3441 _mask[indx] = True
3442 return
3444 # Get the _data part of the new value
3445 dval = getattr(value, '_data', value)
3446 # Get the _mask part of the new value
3447 mval = getmask(value)
3448 if _dtype.names is not None and mval is nomask:
3449 mval = tuple([False] * len(_dtype.names))
3450 if _mask is nomask:
3451 # Set the data, then the mask
3452 _data[indx] = dval
3453 if mval is not nomask:
3454 _mask = self._mask = make_mask_none(self.shape, _dtype)
3455 _mask[indx] = mval
3456 elif not self._hardmask:
3457 # Set the data, then the mask
3458 if (isinstance(indx, masked_array) and
3459 not isinstance(value, masked_array)):
3460 _data[indx.data] = dval
3461 else:
3462 _data[indx] = dval
3463 _mask[indx] = mval
3464 elif hasattr(indx, 'dtype') and (indx.dtype == MaskType):
3465 indx = indx * umath.logical_not(_mask)
3466 _data[indx] = dval
3467 else:
3468 if _dtype.names is not None:
3469 err_msg = "Flexible 'hard' masks are not yet supported."
3470 raise NotImplementedError(err_msg)
3471 mindx = mask_or(_mask[indx], mval, copy=True)
3472 dindx = self._data[indx]
3473 if dindx.size > 1:
3474 np.copyto(dindx, dval, where=~mindx)
3475 elif mindx is nomask:
3476 dindx = dval
3477 _data[indx] = dindx
3478 _mask[indx] = mindx
3479 return
3481 # Define so that we can overwrite the setter.
3482 @property
3483 def dtype(self):
3484 return super().dtype
3486 @dtype.setter
3487 def dtype(self, dtype):
3488 super(MaskedArray, type(self)).dtype.__set__(self, dtype)
3489 if self._mask is not nomask:
3490 self._mask = self._mask.view(make_mask_descr(dtype), ndarray)
3491 # Try to reset the shape of the mask (if we don't have a void).
3492 # This raises a ValueError if the dtype change won't work.
3493 try:
3494 self._mask.shape = self.shape
3495 except (AttributeError, TypeError):
3496 pass
3498 @property
3499 def shape(self):
3500 return super().shape
3502 @shape.setter
3503 def shape(self, shape):
3504 super(MaskedArray, type(self)).shape.__set__(self, shape)
3505 # Cannot use self._mask, since it may not (yet) exist when a
3506 # masked matrix sets the shape.
3507 if getmask(self) is not nomask:
3508 self._mask.shape = self.shape
3510 def __setmask__(self, mask, copy=False):
3511 """
3512 Set the mask.
3514 """
3515 idtype = self.dtype
3516 current_mask = self._mask
3517 if mask is masked:
3518 mask = True
3520 if current_mask is nomask:
3521 # Make sure the mask is set
3522 # Just don't do anything if there's nothing to do.
3523 if mask is nomask:
3524 return
3525 current_mask = self._mask = make_mask_none(self.shape, idtype)
3527 if idtype.names is None:
3528 # No named fields.
3529 # Hardmask: don't unmask the data
3530 if self._hardmask:
3531 current_mask |= mask
3532 # Softmask: set everything to False
3533 # If it's obviously a compatible scalar, use a quick update
3534 # method.
3535 elif isinstance(mask, (int, float, np.bool, np.number)):
3536 current_mask[...] = mask
3537 # Otherwise fall back to the slower, general purpose way.
3538 else:
3539 current_mask.flat = mask
3540 else:
3541 # Named fields w/
3542 mdtype = current_mask.dtype
3543 mask = np.asarray(mask)
3544 # Mask is a singleton
3545 if not mask.ndim:
3546 # It's a boolean : make a record
3547 if mask.dtype.kind == 'b':
3548 mask = np.array(tuple([mask.item()] * len(mdtype)),
3549 dtype=mdtype)
3550 # It's a record: make sure the dtype is correct
3551 else:
3552 mask = mask.astype(mdtype)
3553 # Mask is a sequence
3554 else:
3555 # Make sure the new mask is a ndarray with the proper dtype
3556 try:
3557 copy = None if not copy else True
3558 mask = np.array(mask, copy=copy, dtype=mdtype)
3559 # Or assume it's a sequence of bool/int
3560 except TypeError:
3561 mask = np.array([tuple([m] * len(mdtype)) for m in mask],
3562 dtype=mdtype)
3563 # Hardmask: don't unmask the data
3564 if self._hardmask:
3565 for n in idtype.names:
3566 current_mask[n] |= mask[n]
3567 # Softmask: set everything to False
3568 # If it's obviously a compatible scalar, use a quick update
3569 # method.
3570 elif isinstance(mask, (int, float, np.bool, np.number)):
3571 current_mask[...] = mask
3572 # Otherwise fall back to the slower, general purpose way.
3573 else:
3574 current_mask.flat = mask
3575 # Reshape if needed
3576 if current_mask.shape:
3577 current_mask.shape = self.shape
3578 return
3580 _set_mask = __setmask__
3582 @property
3583 def mask(self):
3584 """ Current mask. """
3586 # We could try to force a reshape, but that wouldn't work in some
3587 # cases.
3588 # Return a view so that the dtype and shape cannot be changed in place
3589 # This still preserves nomask by identity
3590 return self._mask.view()
3592 @mask.setter
3593 def mask(self, value):
3594 self.__setmask__(value)
3596 @property
3597 def recordmask(self):
3598 """
3599 Get or set the mask of the array if it has no named fields. For
3600 structured arrays, returns a ndarray of booleans where entries are
3601 ``True`` if **all** the fields are masked, ``False`` otherwise:
3603 >>> x = np.ma.array([(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)],
3604 ... mask=[(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)],
3605 ... dtype=[('a', int), ('b', int)])
3606 >>> x.recordmask
3607 array([False, False, True, False, False])
3608 """
3610 _mask = self._mask.view(ndarray)
3611 if _mask.dtype.names is None:
3612 return _mask
3613 return np.all(flatten_structured_array(_mask), axis=-1)
3615 @recordmask.setter
3616 def recordmask(self, mask):
3617 raise NotImplementedError("Coming soon: setting the mask per records!")
3619 def harden_mask(self):
3620 """
3621 Force the mask to hard, preventing unmasking by assignment.
3623 Whether the mask of a masked array is hard or soft is determined by
3624 its `~ma.MaskedArray.hardmask` property. `harden_mask` sets
3625 `~ma.MaskedArray.hardmask` to ``True`` (and returns the modified
3626 self).
3628 See Also
3629 --------
3630 ma.MaskedArray.hardmask
3631 ma.MaskedArray.soften_mask
3633 """
3634 self._hardmask = True
3635 return self
3637 def soften_mask(self):
3638 """
3639 Force the mask to soft (default), allowing unmasking by assignment.
3641 Whether the mask of a masked array is hard or soft is determined by
3642 its `~ma.MaskedArray.hardmask` property. `soften_mask` sets
3643 `~ma.MaskedArray.hardmask` to ``False`` (and returns the modified
3644 self).
3646 See Also
3647 --------
3648 ma.MaskedArray.hardmask
3649 ma.MaskedArray.harden_mask
3651 """
3652 self._hardmask = False
3653 return self
3655 @property
3656 def hardmask(self):
3657 """
3658 Specifies whether values can be unmasked through assignments.
3660 By default, assigning definite values to masked array entries will
3661 unmask them. When `hardmask` is ``True``, the mask will not change
3662 through assignments.
3664 See Also
3665 --------
3666 ma.MaskedArray.harden_mask
3667 ma.MaskedArray.soften_mask
3669 Examples
3670 --------
3671 >>> import numpy as np
3672 >>> x = np.arange(10)
3673 >>> m = np.ma.masked_array(x, x>5)
3674 >>> assert not m.hardmask
3676 Since `m` has a soft mask, assigning an element value unmasks that
3677 element:
3679 >>> m[8] = 42
3680 >>> m
3681 masked_array(data=[0, 1, 2, 3, 4, 5, --, --, 42, --],
3682 mask=[False, False, False, False, False, False,
3683 True, True, False, True],
3684 fill_value=999999)
3686 After hardening, the mask is not affected by assignments:
3688 >>> hardened = np.ma.harden_mask(m)
3689 >>> assert m.hardmask and hardened is m
3690 >>> m[:] = 23
3691 >>> m
3692 masked_array(data=[23, 23, 23, 23, 23, 23, --, --, 23, --],
3693 mask=[False, False, False, False, False, False,
3694 True, True, False, True],
3695 fill_value=999999)
3697 """
3698 return self._hardmask
3700 def unshare_mask(self):
3701 """
3702 Copy the mask and set the `sharedmask` flag to ``False``.
3704 Whether the mask is shared between masked arrays can be seen from
3705 the `sharedmask` property. `unshare_mask` ensures the mask is not
3706 shared. A copy of the mask is only made if it was shared.
3708 See Also
3709 --------
3710 sharedmask
3712 """
3713 if self._sharedmask:
3714 self._mask = self._mask.copy()
3715 self._sharedmask = False
3716 return self
3718 @property
3719 def sharedmask(self):
3720 """ Share status of the mask (read-only). """
3721 return self._sharedmask
3723 def shrink_mask(self):
3724 """
3725 Reduce a mask to nomask when possible.
3727 Parameters
3728 ----------
3729 None
3731 Returns
3732 -------
3733 result : MaskedArray
3734 A :class:`~ma.MaskedArray` object.
3736 Examples
3737 --------
3738 >>> import numpy as np
3739 >>> x = np.ma.array([[1,2 ], [3, 4]], mask=[0]*4)
3740 >>> x.mask
3741 array([[False, False],
3742 [False, False]])
3743 >>> x.shrink_mask()
3744 masked_array(
3745 data=[[1, 2],
3746 [3, 4]],
3747 mask=False,
3748 fill_value=999999)
3749 >>> x.mask
3750 False
3752 """
3753 self._mask = _shrink_mask(self._mask)
3754 return self
3756 @property
3757 def baseclass(self):
3758 """ Class of the underlying data (read-only). """
3759 return self._baseclass
3761 def _get_data(self):
3762 """
3763 Returns the underlying data, as a view of the masked array.
3765 If the underlying data is a subclass of :class:`numpy.ndarray`, it is
3766 returned as such.
3768 >>> x = np.ma.array(np.matrix([[1, 2], [3, 4]]), mask=[[0, 1], [1, 0]])
3769 >>> x.data
3770 matrix([[1, 2],
3771 [3, 4]])
3773 The type of the data can be accessed through the :attr:`baseclass`
3774 attribute.
3775 """
3776 return ndarray.view(self, self._baseclass)
3778 _data = property(fget=_get_data)
3779 data = property(fget=_get_data)
3781 @property
3782 def flat(self):
3783 """ Return a flat iterator, or set a flattened version of self to value. """
3784 return MaskedIterator(self)
3786 @flat.setter
3787 def flat(self, value):
3788 y = self.ravel()
3789 y[:] = value
3791 @property
3792 def fill_value(self):
3793 """
3794 The filling value of the masked array is a scalar. When setting, None
3795 will set to a default based on the data type.
3797 Examples
3798 --------
3799 >>> import numpy as np
3800 >>> for dt in [np.int32, np.int64, np.float64, np.complex128]:
3801 ... np.ma.array([0, 1], dtype=dt).get_fill_value()
3802 ...
3803 np.int64(999999)
3804 np.int64(999999)
3805 np.float64(1e+20)
3806 np.complex128(1e+20+0j)
3808 >>> x = np.ma.array([0, 1.], fill_value=-np.inf)
3809 >>> x.fill_value
3810 np.float64(-inf)
3811 >>> x.fill_value = np.pi
3812 >>> x.fill_value
3813 np.float64(3.1415926535897931)
3815 Reset to default:
3817 >>> x.fill_value = None
3818 >>> x.fill_value
3819 np.float64(1e+20)
3821 """
3822 if self._fill_value is None:
3823 self._fill_value = _check_fill_value(None, self.dtype)
3825 # Temporary workaround to account for the fact that str and bytes
3826 # scalars cannot be indexed with (), whereas all other numpy
3827 # scalars can. See issues #7259 and #7267.
3828 # The if-block can be removed after #7267 has been fixed.
3829 if isinstance(self._fill_value, ndarray):
3830 return self._fill_value[()]
3831 return self._fill_value
3833 @fill_value.setter
3834 def fill_value(self, value=None):
3835 target = _check_fill_value(value, self.dtype)
3836 if not target.ndim == 0:
3837 # 2019-11-12, 1.18.0
3838 warnings.warn(
3839 "Non-scalar arrays for the fill value are deprecated. Use "
3840 "arrays with scalar values instead. The filled function "
3841 "still supports any array as `fill_value`.",
3842 DeprecationWarning, stacklevel=2)
3844 _fill_value = self._fill_value
3845 if _fill_value is None:
3846 # Create the attribute if it was undefined
3847 self._fill_value = target
3848 else:
3849 # Don't overwrite the attribute, just fill it (for propagation)
3850 _fill_value[()] = target
3852 # kept for compatibility
3853 get_fill_value = fill_value.fget
3854 set_fill_value = fill_value.fset
3856 def filled(self, fill_value=None):
3857 """
3858 Return a copy of self, with masked values filled with a given value.
3859 **However**, if there are no masked values to fill, self will be
3860 returned instead as an ndarray.
3862 Parameters
3863 ----------
3864 fill_value : array_like, optional
3865 The value to use for invalid entries. Can be scalar or non-scalar.
3866 If non-scalar, the resulting ndarray must be broadcastable over
3867 input array. Default is None, in which case, the `fill_value`
3868 attribute of the array is used instead.
3870 Returns
3871 -------
3872 filled_array : ndarray
3873 A copy of ``self`` with invalid entries replaced by *fill_value*
3874 (be it the function argument or the attribute of ``self``), or
3875 ``self`` itself as an ndarray if there are no invalid entries to
3876 be replaced.
3878 Notes
3879 -----
3880 The result is **not** a MaskedArray!
3882 Examples
3883 --------
3884 >>> import numpy as np
3885 >>> x = np.ma.array([1,2,3,4,5], mask=[0,0,1,0,1], fill_value=-999)
3886 >>> x.filled()
3887 array([ 1, 2, -999, 4, -999])
3888 >>> x.filled(fill_value=1000)
3889 array([ 1, 2, 1000, 4, 1000])
3890 >>> type(x.filled())
3891 <class 'numpy.ndarray'>
3893 Subclassing is preserved. This means that if, e.g., the data part of
3894 the masked array is a recarray, `filled` returns a recarray:
3896 >>> x = np.array([(-1, 2), (-3, 4)], dtype='i8,i8').view(np.recarray)
3897 >>> m = np.ma.array(x, mask=[(True, False), (False, True)])
3898 >>> m.filled()
3899 rec.array([(999999, 2), ( -3, 999999)],
3900 dtype=[('f0', '<i8'), ('f1', '<i8')])
3901 """
3902 m = self._mask
3903 if m is nomask:
3904 return self._data
3906 if fill_value is None:
3907 fill_value = self.fill_value
3908 else:
3909 fill_value = _check_fill_value(fill_value, self.dtype)
3911 if self is masked_singleton:
3912 return np.asanyarray(fill_value)
3914 if m.dtype.names is not None:
3915 result = self._data.copy('K')
3916 _recursive_filled(result, self._mask, fill_value)
3917 elif not m.any():
3918 return self._data
3919 else:
3920 result = self._data.copy('K')
3921 try:
3922 np.copyto(result, fill_value, where=m)
3923 except (TypeError, AttributeError):
3924 fill_value = narray(fill_value, dtype=object)
3925 d = result.astype(object)
3926 result = np.choose(m, (d, fill_value))
3927 except IndexError:
3928 # ok, if scalar
3929 if self._data.shape:
3930 raise
3931 elif m:
3932 result = np.array(fill_value, dtype=self.dtype)
3933 else:
3934 result = self._data
3935 return result
3937 def compressed(self):
3938 """
3939 Return all the non-masked data as a 1-D array.
3941 Returns
3942 -------
3943 data : ndarray
3944 A new `ndarray` holding the non-masked data is returned.
3946 Notes
3947 -----
3948 The result is **not** a MaskedArray!
3950 Examples
3951 --------
3952 >>> import numpy as np
3953 >>> x = np.ma.array(np.arange(5), mask=[0]*2 + [1]*3)
3954 >>> x.compressed()
3955 array([0, 1])
3956 >>> type(x.compressed())
3957 <class 'numpy.ndarray'>
3959 N-D arrays are compressed to 1-D.
3961 >>> arr = [[1, 2], [3, 4]]
3962 >>> mask = [[1, 0], [0, 1]]
3963 >>> x = np.ma.array(arr, mask=mask)
3964 >>> x.compressed()
3965 array([2, 3])
3967 """
3968 data = ndarray.ravel(self._data)
3969 if self._mask is not nomask:
3970 data = data.compress(np.logical_not(ndarray.ravel(self._mask)))
3971 return data
3973 def compress(self, condition, axis=None, out=None):
3974 """
3975 Return `a` where condition is ``True``.
3977 If condition is a `~ma.MaskedArray`, missing values are considered
3978 as ``False``.
3980 Parameters
3981 ----------
3982 condition : var
3983 Boolean 1-d array selecting which entries to return. If len(condition)
3984 is less than the size of a along the axis, then output is truncated
3985 to length of condition array.
3986 axis : {None, int}, optional
3987 Axis along which the operation must be performed.
3988 out : {None, ndarray}, optional
3989 Alternative output array in which to place the result. It must have
3990 the same shape as the expected output but the type will be cast if
3991 necessary.
3993 Returns
3994 -------
3995 result : MaskedArray
3996 A :class:`~ma.MaskedArray` object.
3998 Notes
3999 -----
4000 Please note the difference with :meth:`compressed` !
4001 The output of :meth:`compress` has a mask, the output of
4002 :meth:`compressed` does not.
4004 Examples
4005 --------
4006 >>> import numpy as np
4007 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
4008 >>> x
4009 masked_array(
4010 data=[[1, --, 3],
4011 [--, 5, --],
4012 [7, --, 9]],
4013 mask=[[False, True, False],
4014 [ True, False, True],
4015 [False, True, False]],
4016 fill_value=999999)
4017 >>> x.compress([1, 0, 1])
4018 masked_array(data=[1, 3],
4019 mask=[False, False],
4020 fill_value=999999)
4022 >>> x.compress([1, 0, 1], axis=1)
4023 masked_array(
4024 data=[[1, 3],
4025 [--, --],
4026 [7, 9]],
4027 mask=[[False, False],
4028 [ True, True],
4029 [False, False]],
4030 fill_value=999999)
4032 """
4033 # Get the basic components
4034 (_data, _mask) = (self._data, self._mask)
4036 # Force the condition to a regular ndarray and forget the missing
4037 # values.
4038 condition = np.asarray(condition)
4040 _new = _data.compress(condition, axis=axis, out=out).view(type(self))
4041 _new._update_from(self)
4042 if _mask is not nomask:
4043 _new._mask = _mask.compress(condition, axis=axis)
4044 return _new
4046 def _insert_masked_print(self):
4047 """
4048 Replace masked values with masked_print_option, casting all innermost
4049 dtypes to object.
4050 """
4051 if masked_print_option.enabled():
4052 mask = self._mask
4053 if mask is nomask:
4054 res = self._data
4055 else:
4056 # convert to object array to make filled work
4057 data = self._data
4058 # For big arrays, to avoid a costly conversion to the
4059 # object dtype, extract the corners before the conversion.
4060 print_width = (self._print_width if self.ndim > 1
4061 else self._print_width_1d)
4062 for axis in range(self.ndim):
4063 if data.shape[axis] > print_width:
4064 ind = print_width // 2
4065 arr = np.split(data, (ind, -ind), axis=axis)
4066 data = np.concatenate((arr[0], arr[2]), axis=axis)
4067 arr = np.split(mask, (ind, -ind), axis=axis)
4068 mask = np.concatenate((arr[0], arr[2]), axis=axis)
4070 rdtype = _replace_dtype_fields(self.dtype, "O")
4071 res = data.astype(rdtype)
4072 _recursive_printoption(res, mask, masked_print_option)
4073 else:
4074 res = self.filled(self.fill_value)
4075 return res
4077 def __str__(self):
4078 return str(self._insert_masked_print())
4080 def __repr__(self):
4081 """
4082 Literal string representation.
4084 """
4085 if self._baseclass is np.ndarray:
4086 name = 'array'
4087 else:
4088 name = self._baseclass.__name__
4090 # 2016-11-19: Demoted to legacy format
4091 if np._core.arrayprint._get_legacy_print_mode() <= 113:
4092 is_long = self.ndim > 1
4093 parameters = {
4094 'name': name,
4095 'nlen': " " * len(name),
4096 'data': str(self),
4097 'mask': str(self._mask),
4098 'fill': str(self.fill_value),
4099 'dtype': str(self.dtype)
4100 }
4101 is_structured = bool(self.dtype.names)
4102 key = '{}_{}'.format(
4103 'long' if is_long else 'short',
4104 'flx' if is_structured else 'std'
4105 )
4106 return _legacy_print_templates[key] % parameters
4108 prefix = f"masked_{name}("
4110 dtype_needed = (
4111 not np._core.arrayprint.dtype_is_implied(self.dtype) or
4112 np.all(self.mask) or
4113 self.size == 0
4114 )
4116 # determine which keyword args need to be shown
4117 keys = ['data', 'mask', 'fill_value']
4118 if dtype_needed:
4119 keys.append('dtype')
4121 # array has only one row (non-column)
4122 is_one_row = builtins.all(dim == 1 for dim in self.shape[:-1])
4124 # choose what to indent each keyword with
4125 min_indent = 2
4126 if is_one_row:
4127 # first key on the same line as the type, remaining keys
4128 # aligned by equals
4129 indents = {}
4130 indents[keys[0]] = prefix
4131 for k in keys[1:]:
4132 n = builtins.max(min_indent, len(prefix + keys[0]) - len(k))
4133 indents[k] = ' ' * n
4134 prefix = '' # absorbed into the first indent
4135 else:
4136 # each key on its own line, indented by two spaces
4137 indents = dict.fromkeys(keys, ' ' * min_indent)
4138 prefix = prefix + '\n' # first key on the next line
4140 # format the field values
4141 reprs = {}
4142 reprs['data'] = np.array2string(
4143 self._insert_masked_print(),
4144 separator=", ",
4145 prefix=indents['data'] + 'data=',
4146 suffix=',')
4147 reprs['mask'] = np.array2string(
4148 self._mask,
4149 separator=", ",
4150 prefix=indents['mask'] + 'mask=',
4151 suffix=',')
4153 if self._fill_value is None:
4154 self.fill_value # initialize fill_value # noqa: B018
4156 if (self._fill_value.dtype.kind in ("S", "U")
4157 and self.dtype.kind == self._fill_value.dtype.kind):
4158 # Allow strings: "N/A" has length 3 so would mismatch.
4159 fill_repr = repr(self.fill_value.item())
4160 elif self._fill_value.dtype == self.dtype and not self.dtype == object:
4161 # Guess that it is OK to use the string as item repr. To really
4162 # fix this, it needs new logic (shared with structured scalars)
4163 fill_repr = str(self.fill_value)
4164 else:
4165 fill_repr = repr(self.fill_value)
4167 reprs['fill_value'] = fill_repr
4168 if dtype_needed:
4169 reprs['dtype'] = np._core.arrayprint.dtype_short_repr(self.dtype)
4171 # join keys with values and indentations
4172 result = ',\n'.join(
4173 f'{indents[k]}{k}={reprs[k]}'
4174 for k in keys
4175 )
4176 return prefix + result + ')'
4178 def _delegate_binop(self, other):
4179 # This emulates the logic in
4180 # private/binop_override.h:forward_binop_should_defer
4181 if isinstance(other, type(self)):
4182 return False
4183 array_ufunc = getattr(other, "__array_ufunc__", False)
4184 if array_ufunc is False:
4185 other_priority = getattr(other, "__array_priority__", -1000000)
4186 return self.__array_priority__ < other_priority
4187 else:
4188 # If array_ufunc is not None, it will be called inside the ufunc;
4189 # None explicitly tells us to not call the ufunc, i.e., defer.
4190 return array_ufunc is None
4192 def _comparison(self, other, compare):
4193 """Compare self with other using operator.eq or operator.ne.
4195 When either of the elements is masked, the result is masked as well,
4196 but the underlying boolean data are still set, with self and other
4197 considered equal if both are masked, and unequal otherwise.
4199 For structured arrays, all fields are combined, with masked values
4200 ignored. The result is masked if all fields were masked, with self
4201 and other considered equal only if both were fully masked.
4202 """
4203 omask = getmask(other)
4204 smask = self.mask
4205 mask = mask_or(smask, omask, copy=True)
4207 odata = getdata(other)
4208 if mask.dtype.names is not None:
4209 # only == and != are reasonably defined for structured dtypes,
4210 # so give up early for all other comparisons:
4211 if compare not in (operator.eq, operator.ne):
4212 return NotImplemented
4213 # For possibly masked structured arrays we need to be careful,
4214 # since the standard structured array comparison will use all
4215 # fields, masked or not. To avoid masked fields influencing the
4216 # outcome, we set all masked fields in self to other, so they'll
4217 # count as equal. To prepare, we ensure we have the right shape.
4218 broadcast_shape = np.broadcast(self, odata).shape
4219 sbroadcast = np.broadcast_to(self, broadcast_shape, subok=True)
4220 sbroadcast._mask = mask
4221 sdata = sbroadcast.filled(odata)
4222 # Now take care of the mask; the merged mask should have an item
4223 # masked if all fields were masked (in one and/or other).
4224 mask = (mask == np.ones((), mask.dtype))
4225 # Ensure we can compare masks below if other was not masked.
4226 if omask is np.False_:
4227 omask = np.zeros((), smask.dtype)
4229 else:
4230 # For regular arrays, just use the data as they come.
4231 sdata = self.data
4233 check = compare(sdata, odata)
4235 if isinstance(check, (np.bool, bool)):
4236 return masked if mask else check
4238 if mask is not nomask:
4239 if compare in (operator.eq, operator.ne):
4240 # Adjust elements that were masked, which should be treated
4241 # as equal if masked in both, unequal if masked in one.
4242 # Note that this works automatically for structured arrays too.
4243 # Ignore this for operations other than `==` and `!=`
4244 check = np.where(mask, compare(smask, omask), check)
4246 if mask.shape != check.shape:
4247 # Guarantee consistency of the shape, making a copy since the
4248 # the mask may need to get written to later.
4249 mask = np.broadcast_to(mask, check.shape).copy()
4251 check = check.view(type(self))
4252 check._update_from(self)
4253 check._mask = mask
4255 # Cast fill value to np.bool if needed. If it cannot be cast, the
4256 # default boolean fill value is used.
4257 if check._fill_value is not None:
4258 try:
4259 fill = _check_fill_value(check._fill_value, np.bool)
4260 except (TypeError, ValueError):
4261 fill = _check_fill_value(None, np.bool)
4262 check._fill_value = fill
4264 return check
4266 def __eq__(self, other):
4267 """Check whether other equals self elementwise.
4269 When either of the elements is masked, the result is masked as well,
4270 but the underlying boolean data are still set, with self and other
4271 considered equal if both are masked, and unequal otherwise.
4273 For structured arrays, all fields are combined, with masked values
4274 ignored. The result is masked if all fields were masked, with self
4275 and other considered equal only if both were fully masked.
4276 """
4277 return self._comparison(other, operator.eq)
4279 def __ne__(self, other):
4280 """Check whether other does not equal self elementwise.
4282 When either of the elements is masked, the result is masked as well,
4283 but the underlying boolean data are still set, with self and other
4284 considered equal if both are masked, and unequal otherwise.
4286 For structured arrays, all fields are combined, with masked values
4287 ignored. The result is masked if all fields were masked, with self
4288 and other considered equal only if both were fully masked.
4289 """
4290 return self._comparison(other, operator.ne)
4292 # All other comparisons:
4293 def __le__(self, other):
4294 return self._comparison(other, operator.le)
4296 def __lt__(self, other):
4297 return self._comparison(other, operator.lt)
4299 def __ge__(self, other):
4300 return self._comparison(other, operator.ge)
4302 def __gt__(self, other):
4303 return self._comparison(other, operator.gt)
4305 def __add__(self, other):
4306 """
4307 Add self to other, and return a new masked array.
4309 """
4310 if self._delegate_binop(other):
4311 return NotImplemented
4312 return add(self, other)
4314 def __radd__(self, other):
4315 """
4316 Add other to self, and return a new masked array.
4318 """
4319 # In analogy with __rsub__ and __rdiv__, use original order:
4320 # we get here from `other + self`.
4321 return add(other, self)
4323 def __sub__(self, other):
4324 """
4325 Subtract other from self, and return a new masked array.
4327 """
4328 if self._delegate_binop(other):
4329 return NotImplemented
4330 return subtract(self, other)
4332 def __rsub__(self, other):
4333 """
4334 Subtract self from other, and return a new masked array.
4336 """
4337 return subtract(other, self)
4339 def __mul__(self, other):
4340 "Multiply self by other, and return a new masked array."
4341 if self._delegate_binop(other):
4342 return NotImplemented
4343 return multiply(self, other)
4345 def __rmul__(self, other):
4346 """
4347 Multiply other by self, and return a new masked array.
4349 """
4350 # In analogy with __rsub__ and __rdiv__, use original order:
4351 # we get here from `other * self`.
4352 return multiply(other, self)
4354 def __truediv__(self, other):
4355 """
4356 Divide other into self, and return a new masked array.
4358 """
4359 if self._delegate_binop(other):
4360 return NotImplemented
4361 return true_divide(self, other)
4363 def __rtruediv__(self, other):
4364 """
4365 Divide self into other, and return a new masked array.
4367 """
4368 return true_divide(other, self)
4370 def __floordiv__(self, other):
4371 """
4372 Divide other into self, and return a new masked array.
4374 """
4375 if self._delegate_binop(other):
4376 return NotImplemented
4377 return floor_divide(self, other)
4379 def __rfloordiv__(self, other):
4380 """
4381 Divide self into other, and return a new masked array.
4383 """
4384 return floor_divide(other, self)
4386 def __pow__(self, other):
4387 """
4388 Raise self to the power other, masking the potential NaNs/Infs
4390 """
4391 if self._delegate_binop(other):
4392 return NotImplemented
4393 return power(self, other)
4395 def __rpow__(self, other):
4396 """
4397 Raise other to the power self, masking the potential NaNs/Infs
4399 """
4400 return power(other, self)
4402 def __iadd__(self, other):
4403 """
4404 Add other to self in-place.
4406 """
4407 m = getmask(other)
4408 if self._mask is nomask:
4409 if m is not nomask and m.any():
4410 self._mask = make_mask_none(self.shape, self.dtype)
4411 self._mask += m
4412 elif m is not nomask:
4413 self._mask += m
4414 other_data = getdata(other)
4415 other_data = np.where(self._mask, other_data.dtype.type(0), other_data)
4416 self._data.__iadd__(other_data)
4417 return self
4419 def __isub__(self, other):
4420 """
4421 Subtract other from self in-place.
4423 """
4424 m = getmask(other)
4425 if self._mask is nomask:
4426 if m is not nomask and m.any():
4427 self._mask = make_mask_none(self.shape, self.dtype)
4428 self._mask += m
4429 elif m is not nomask:
4430 self._mask += m
4431 other_data = getdata(other)
4432 other_data = np.where(self._mask, other_data.dtype.type(0), other_data)
4433 self._data.__isub__(other_data)
4434 return self
4436 def __imul__(self, other):
4437 """
4438 Multiply self by other in-place.
4440 """
4441 m = getmask(other)
4442 if self._mask is nomask:
4443 if m is not nomask and m.any():
4444 self._mask = make_mask_none(self.shape, self.dtype)
4445 self._mask += m
4446 elif m is not nomask:
4447 self._mask += m
4448 other_data = getdata(other)
4449 other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
4450 self._data.__imul__(other_data)
4451 return self
4453 def __ifloordiv__(self, other):
4454 """
4455 Floor divide self by other in-place.
4457 """
4458 other_data = getdata(other)
4459 dom_mask = _DomainSafeDivide().__call__(self._data, other_data)
4460 other_mask = getmask(other)
4461 new_mask = mask_or(other_mask, dom_mask)
4462 # The following 3 lines control the domain filling
4463 if dom_mask.any():
4464 (_, fval) = ufunc_fills[np.floor_divide]
4465 other_data = np.where(
4466 dom_mask, other_data.dtype.type(fval), other_data)
4467 self._mask |= new_mask
4468 other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
4469 self._data.__ifloordiv__(other_data)
4470 return self
4472 def __itruediv__(self, other):
4473 """
4474 True divide self by other in-place.
4476 """
4477 other_data = getdata(other)
4478 dom_mask = _DomainSafeDivide().__call__(self._data, other_data)
4479 other_mask = getmask(other)
4480 new_mask = mask_or(other_mask, dom_mask)
4481 # The following 3 lines control the domain filling
4482 if dom_mask.any():
4483 (_, fval) = ufunc_fills[np.true_divide]
4484 other_data = np.where(
4485 dom_mask, other_data.dtype.type(fval), other_data)
4486 self._mask |= new_mask
4487 other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
4488 self._data.__itruediv__(other_data)
4489 return self
4491 def __ipow__(self, other):
4492 """
4493 Raise self to the power other, in place.
4495 """
4496 other_data = getdata(other)
4497 other_data = np.where(self._mask, other_data.dtype.type(1), other_data)
4498 other_mask = getmask(other)
4499 with np.errstate(divide='ignore', invalid='ignore'):
4500 self._data.__ipow__(other_data)
4501 invalid = np.logical_not(np.isfinite(self._data))
4502 if invalid.any():
4503 if self._mask is not nomask:
4504 self._mask |= invalid
4505 else:
4506 self._mask = invalid
4507 np.copyto(self._data, self.fill_value, where=invalid)
4508 new_mask = mask_or(other_mask, invalid)
4509 self._mask = mask_or(self._mask, new_mask)
4510 return self
4512 def __float__(self):
4513 """
4514 Convert to float.
4516 """
4517 if self.size > 1:
4518 raise TypeError("Only length-1 arrays can be converted "
4519 "to Python scalars")
4520 elif self._mask:
4521 warnings.warn("Warning: converting a masked element to nan.", stacklevel=2)
4522 return np.nan
4523 return float(self.item())
4525 def __int__(self):
4526 """
4527 Convert to int.
4529 """
4530 if self.size > 1:
4531 raise TypeError("Only length-1 arrays can be converted "
4532 "to Python scalars")
4533 elif self._mask:
4534 raise MaskError('Cannot convert masked element to a Python int.')
4535 return int(self.item())
4537 @property
4538 def imag(self):
4539 """
4540 The imaginary part of the masked array.
4542 This property is a view on the imaginary part of this `MaskedArray`.
4544 See Also
4545 --------
4546 real
4548 Examples
4549 --------
4550 >>> import numpy as np
4551 >>> x = np.ma.array([1+1.j, -2j, 3.45+1.6j], mask=[False, True, False])
4552 >>> x.imag
4553 masked_array(data=[1.0, --, 1.6],
4554 mask=[False, True, False],
4555 fill_value=1e+20)
4557 """
4558 result = self._data.imag.view(type(self))
4559 result.__setmask__(self._mask)
4560 return result
4562 # kept for compatibility
4563 get_imag = imag.fget
4565 @property
4566 def real(self):
4567 """
4568 The real part of the masked array.
4570 This property is a view on the real part of this `MaskedArray`.
4572 See Also
4573 --------
4574 imag
4576 Examples
4577 --------
4578 >>> import numpy as np
4579 >>> x = np.ma.array([1+1.j, -2j, 3.45+1.6j], mask=[False, True, False])
4580 >>> x.real
4581 masked_array(data=[1.0, --, 3.45],
4582 mask=[False, True, False],
4583 fill_value=1e+20)
4585 """
4586 result = self._data.real.view(type(self))
4587 result.__setmask__(self._mask)
4588 return result
4590 # kept for compatibility
4591 get_real = real.fget
4593 def count(self, axis=None, keepdims=np._NoValue):
4594 """
4595 Count the non-masked elements of the array along the given axis.
4597 Parameters
4598 ----------
4599 axis : None or int or tuple of ints, optional
4600 Axis or axes along which the count is performed.
4601 The default, None, performs the count over all
4602 the dimensions of the input array. `axis` may be negative, in
4603 which case it counts from the last to the first axis.
4604 If this is a tuple of ints, the count is performed on multiple
4605 axes, instead of a single axis or all the axes as before.
4606 keepdims : bool, optional
4607 If this is set to True, the axes which are reduced are left
4608 in the result as dimensions with size one. With this option,
4609 the result will broadcast correctly against the array.
4611 Returns
4612 -------
4613 result : ndarray or scalar
4614 An array with the same shape as the input array, with the specified
4615 axis removed. If the array is a 0-d array, or if `axis` is None, a
4616 scalar is returned.
4618 See Also
4619 --------
4620 ma.count_masked : Count masked elements in array or along a given axis.
4622 Examples
4623 --------
4624 >>> import numpy.ma as ma
4625 >>> a = ma.arange(6).reshape((2, 3))
4626 >>> a[1, :] = ma.masked
4627 >>> a
4628 masked_array(
4629 data=[[0, 1, 2],
4630 [--, --, --]],
4631 mask=[[False, False, False],
4632 [ True, True, True]],
4633 fill_value=999999)
4634 >>> a.count()
4635 3
4637 When the `axis` keyword is specified an array of appropriate size is
4638 returned.
4640 >>> a.count(axis=0)
4641 array([1, 1, 1])
4642 >>> a.count(axis=1)
4643 array([3, 0])
4645 """
4646 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
4648 m = self._mask
4649 # special case for matrices (we assume no other subclasses modify
4650 # their dimensions)
4651 if isinstance(self.data, np.matrix):
4652 if m is nomask:
4653 m = np.zeros(self.shape, dtype=np.bool)
4654 m = m.view(type(self.data))
4656 if m is nomask:
4657 # compare to _count_reduce_items in _methods.py
4659 if self.shape == ():
4660 if axis not in (None, 0):
4661 raise np.exceptions.AxisError(axis=axis, ndim=self.ndim)
4662 return 1
4663 elif axis is None:
4664 if kwargs.get('keepdims'):
4665 return np.array(self.size, dtype=np.intp, ndmin=self.ndim)
4666 return self.size
4668 axes = normalize_axis_tuple(axis, self.ndim)
4669 items = 1
4670 for ax in axes:
4671 items *= self.shape[ax]
4673 if kwargs.get('keepdims'):
4674 out_dims = list(self.shape)
4675 for a in axes:
4676 out_dims[a] = 1
4677 else:
4678 out_dims = [d for n, d in enumerate(self.shape)
4679 if n not in axes]
4680 # make sure to return a 0-d array if axis is supplied
4681 return np.full(out_dims, items, dtype=np.intp)
4683 # take care of the masked singleton
4684 if self is masked:
4685 return 0
4687 return (~m).sum(axis=axis, dtype=np.intp, **kwargs)
4689 def ravel(self, order='C'):
4690 """
4691 Returns a 1D version of self, as a view.
4693 Parameters
4694 ----------
4695 order : {'C', 'F', 'A', 'K'}, optional
4696 The elements of `a` are read using this index order. 'C' means to
4697 index the elements in C-like order, with the last axis index
4698 changing fastest, back to the first axis index changing slowest.
4699 'F' means to index the elements in Fortran-like index order, with
4700 the first index changing fastest, and the last index changing
4701 slowest. Note that the 'C' and 'F' options take no account of the
4702 memory layout of the underlying array, and only refer to the order
4703 of axis indexing. 'A' means to read the elements in Fortran-like
4704 index order if `m` is Fortran *contiguous* in memory, C-like order
4705 otherwise. 'K' means to read the elements in the order they occur
4706 in memory, except for reversing the data when strides are negative.
4707 By default, 'C' index order is used.
4708 (Masked arrays currently use 'A' on the data when 'K' is passed.)
4710 Returns
4711 -------
4712 MaskedArray
4713 Output view is of shape ``(self.size,)`` (or
4714 ``(np.ma.product(self.shape),)``).
4716 Examples
4717 --------
4718 >>> import numpy as np
4719 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
4720 >>> x
4721 masked_array(
4722 data=[[1, --, 3],
4723 [--, 5, --],
4724 [7, --, 9]],
4725 mask=[[False, True, False],
4726 [ True, False, True],
4727 [False, True, False]],
4728 fill_value=999999)
4729 >>> x.ravel()
4730 masked_array(data=[1, --, 3, --, 5, --, 7, --, 9],
4731 mask=[False, True, False, True, False, True, False, True,
4732 False],
4733 fill_value=999999)
4735 """
4736 # The order of _data and _mask could be different (it shouldn't be
4737 # normally). Passing order `K` or `A` would be incorrect.
4738 # So we ignore the mask memory order.
4739 # TODO: We don't actually support K, so use A instead. We could
4740 # try to guess this correct by sorting strides or deprecate.
4741 if order in "kKaA":
4742 order = "F" if self._data.flags.fnc else "C"
4743 r = ndarray.ravel(self._data, order=order).view(type(self))
4744 r._update_from(self)
4745 if self._mask is not nomask:
4746 r._mask = ndarray.ravel(self._mask, order=order).reshape(r.shape)
4747 else:
4748 r._mask = nomask
4749 return r
4751 def reshape(self, *s, **kwargs):
4752 """
4753 Give a new shape to the array without changing its data.
4755 Returns a masked array containing the same data, but with a new shape.
4756 The result is a view on the original array; if this is not possible, a
4757 ValueError is raised.
4759 Parameters
4760 ----------
4761 shape : int or tuple of ints
4762 The new shape should be compatible with the original shape. If an
4763 integer is supplied, then the result will be a 1-D array of that
4764 length.
4765 order : {'C', 'F'}, optional
4766 Determines whether the array data should be viewed as in C
4767 (row-major) or FORTRAN (column-major) order.
4769 Returns
4770 -------
4771 reshaped_array : array
4772 A new view on the array.
4774 See Also
4775 --------
4776 reshape : Equivalent function in the masked array module.
4777 numpy.ndarray.reshape : Equivalent method on ndarray object.
4778 numpy.reshape : Equivalent function in the NumPy module.
4780 Notes
4781 -----
4782 The reshaping operation cannot guarantee that a copy will not be made,
4783 to modify the shape in place, use ``a.shape = s``
4785 Examples
4786 --------
4787 >>> import numpy as np
4788 >>> x = np.ma.array([[1,2],[3,4]], mask=[1,0,0,1])
4789 >>> x
4790 masked_array(
4791 data=[[--, 2],
4792 [3, --]],
4793 mask=[[ True, False],
4794 [False, True]],
4795 fill_value=999999)
4796 >>> x = x.reshape((4,1))
4797 >>> x
4798 masked_array(
4799 data=[[--],
4800 [2],
4801 [3],
4802 [--]],
4803 mask=[[ True],
4804 [False],
4805 [False],
4806 [ True]],
4807 fill_value=999999)
4809 """
4810 result = self._data.reshape(*s, **kwargs).view(type(self))
4811 result._update_from(self)
4812 mask = self._mask
4813 if mask is not nomask:
4814 result._mask = mask.reshape(*s, **kwargs)
4815 return result
4817 def resize(self, newshape, refcheck=True, order=False):
4818 """
4819 .. warning::
4821 This method does nothing, except raise a ValueError exception. A
4822 masked array does not own its data and therefore cannot safely be
4823 resized in place. Use the `numpy.ma.resize` function instead.
4825 This method is difficult to implement safely and may be deprecated in
4826 future releases of NumPy.
4828 """
4829 # Note : the 'order' keyword looks broken, let's just drop it
4830 errmsg = "A masked array does not own its data "\
4831 "and therefore cannot be resized.\n" \
4832 "Use the numpy.ma.resize function instead."
4833 raise ValueError(errmsg)
4835 def put(self, indices, values, mode='raise'):
4836 """
4837 Set storage-indexed locations to corresponding values.
4839 Sets self._data.flat[n] = values[n] for each n in indices.
4840 If `values` is shorter than `indices` then it will repeat.
4841 If `values` has some masked values, the initial mask is updated
4842 in consequence, else the corresponding values are unmasked.
4844 Parameters
4845 ----------
4846 indices : 1-D array_like
4847 Target indices, interpreted as integers.
4848 values : array_like
4849 Values to place in self._data copy at target indices.
4850 mode : {'raise', 'wrap', 'clip'}, optional
4851 Specifies how out-of-bounds indices will behave.
4852 'raise' : raise an error.
4853 'wrap' : wrap around.
4854 'clip' : clip to the range.
4856 Notes
4857 -----
4858 `values` can be a scalar or length 1 array.
4860 Examples
4861 --------
4862 >>> import numpy as np
4863 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
4864 >>> x
4865 masked_array(
4866 data=[[1, --, 3],
4867 [--, 5, --],
4868 [7, --, 9]],
4869 mask=[[False, True, False],
4870 [ True, False, True],
4871 [False, True, False]],
4872 fill_value=999999)
4873 >>> x.put([0,4,8],[10,20,30])
4874 >>> x
4875 masked_array(
4876 data=[[10, --, 3],
4877 [--, 20, --],
4878 [7, --, 30]],
4879 mask=[[False, True, False],
4880 [ True, False, True],
4881 [False, True, False]],
4882 fill_value=999999)
4884 >>> x.put(4,999)
4885 >>> x
4886 masked_array(
4887 data=[[10, --, 3],
4888 [--, 999, --],
4889 [7, --, 30]],
4890 mask=[[False, True, False],
4891 [ True, False, True],
4892 [False, True, False]],
4893 fill_value=999999)
4895 """
4896 # Hard mask: Get rid of the values/indices that fall on masked data
4897 if self._hardmask and self._mask is not nomask:
4898 mask = self._mask[indices]
4899 indices = narray(indices, copy=None)
4900 values = narray(values, copy=None, subok=True)
4901 values.resize(indices.shape)
4902 indices = indices[~mask]
4903 values = values[~mask]
4905 self._data.put(indices, values, mode=mode)
4907 # short circuit if neither self nor values are masked
4908 if self._mask is nomask and getmask(values) is nomask:
4909 return
4911 m = getmaskarray(self)
4913 if getmask(values) is nomask:
4914 m.put(indices, False, mode=mode)
4915 else:
4916 m.put(indices, values._mask, mode=mode)
4917 m = make_mask(m, copy=False, shrink=True)
4918 self._mask = m
4919 return
4921 def ids(self):
4922 """
4923 Return the addresses of the data and mask areas.
4925 Parameters
4926 ----------
4927 None
4929 Examples
4930 --------
4931 >>> import numpy as np
4932 >>> x = np.ma.array([1, 2, 3], mask=[0, 1, 1])
4933 >>> x.ids()
4934 (166670640, 166659832) # may vary
4936 If the array has no mask, the address of `nomask` is returned. This address
4937 is typically not close to the data in memory:
4939 >>> x = np.ma.array([1, 2, 3])
4940 >>> x.ids()
4941 (166691080, 3083169284) # may vary
4943 """
4944 if self._mask is nomask:
4945 return (self.ctypes.data, id(nomask))
4946 return (self.ctypes.data, self._mask.ctypes.data)
4948 def iscontiguous(self):
4949 """
4950 Return a boolean indicating whether the data is contiguous.
4952 Parameters
4953 ----------
4954 None
4956 Examples
4957 --------
4958 >>> import numpy as np
4959 >>> x = np.ma.array([1, 2, 3])
4960 >>> x.iscontiguous()
4961 True
4963 `iscontiguous` returns one of the flags of the masked array:
4965 >>> x.flags
4966 C_CONTIGUOUS : True
4967 F_CONTIGUOUS : True
4968 OWNDATA : False
4969 WRITEABLE : True
4970 ALIGNED : True
4971 WRITEBACKIFCOPY : False
4973 """
4974 return self.flags['CONTIGUOUS']
4976 def all(self, axis=None, out=None, keepdims=np._NoValue):
4977 """
4978 Returns True if all elements evaluate to True.
4980 The output array is masked where all the values along the given axis
4981 are masked: if the output would have been a scalar and that all the
4982 values are masked, then the output is `masked`.
4984 Refer to `numpy.all` for full documentation.
4986 See Also
4987 --------
4988 numpy.ndarray.all : corresponding function for ndarrays
4989 numpy.all : equivalent function
4991 Examples
4992 --------
4993 >>> import numpy as np
4994 >>> np.ma.array([1,2,3]).all()
4995 True
4996 >>> a = np.ma.array([1,2,3], mask=True)
4997 >>> (a.all() is np.ma.masked)
4998 True
5000 """
5001 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
5003 mask = _check_mask_axis(self._mask, axis, **kwargs)
5004 if out is None:
5005 d = self.filled(True).all(axis=axis, **kwargs).view(type(self))
5006 if d.ndim:
5007 d.__setmask__(mask)
5008 elif mask:
5009 return masked
5010 return d
5011 self.filled(True).all(axis=axis, out=out, **kwargs)
5012 if isinstance(out, MaskedArray):
5013 if out.ndim or mask:
5014 out.__setmask__(mask)
5015 return out
5017 def any(self, axis=None, out=None, keepdims=np._NoValue):
5018 """
5019 Returns True if any of the elements of `a` evaluate to True.
5021 Masked values are considered as False during computation.
5023 Refer to `numpy.any` for full documentation.
5025 See Also
5026 --------
5027 numpy.ndarray.any : corresponding function for ndarrays
5028 numpy.any : equivalent function
5030 """
5031 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
5033 mask = _check_mask_axis(self._mask, axis, **kwargs)
5034 if out is None:
5035 d = self.filled(False).any(axis=axis, **kwargs).view(type(self))
5036 if d.ndim:
5037 d.__setmask__(mask)
5038 elif mask:
5039 d = masked
5040 return d
5041 self.filled(False).any(axis=axis, out=out, **kwargs)
5042 if isinstance(out, MaskedArray):
5043 if out.ndim or mask:
5044 out.__setmask__(mask)
5045 return out
5047 def nonzero(self):
5048 """
5049 Return the indices of unmasked elements that are not zero.
5051 Returns a tuple of arrays, one for each dimension, containing the
5052 indices of the non-zero elements in that dimension. The corresponding
5053 non-zero values can be obtained with::
5055 a[a.nonzero()]
5057 To group the indices by element, rather than dimension, use
5058 instead::
5060 np.transpose(a.nonzero())
5062 The result of this is always a 2d array, with a row for each non-zero
5063 element.
5065 Parameters
5066 ----------
5067 None
5069 Returns
5070 -------
5071 tuple_of_arrays : tuple
5072 Indices of elements that are non-zero.
5074 See Also
5075 --------
5076 numpy.nonzero :
5077 Function operating on ndarrays.
5078 flatnonzero :
5079 Return indices that are non-zero in the flattened version of the input
5080 array.
5081 numpy.ndarray.nonzero :
5082 Equivalent ndarray method.
5083 count_nonzero :
5084 Counts the number of non-zero elements in the input array.
5086 Examples
5087 --------
5088 >>> import numpy as np
5089 >>> import numpy.ma as ma
5090 >>> x = ma.array(np.eye(3))
5091 >>> x
5092 masked_array(
5093 data=[[1., 0., 0.],
5094 [0., 1., 0.],
5095 [0., 0., 1.]],
5096 mask=False,
5097 fill_value=1e+20)
5098 >>> x.nonzero()
5099 (array([0, 1, 2]), array([0, 1, 2]))
5101 Masked elements are ignored.
5103 >>> x[1, 1] = ma.masked
5104 >>> x
5105 masked_array(
5106 data=[[1.0, 0.0, 0.0],
5107 [0.0, --, 0.0],
5108 [0.0, 0.0, 1.0]],
5109 mask=[[False, False, False],
5110 [False, True, False],
5111 [False, False, False]],
5112 fill_value=1e+20)
5113 >>> x.nonzero()
5114 (array([0, 2]), array([0, 2]))
5116 Indices can also be grouped by element.
5118 >>> np.transpose(x.nonzero())
5119 array([[0, 0],
5120 [2, 2]])
5122 A common use for ``nonzero`` is to find the indices of an array, where
5123 a condition is True. Given an array `a`, the condition `a` > 3 is a
5124 boolean array and since False is interpreted as 0, ma.nonzero(a > 3)
5125 yields the indices of the `a` where the condition is true.
5127 >>> a = ma.array([[1,2,3],[4,5,6],[7,8,9]])
5128 >>> a > 3
5129 masked_array(
5130 data=[[False, False, False],
5131 [ True, True, True],
5132 [ True, True, True]],
5133 mask=False,
5134 fill_value=True)
5135 >>> ma.nonzero(a > 3)
5136 (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))
5138 The ``nonzero`` method of the condition array can also be called.
5140 >>> (a > 3).nonzero()
5141 (array([1, 1, 1, 2, 2, 2]), array([0, 1, 2, 0, 1, 2]))
5143 """
5144 return np.asarray(self.filled(0)).nonzero()
5146 def trace(self, offset=0, axis1=0, axis2=1, dtype=None, out=None):
5147 """
5148 (this docstring should be overwritten)
5149 """
5150 # !!!: implement out + test!
5151 m = self._mask
5152 if m is nomask:
5153 result = super().trace(offset=offset, axis1=axis1, axis2=axis2,
5154 out=out)
5155 return result.astype(dtype)
5156 else:
5157 D = self.diagonal(offset=offset, axis1=axis1, axis2=axis2)
5158 return D.astype(dtype).filled(0).sum(axis=-1, out=out)
5159 trace.__doc__ = ndarray.trace.__doc__
5161 def dot(self, b, out=None, strict=False):
5162 """
5163 a.dot(b, out=None)
5165 Masked dot product of two arrays. Note that `out` and `strict` are
5166 located in different positions than in `ma.dot`. In order to
5167 maintain compatibility with the functional version, it is
5168 recommended that the optional arguments be treated as keyword only.
5169 At some point that may be mandatory.
5171 Parameters
5172 ----------
5173 b : masked_array_like
5174 Inputs array.
5175 out : masked_array, optional
5176 Output argument. This must have the exact kind that would be
5177 returned if it was not used. In particular, it must have the
5178 right type, must be C-contiguous, and its dtype must be the
5179 dtype that would be returned for `ma.dot(a,b)`. This is a
5180 performance feature. Therefore, if these conditions are not
5181 met, an exception is raised, instead of attempting to be
5182 flexible.
5183 strict : bool, optional
5184 Whether masked data are propagated (True) or set to 0 (False)
5185 for the computation. Default is False. Propagating the mask
5186 means that if a masked value appears in a row or column, the
5187 whole row or column is considered masked.
5189 See Also
5190 --------
5191 numpy.ma.dot : equivalent function
5193 """
5194 return dot(self, b, out=out, strict=strict)
5196 def sum(self, axis=None, dtype=None, out=None, keepdims=np._NoValue):
5197 """
5198 Return the sum of the array elements over the given axis.
5200 Masked elements are set to 0 internally.
5202 Refer to `numpy.sum` for full documentation.
5204 See Also
5205 --------
5206 numpy.ndarray.sum : corresponding function for ndarrays
5207 numpy.sum : equivalent function
5209 Examples
5210 --------
5211 >>> import numpy as np
5212 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
5213 >>> x
5214 masked_array(
5215 data=[[1, --, 3],
5216 [--, 5, --],
5217 [7, --, 9]],
5218 mask=[[False, True, False],
5219 [ True, False, True],
5220 [False, True, False]],
5221 fill_value=999999)
5222 >>> x.sum()
5223 25
5224 >>> x.sum(axis=1)
5225 masked_array(data=[4, 5, 16],
5226 mask=[False, False, False],
5227 fill_value=999999)
5228 >>> x.sum(axis=0)
5229 masked_array(data=[8, 5, 12],
5230 mask=[False, False, False],
5231 fill_value=999999)
5232 >>> print(type(x.sum(axis=0, dtype=np.int64)[0]))
5233 <class 'numpy.int64'>
5235 """
5236 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
5238 _mask = self._mask
5239 newmask = _check_mask_axis(_mask, axis, **kwargs)
5240 # No explicit output
5241 if out is None:
5242 result = self.filled(0).sum(axis, dtype=dtype, **kwargs)
5243 rndim = getattr(result, 'ndim', 0)
5244 if rndim:
5245 result = result.view(type(self))
5246 result.__setmask__(newmask)
5247 elif newmask:
5248 result = masked
5249 return result
5250 # Explicit output
5251 result = self.filled(0).sum(axis, dtype=dtype, out=out, **kwargs)
5252 if isinstance(out, MaskedArray):
5253 outmask = getmask(out)
5254 if outmask is nomask:
5255 outmask = out._mask = make_mask_none(out.shape)
5256 outmask.flat = newmask
5257 return out
5259 def cumsum(self, axis=None, dtype=None, out=None):
5260 """
5261 Return the cumulative sum of the array elements over the given axis.
5263 Masked values are set to 0 internally during the computation.
5264 However, their position is saved, and the result will be masked at
5265 the same locations.
5267 Refer to `numpy.cumsum` for full documentation.
5269 Notes
5270 -----
5271 The mask is lost if `out` is not a valid :class:`ma.MaskedArray` !
5273 Arithmetic is modular when using integer types, and no error is
5274 raised on overflow.
5276 See Also
5277 --------
5278 numpy.ndarray.cumsum : corresponding function for ndarrays
5279 numpy.cumsum : equivalent function
5281 Examples
5282 --------
5283 >>> import numpy as np
5284 >>> marr = np.ma.array(np.arange(10), mask=[0,0,0,1,1,1,0,0,0,0])
5285 >>> marr.cumsum()
5286 masked_array(data=[0, 1, 3, --, --, --, 9, 16, 24, 33],
5287 mask=[False, False, False, True, True, True, False, False,
5288 False, False],
5289 fill_value=999999)
5291 """
5292 result = self.filled(0).cumsum(axis=axis, dtype=dtype, out=out)
5293 if out is not None:
5294 if isinstance(out, MaskedArray):
5295 out.__setmask__(self.mask)
5296 return out
5297 result = result.view(type(self))
5298 result.__setmask__(self._mask)
5299 return result
5301 def prod(self, axis=None, dtype=None, out=None, keepdims=np._NoValue):
5302 """
5303 Return the product of the array elements over the given axis.
5305 Masked elements are set to 1 internally for computation.
5307 Refer to `numpy.prod` for full documentation.
5309 Notes
5310 -----
5311 Arithmetic is modular when using integer types, and no error is raised
5312 on overflow.
5314 See Also
5315 --------
5316 numpy.ndarray.prod : corresponding function for ndarrays
5317 numpy.prod : equivalent function
5318 """
5319 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
5321 _mask = self._mask
5322 newmask = _check_mask_axis(_mask, axis, **kwargs)
5323 # No explicit output
5324 if out is None:
5325 result = self.filled(1).prod(axis, dtype=dtype, **kwargs)
5326 rndim = getattr(result, 'ndim', 0)
5327 if rndim:
5328 result = result.view(type(self))
5329 result.__setmask__(newmask)
5330 elif newmask:
5331 result = masked
5332 return result
5333 # Explicit output
5334 result = self.filled(1).prod(axis, dtype=dtype, out=out, **kwargs)
5335 if isinstance(out, MaskedArray):
5336 outmask = getmask(out)
5337 if outmask is nomask:
5338 outmask = out._mask = make_mask_none(out.shape)
5339 outmask.flat = newmask
5340 return out
5341 product = prod
5343 def cumprod(self, axis=None, dtype=None, out=None):
5344 """
5345 Return the cumulative product of the array elements over the given axis.
5347 Masked values are set to 1 internally during the computation.
5348 However, their position is saved, and the result will be masked at
5349 the same locations.
5351 Refer to `numpy.cumprod` for full documentation.
5353 Notes
5354 -----
5355 The mask is lost if `out` is not a valid MaskedArray !
5357 Arithmetic is modular when using integer types, and no error is
5358 raised on overflow.
5360 See Also
5361 --------
5362 numpy.ndarray.cumprod : corresponding function for ndarrays
5363 numpy.cumprod : equivalent function
5364 """
5365 result = self.filled(1).cumprod(axis=axis, dtype=dtype, out=out)
5366 if out is not None:
5367 if isinstance(out, MaskedArray):
5368 out.__setmask__(self._mask)
5369 return out
5370 result = result.view(type(self))
5371 result.__setmask__(self._mask)
5372 return result
5374 def mean(self, axis=None, dtype=None, out=None, keepdims=np._NoValue):
5375 """
5376 Returns the average of the array elements along given axis.
5378 Masked entries are ignored, and result elements which are not
5379 finite will be masked.
5381 Refer to `numpy.mean` for full documentation.
5383 See Also
5384 --------
5385 numpy.ndarray.mean : corresponding function for ndarrays
5386 numpy.mean : Equivalent function
5387 numpy.ma.average : Weighted average.
5389 Examples
5390 --------
5391 >>> import numpy as np
5392 >>> a = np.ma.array([1,2,3], mask=[False, False, True])
5393 >>> a
5394 masked_array(data=[1, 2, --],
5395 mask=[False, False, True],
5396 fill_value=999999)
5397 >>> a.mean()
5398 1.5
5400 """
5401 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
5402 if self._mask is nomask:
5403 result = super().mean(axis=axis, dtype=dtype, **kwargs)[()]
5404 else:
5405 is_float16_result = False
5406 if dtype is None:
5407 if issubclass(self.dtype.type, (ntypes.integer, ntypes.bool)):
5408 dtype = mu.dtype('f8')
5409 elif issubclass(self.dtype.type, ntypes.float16):
5410 dtype = mu.dtype('f4')
5411 is_float16_result = True
5412 dsum = self.sum(axis=axis, dtype=dtype, **kwargs)
5413 cnt = self.count(axis=axis, **kwargs)
5414 if cnt.shape == () and (cnt == 0):
5415 result = masked
5416 elif is_float16_result:
5417 result = self.dtype.type(dsum * 1. / cnt)
5418 else:
5419 result = dsum * 1. / cnt
5420 if out is not None:
5421 out.flat = result
5422 if isinstance(out, MaskedArray):
5423 outmask = getmask(out)
5424 if outmask is nomask:
5425 outmask = out._mask = make_mask_none(out.shape)
5426 outmask.flat = getmask(result)
5427 return out
5428 return result
5430 def anom(self, axis=None, dtype=None):
5431 """
5432 Compute the anomalies (deviations from the arithmetic mean)
5433 along the given axis.
5435 Returns an array of anomalies, with the same shape as the input and
5436 where the arithmetic mean is computed along the given axis.
5438 Parameters
5439 ----------
5440 axis : int, optional
5441 Axis over which the anomalies are taken.
5442 The default is to use the mean of the flattened array as reference.
5443 dtype : dtype, optional
5444 Type to use in computing the variance. For arrays of integer type
5445 the default is float32; for arrays of float types it is the same as
5446 the array type.
5448 See Also
5449 --------
5450 mean : Compute the mean of the array.
5452 Examples
5453 --------
5454 >>> import numpy as np
5455 >>> a = np.ma.array([1,2,3])
5456 >>> a.anom()
5457 masked_array(data=[-1., 0., 1.],
5458 mask=False,
5459 fill_value=1e+20)
5461 """
5462 m = self.mean(axis, dtype)
5463 if not axis:
5464 return self - m
5465 else:
5466 return self - expand_dims(m, axis)
5468 def var(self, axis=None, dtype=None, out=None, ddof=0,
5469 keepdims=np._NoValue, mean=np._NoValue):
5470 """
5471 Returns the variance of the array elements along given axis.
5473 Masked entries are ignored, and result elements which are not
5474 finite will be masked.
5476 Refer to `numpy.var` for full documentation.
5478 See Also
5479 --------
5480 numpy.ndarray.var : corresponding function for ndarrays
5481 numpy.var : Equivalent function
5482 """
5483 kwargs = {}
5485 if keepdims is not np._NoValue:
5486 kwargs['keepdims'] = keepdims
5488 # Easy case: nomask, business as usual
5489 if self._mask is nomask:
5491 if mean is not np._NoValue:
5492 kwargs['mean'] = mean
5494 ret = super().var(axis=axis, dtype=dtype, out=out, ddof=ddof,
5495 **kwargs)[()]
5496 if out is not None:
5497 if isinstance(out, MaskedArray):
5498 out.__setmask__(nomask)
5499 return out
5500 return ret
5502 # Some data are masked, yay!
5503 cnt = self.count(axis=axis, **kwargs) - ddof
5505 if mean is not np._NoValue:
5506 danom = self - mean
5507 else:
5508 danom = self - self.mean(axis, dtype, keepdims=True)
5510 if iscomplexobj(self):
5511 danom = umath.absolute(danom) ** 2
5512 else:
5513 danom *= danom
5514 dvar = divide(danom.sum(axis, **kwargs), cnt).view(type(self))
5515 # Apply the mask if it's not a scalar
5516 if dvar.ndim:
5517 dvar._mask = mask_or(self._mask.all(axis, **kwargs), (cnt <= 0))
5518 dvar._update_from(self)
5519 elif getmask(dvar):
5520 # Make sure that masked is returned when the scalar is masked.
5521 dvar = masked
5522 if out is not None:
5523 if isinstance(out, MaskedArray):
5524 out.flat = 0
5525 out.__setmask__(True)
5526 elif out.dtype.kind in 'biu':
5527 errmsg = "Masked data information would be lost in one or "\
5528 "more location."
5529 raise MaskError(errmsg)
5530 else:
5531 out.flat = np.nan
5532 return out
5533 # In case with have an explicit output
5534 if out is not None:
5535 # Set the data
5536 out.flat = dvar
5537 # Set the mask if needed
5538 if isinstance(out, MaskedArray):
5539 out.__setmask__(dvar.mask)
5540 return out
5541 return dvar
5542 var.__doc__ = np.var.__doc__
5544 def std(self, axis=None, dtype=None, out=None, ddof=0,
5545 keepdims=np._NoValue, mean=np._NoValue):
5546 """
5547 Returns the standard deviation of the array elements along given axis.
5549 Masked entries are ignored.
5551 Refer to `numpy.std` for full documentation.
5553 See Also
5554 --------
5555 numpy.ndarray.std : corresponding function for ndarrays
5556 numpy.std : Equivalent function
5557 """
5558 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
5560 dvar = self.var(axis, dtype, out, ddof, **kwargs)
5561 if dvar is not masked:
5562 if out is not None:
5563 np.power(out, 0.5, out=out, casting='unsafe')
5564 return out
5565 dvar = sqrt(dvar)
5566 return dvar
5568 def round(self, decimals=0, out=None):
5569 """
5570 Return each element rounded to the given number of decimals.
5572 Refer to `numpy.around` for full documentation.
5574 See Also
5575 --------
5576 numpy.ndarray.round : corresponding function for ndarrays
5577 numpy.around : equivalent function
5579 Examples
5580 --------
5581 >>> import numpy as np
5582 >>> import numpy.ma as ma
5583 >>> x = ma.array([1.35, 2.5, 1.5, 1.75, 2.25, 2.75],
5584 ... mask=[0, 0, 0, 1, 0, 0])
5585 >>> ma.round(x)
5586 masked_array(data=[1.0, 2.0, 2.0, --, 2.0, 3.0],
5587 mask=[False, False, False, True, False, False],
5588 fill_value=1e+20)
5590 """
5591 result = self._data.round(decimals=decimals, out=out).view(type(self))
5592 if result.ndim > 0:
5593 result._mask = self._mask
5594 result._update_from(self)
5595 elif self._mask:
5596 # Return masked when the scalar is masked
5597 result = masked
5598 # No explicit output: we're done
5599 if out is None:
5600 return result
5601 if isinstance(out, MaskedArray):
5602 out.__setmask__(self._mask)
5603 return out
5605 def argsort(self, axis=np._NoValue, kind=None, order=None, endwith=True,
5606 fill_value=None, *, stable=False):
5607 """
5608 Return an ndarray of indices that sort the array along the
5609 specified axis. Masked values are filled beforehand to
5610 `fill_value`.
5612 Parameters
5613 ----------
5614 axis : int, optional
5615 Axis along which to sort. If None, the default, the flattened array
5616 is used.
5617 kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional
5618 The sorting algorithm used.
5619 order : str or list of str, optional
5620 When `a` is an array with fields defined, this argument specifies
5621 which fields to compare first, second, etc. Not all fields need be
5622 specified.
5623 endwith : {True, False}, optional
5624 Whether missing values (if any) should be treated as the largest values
5625 (True) or the smallest values (False)
5626 When the array contains unmasked values at the same extremes of the
5627 datatype, the ordering of these values and the masked values is
5628 undefined.
5629 fill_value : scalar or None, optional
5630 Value used internally for the masked values.
5631 If ``fill_value`` is not None, it supersedes ``endwith``.
5632 stable : bool, optional
5633 Only for compatibility with ``np.argsort``. Ignored.
5635 Returns
5636 -------
5637 index_array : ndarray, int
5638 Array of indices that sort `a` along the specified axis.
5639 In other words, ``a[index_array]`` yields a sorted `a`.
5641 See Also
5642 --------
5643 ma.MaskedArray.sort : Describes sorting algorithms used.
5644 lexsort : Indirect stable sort with multiple keys.
5645 numpy.ndarray.sort : Inplace sort.
5647 Notes
5648 -----
5649 See `sort` for notes on the different sorting algorithms.
5651 Examples
5652 --------
5653 >>> import numpy as np
5654 >>> a = np.ma.array([3,2,1], mask=[False, False, True])
5655 >>> a
5656 masked_array(data=[3, 2, --],
5657 mask=[False, False, True],
5658 fill_value=999999)
5659 >>> a.argsort()
5660 array([1, 0, 2])
5662 """
5663 if stable:
5664 raise ValueError(
5665 "`stable` parameter is not supported for masked arrays."
5666 )
5668 # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default
5669 if axis is np._NoValue:
5670 axis = _deprecate_argsort_axis(self)
5672 if fill_value is None:
5673 if endwith:
5674 # nan > inf
5675 if np.issubdtype(self.dtype, np.floating):
5676 fill_value = np.nan
5677 else:
5678 fill_value = minimum_fill_value(self)
5679 else:
5680 fill_value = maximum_fill_value(self)
5682 filled = self.filled(fill_value)
5683 return filled.argsort(axis=axis, kind=kind, order=order)
5685 def argmin(self, axis=None, fill_value=None, out=None, *,
5686 keepdims=np._NoValue):
5687 """
5688 Return array of indices to the minimum values along the given axis.
5690 Parameters
5691 ----------
5692 axis : {None, integer}
5693 If None, the index is into the flattened array, otherwise along
5694 the specified axis
5695 fill_value : scalar or None, optional
5696 Value used to fill in the masked values. If None, the output of
5697 minimum_fill_value(self._data) is used instead.
5698 out : {None, array}, optional
5699 Array into which the result can be placed. Its type is preserved
5700 and it must be of the right shape to hold the output.
5702 Returns
5703 -------
5704 ndarray or scalar
5705 If multi-dimension input, returns a new ndarray of indices to the
5706 minimum values along the given axis. Otherwise, returns a scalar
5707 of index to the minimum values along the given axis.
5709 Examples
5710 --------
5711 >>> import numpy as np
5712 >>> x = np.ma.array(np.arange(4), mask=[1,1,0,0])
5713 >>> x.shape = (2,2)
5714 >>> x
5715 masked_array(
5716 data=[[--, --],
5717 [2, 3]],
5718 mask=[[ True, True],
5719 [False, False]],
5720 fill_value=999999)
5721 >>> x.argmin(axis=0, fill_value=-1)
5722 array([0, 0])
5723 >>> x.argmin(axis=0, fill_value=9)
5724 array([1, 1])
5726 """
5727 if fill_value is None:
5728 fill_value = minimum_fill_value(self)
5729 d = self.filled(fill_value).view(ndarray)
5730 keepdims = False if keepdims is np._NoValue else bool(keepdims)
5731 return d.argmin(axis, out=out, keepdims=keepdims)
5733 def argmax(self, axis=None, fill_value=None, out=None, *,
5734 keepdims=np._NoValue):
5735 """
5736 Returns array of indices of the maximum values along the given axis.
5737 Masked values are treated as if they had the value fill_value.
5739 Parameters
5740 ----------
5741 axis : {None, integer}
5742 If None, the index is into the flattened array, otherwise along
5743 the specified axis
5744 fill_value : scalar or None, optional
5745 Value used to fill in the masked values. If None, the output of
5746 maximum_fill_value(self._data) is used instead.
5747 out : {None, array}, optional
5748 Array into which the result can be placed. Its type is preserved
5749 and it must be of the right shape to hold the output.
5751 Returns
5752 -------
5753 index_array : {integer_array}
5755 Examples
5756 --------
5757 >>> import numpy as np
5758 >>> a = np.arange(6).reshape(2,3)
5759 >>> a.argmax()
5760 5
5761 >>> a.argmax(0)
5762 array([1, 1, 1])
5763 >>> a.argmax(1)
5764 array([2, 2])
5766 """
5767 if fill_value is None:
5768 fill_value = maximum_fill_value(self._data)
5769 d = self.filled(fill_value).view(ndarray)
5770 keepdims = False if keepdims is np._NoValue else bool(keepdims)
5771 return d.argmax(axis, out=out, keepdims=keepdims)
5773 def sort(self, axis=-1, kind=None, order=None, endwith=True,
5774 fill_value=None, *, stable=False):
5775 """
5776 Sort the array, in-place
5778 Parameters
5779 ----------
5780 a : array_like
5781 Array to be sorted.
5782 axis : int, optional
5783 Axis along which to sort. If None, the array is flattened before
5784 sorting. The default is -1, which sorts along the last axis.
5785 kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional
5786 The sorting algorithm used.
5787 order : list, optional
5788 When `a` is a structured array, this argument specifies which fields
5789 to compare first, second, and so on. This list does not need to
5790 include all of the fields.
5791 endwith : {True, False}, optional
5792 Whether missing values (if any) should be treated as the largest values
5793 (True) or the smallest values (False)
5794 When the array contains unmasked values sorting at the same extremes of the
5795 datatype, the ordering of these values and the masked values is
5796 undefined.
5797 fill_value : scalar or None, optional
5798 Value used internally for the masked values.
5799 If ``fill_value`` is not None, it supersedes ``endwith``.
5800 stable : bool, optional
5801 Only for compatibility with ``np.sort``. Ignored.
5803 See Also
5804 --------
5805 numpy.ndarray.sort : Method to sort an array in-place.
5806 argsort : Indirect sort.
5807 lexsort : Indirect stable sort on multiple keys.
5808 searchsorted : Find elements in a sorted array.
5810 Notes
5811 -----
5812 See ``sort`` for notes on the different sorting algorithms.
5814 Examples
5815 --------
5816 >>> import numpy as np
5817 >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0])
5818 >>> # Default
5819 >>> a.sort()
5820 >>> a
5821 masked_array(data=[1, 3, 5, --, --],
5822 mask=[False, False, False, True, True],
5823 fill_value=999999)
5825 >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0])
5826 >>> # Put missing values in the front
5827 >>> a.sort(endwith=False)
5828 >>> a
5829 masked_array(data=[--, --, 1, 3, 5],
5830 mask=[ True, True, False, False, False],
5831 fill_value=999999)
5833 >>> a = np.ma.array([1, 2, 5, 4, 3],mask=[0, 1, 0, 1, 0])
5834 >>> # fill_value takes over endwith
5835 >>> a.sort(endwith=False, fill_value=3)
5836 >>> a
5837 masked_array(data=[1, --, --, 3, 5],
5838 mask=[False, True, True, False, False],
5839 fill_value=999999)
5841 """
5842 if stable:
5843 raise ValueError(
5844 "`stable` parameter is not supported for masked arrays."
5845 )
5847 if self._mask is nomask:
5848 ndarray.sort(self, axis=axis, kind=kind, order=order)
5849 return
5851 if self is masked:
5852 return
5854 sidx = self.argsort(axis=axis, kind=kind, order=order,
5855 fill_value=fill_value, endwith=endwith)
5857 self[...] = np.take_along_axis(self, sidx, axis=axis)
5859 def min(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
5860 """
5861 Return the minimum along a given axis.
5863 Parameters
5864 ----------
5865 axis : None or int or tuple of ints, optional
5866 Axis along which to operate. By default, ``axis`` is None and the
5867 flattened input is used.
5868 If this is a tuple of ints, the minimum is selected over multiple
5869 axes, instead of a single axis or all the axes as before.
5870 out : array_like, optional
5871 Alternative output array in which to place the result. Must be of
5872 the same shape and buffer length as the expected output.
5873 fill_value : scalar or None, optional
5874 Value used to fill in the masked values.
5875 If None, use the output of `minimum_fill_value`.
5876 keepdims : bool, optional
5877 If this is set to True, the axes which are reduced are left
5878 in the result as dimensions with size one. With this option,
5879 the result will broadcast correctly against the array.
5881 Returns
5882 -------
5883 amin : array_like
5884 New array holding the result.
5885 If ``out`` was specified, ``out`` is returned.
5887 See Also
5888 --------
5889 ma.minimum_fill_value
5890 Returns the minimum filling value for a given datatype.
5892 Examples
5893 --------
5894 >>> import numpy.ma as ma
5895 >>> x = [[1., -2., 3.], [0.2, -0.7, 0.1]]
5896 >>> mask = [[1, 1, 0], [0, 0, 1]]
5897 >>> masked_x = ma.masked_array(x, mask)
5898 >>> masked_x
5899 masked_array(
5900 data=[[--, --, 3.0],
5901 [0.2, -0.7, --]],
5902 mask=[[ True, True, False],
5903 [False, False, True]],
5904 fill_value=1e+20)
5905 >>> ma.min(masked_x)
5906 -0.7
5907 >>> ma.min(masked_x, axis=-1)
5908 masked_array(data=[3.0, -0.7],
5909 mask=[False, False],
5910 fill_value=1e+20)
5911 >>> ma.min(masked_x, axis=0, keepdims=True)
5912 masked_array(data=[[0.2, -0.7, 3.0]],
5913 mask=[[False, False, False]],
5914 fill_value=1e+20)
5915 >>> mask = [[1, 1, 1,], [1, 1, 1]]
5916 >>> masked_x = ma.masked_array(x, mask)
5917 >>> ma.min(masked_x, axis=0)
5918 masked_array(data=[--, --, --],
5919 mask=[ True, True, True],
5920 fill_value=1e+20,
5921 dtype=float64)
5922 """
5923 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
5925 _mask = self._mask
5926 newmask = _check_mask_axis(_mask, axis, **kwargs)
5927 if fill_value is None:
5928 fill_value = minimum_fill_value(self)
5929 # No explicit output
5930 if out is None:
5931 result = self.filled(fill_value).min(
5932 axis=axis, out=out, **kwargs).view(type(self))
5933 if result.ndim:
5934 # Set the mask
5935 result.__setmask__(newmask)
5936 # Get rid of Infs
5937 if newmask.ndim:
5938 np.copyto(result, result.fill_value, where=newmask)
5939 elif newmask:
5940 result = masked
5941 return result
5942 # Explicit output
5943 self.filled(fill_value).min(axis=axis, out=out, **kwargs)
5944 if isinstance(out, MaskedArray):
5945 outmask = getmask(out)
5946 if outmask is nomask:
5947 outmask = out._mask = make_mask_none(out.shape)
5948 outmask.flat = newmask
5949 else:
5950 if out.dtype.kind in 'biu':
5951 errmsg = "Masked data information would be lost in one or more"\
5952 " location."
5953 raise MaskError(errmsg)
5954 np.copyto(out, np.nan, where=newmask)
5955 return out
5957 def max(self, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
5958 """
5959 Return the maximum along a given axis.
5961 Parameters
5962 ----------
5963 axis : None or int or tuple of ints, optional
5964 Axis along which to operate. By default, ``axis`` is None and the
5965 flattened input is used.
5966 If this is a tuple of ints, the maximum is selected over multiple
5967 axes, instead of a single axis or all the axes as before.
5968 out : array_like, optional
5969 Alternative output array in which to place the result. Must
5970 be of the same shape and buffer length as the expected output.
5971 fill_value : scalar or None, optional
5972 Value used to fill in the masked values.
5973 If None, use the output of maximum_fill_value().
5974 keepdims : bool, optional
5975 If this is set to True, the axes which are reduced are left
5976 in the result as dimensions with size one. With this option,
5977 the result will broadcast correctly against the array.
5979 Returns
5980 -------
5981 amax : array_like
5982 New array holding the result.
5983 If ``out`` was specified, ``out`` is returned.
5985 See Also
5986 --------
5987 ma.maximum_fill_value
5988 Returns the maximum filling value for a given datatype.
5990 Examples
5991 --------
5992 >>> import numpy.ma as ma
5993 >>> x = [[-1., 2.5], [4., -2.], [3., 0.]]
5994 >>> mask = [[0, 0], [1, 0], [1, 0]]
5995 >>> masked_x = ma.masked_array(x, mask)
5996 >>> masked_x
5997 masked_array(
5998 data=[[-1.0, 2.5],
5999 [--, -2.0],
6000 [--, 0.0]],
6001 mask=[[False, False],
6002 [ True, False],
6003 [ True, False]],
6004 fill_value=1e+20)
6005 >>> ma.max(masked_x)
6006 2.5
6007 >>> ma.max(masked_x, axis=0)
6008 masked_array(data=[-1.0, 2.5],
6009 mask=[False, False],
6010 fill_value=1e+20)
6011 >>> ma.max(masked_x, axis=1, keepdims=True)
6012 masked_array(
6013 data=[[2.5],
6014 [-2.0],
6015 [0.0]],
6016 mask=[[False],
6017 [False],
6018 [False]],
6019 fill_value=1e+20)
6020 >>> mask = [[1, 1], [1, 1], [1, 1]]
6021 >>> masked_x = ma.masked_array(x, mask)
6022 >>> ma.max(masked_x, axis=1)
6023 masked_array(data=[--, --, --],
6024 mask=[ True, True, True],
6025 fill_value=1e+20,
6026 dtype=float64)
6027 """
6028 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
6030 _mask = self._mask
6031 newmask = _check_mask_axis(_mask, axis, **kwargs)
6032 if fill_value is None:
6033 fill_value = maximum_fill_value(self)
6034 # No explicit output
6035 if out is None:
6036 result = self.filled(fill_value).max(
6037 axis=axis, out=out, **kwargs).view(type(self))
6038 if result.ndim:
6039 # Set the mask
6040 result.__setmask__(newmask)
6041 # Get rid of Infs
6042 if newmask.ndim:
6043 np.copyto(result, result.fill_value, where=newmask)
6044 elif newmask:
6045 result = masked
6046 return result
6047 # Explicit output
6048 self.filled(fill_value).max(axis=axis, out=out, **kwargs)
6049 if isinstance(out, MaskedArray):
6050 outmask = getmask(out)
6051 if outmask is nomask:
6052 outmask = out._mask = make_mask_none(out.shape)
6053 outmask.flat = newmask
6054 else:
6056 if out.dtype.kind in 'biu':
6057 errmsg = "Masked data information would be lost in one or more"\
6058 " location."
6059 raise MaskError(errmsg)
6060 np.copyto(out, np.nan, where=newmask)
6061 return out
6063 def ptp(self, axis=None, out=None, fill_value=None, keepdims=False):
6064 """
6065 Return (maximum - minimum) along the given dimension
6066 (i.e. peak-to-peak value).
6068 .. warning::
6069 `ptp` preserves the data type of the array. This means the
6070 return value for an input of signed integers with n bits
6071 (e.g. `np.int8`, `np.int16`, etc) is also a signed integer
6072 with n bits. In that case, peak-to-peak values greater than
6073 ``2**(n-1)-1`` will be returned as negative values. An example
6074 with a work-around is shown below.
6076 Parameters
6077 ----------
6078 axis : {None, int}, optional
6079 Axis along which to find the peaks. If None (default) the
6080 flattened array is used.
6081 out : {None, array_like}, optional
6082 Alternative output array in which to place the result. It must
6083 have the same shape and buffer length as the expected output
6084 but the type will be cast if necessary.
6085 fill_value : scalar or None, optional
6086 Value used to fill in the masked values.
6087 keepdims : bool, optional
6088 If this is set to True, the axes which are reduced are left
6089 in the result as dimensions with size one. With this option,
6090 the result will broadcast correctly against the array.
6092 Returns
6093 -------
6094 ptp : ndarray.
6095 A new array holding the result, unless ``out`` was
6096 specified, in which case a reference to ``out`` is returned.
6098 Examples
6099 --------
6100 >>> import numpy as np
6101 >>> x = np.ma.MaskedArray([[4, 9, 2, 10],
6102 ... [6, 9, 7, 12]])
6104 >>> x.ptp(axis=1)
6105 masked_array(data=[8, 6],
6106 mask=False,
6107 fill_value=999999)
6109 >>> x.ptp(axis=0)
6110 masked_array(data=[2, 0, 5, 2],
6111 mask=False,
6112 fill_value=999999)
6114 >>> x.ptp()
6115 10
6117 This example shows that a negative value can be returned when
6118 the input is an array of signed integers.
6120 >>> y = np.ma.MaskedArray([[1, 127],
6121 ... [0, 127],
6122 ... [-1, 127],
6123 ... [-2, 127]], dtype=np.int8)
6124 >>> y.ptp(axis=1)
6125 masked_array(data=[ 126, 127, -128, -127],
6126 mask=False,
6127 fill_value=np.int64(999999),
6128 dtype=int8)
6130 A work-around is to use the `view()` method to view the result as
6131 unsigned integers with the same bit width:
6133 >>> y.ptp(axis=1).view(np.uint8)
6134 masked_array(data=[126, 127, 128, 129],
6135 mask=False,
6136 fill_value=np.uint64(999999),
6137 dtype=uint8)
6138 """
6139 if out is None:
6140 result = self.max(axis=axis, fill_value=fill_value,
6141 keepdims=keepdims)
6142 result -= self.min(axis=axis, fill_value=fill_value,
6143 keepdims=keepdims)
6144 return result
6145 out.flat = self.max(axis=axis, out=out, fill_value=fill_value,
6146 keepdims=keepdims)
6147 min_value = self.min(axis=axis, fill_value=fill_value,
6148 keepdims=keepdims)
6149 np.subtract(out, min_value, out=out, casting='unsafe')
6150 return out
6152 def partition(self, *args, **kwargs):
6153 warnings.warn("Warning: 'partition' will ignore the 'mask' "
6154 f"of the {self.__class__.__name__}.",
6155 stacklevel=2)
6156 return super().partition(*args, **kwargs)
6158 def argpartition(self, *args, **kwargs):
6159 warnings.warn("Warning: 'argpartition' will ignore the 'mask' "
6160 f"of the {self.__class__.__name__}.",
6161 stacklevel=2)
6162 return super().argpartition(*args, **kwargs)
6164 def take(self, indices, axis=None, out=None, mode='raise'):
6165 """
6166 Take elements from a masked array along an axis.
6168 This function does the same thing as "fancy" indexing (indexing arrays
6169 using arrays) for masked arrays. It can be easier to use if you need
6170 elements along a given axis.
6172 Parameters
6173 ----------
6174 a : masked_array
6175 The source masked array.
6176 indices : array_like
6177 The indices of the values to extract. Also allow scalars for indices.
6178 axis : int, optional
6179 The axis over which to select values. By default, the flattened
6180 input array is used.
6181 out : MaskedArray, optional
6182 If provided, the result will be placed in this array. It should
6183 be of the appropriate shape and dtype. Note that `out` is always
6184 buffered if `mode='raise'`; use other modes for better performance.
6185 mode : {'raise', 'wrap', 'clip'}, optional
6186 Specifies how out-of-bounds indices will behave.
6188 * 'raise' -- raise an error (default)
6189 * 'wrap' -- wrap around
6190 * 'clip' -- clip to the range
6192 'clip' mode means that all indices that are too large are replaced
6193 by the index that addresses the last element along that axis. Note
6194 that this disables indexing with negative numbers.
6196 Returns
6197 -------
6198 out : MaskedArray
6199 The returned array has the same type as `a`.
6201 See Also
6202 --------
6203 numpy.take : Equivalent function for ndarrays.
6204 compress : Take elements using a boolean mask.
6205 take_along_axis : Take elements by matching the array and the index arrays.
6207 Notes
6208 -----
6209 This function behaves similarly to `numpy.take`, but it handles masked
6210 values. The mask is retained in the output array, and masked values
6211 in the input array remain masked in the output.
6213 Examples
6214 --------
6215 >>> import numpy as np
6216 >>> a = np.ma.array([4, 3, 5, 7, 6, 8], mask=[0, 0, 1, 0, 1, 0])
6217 >>> indices = [0, 1, 4]
6218 >>> np.ma.take(a, indices)
6219 masked_array(data=[4, 3, --],
6220 mask=[False, False, True],
6221 fill_value=999999)
6223 When `indices` is not one-dimensional, the output also has these dimensions:
6225 >>> np.ma.take(a, [[0, 1], [2, 3]])
6226 masked_array(data=[[4, 3],
6227 [--, 7]],
6228 mask=[[False, False],
6229 [ True, False]],
6230 fill_value=999999)
6231 """
6232 (_data, _mask) = (self._data, self._mask)
6233 cls = type(self)
6234 # Make sure the indices are not masked
6235 maskindices = getmask(indices)
6236 if maskindices is not nomask:
6237 indices = indices.filled(0)
6238 # Get the data, promoting scalars to 0d arrays with [...] so that
6239 # .view works correctly
6240 if out is None:
6241 out = _data.take(indices, axis=axis, mode=mode)[...].view(cls)
6242 else:
6243 np.take(_data, indices, axis=axis, mode=mode, out=out)
6244 # Get the mask
6245 if isinstance(out, MaskedArray):
6246 if _mask is nomask:
6247 outmask = maskindices
6248 else:
6249 outmask = _mask.take(indices, axis=axis, mode=mode)
6250 outmask |= maskindices
6251 out.__setmask__(outmask)
6252 # demote 0d arrays back to scalars, for consistency with ndarray.take
6253 return out[()]
6255 # Array methods
6256 copy = _arraymethod('copy')
6257 diagonal = _arraymethod('diagonal')
6258 flatten = _arraymethod('flatten')
6259 repeat = _arraymethod('repeat')
6260 squeeze = _arraymethod('squeeze')
6261 swapaxes = _arraymethod('swapaxes')
6262 T = property(fget=lambda self: self.transpose())
6263 transpose = _arraymethod('transpose')
6265 @property
6266 def mT(self):
6267 """
6268 Return the matrix-transpose of the masked array.
6270 The matrix transpose is the transpose of the last two dimensions, even
6271 if the array is of higher dimension.
6273 .. versionadded:: 2.0
6275 Returns
6276 -------
6277 result: MaskedArray
6278 The masked array with the last two dimensions transposed
6280 Raises
6281 ------
6282 ValueError
6283 If the array is of dimension less than 2.
6285 See Also
6286 --------
6287 ndarray.mT:
6288 Equivalent method for arrays
6289 """
6291 if self.ndim < 2:
6292 raise ValueError("matrix transpose with ndim < 2 is undefined")
6294 if self._mask is nomask:
6295 return masked_array(data=self._data.mT)
6296 else:
6297 return masked_array(data=self.data.mT, mask=self.mask.mT)
6299 def tolist(self, fill_value=None):
6300 """
6301 Return the data portion of the masked array as a hierarchical Python list.
6303 Data items are converted to the nearest compatible Python type.
6304 Masked values are converted to `fill_value`. If `fill_value` is None,
6305 the corresponding entries in the output list will be ``None``.
6307 Parameters
6308 ----------
6309 fill_value : scalar, optional
6310 The value to use for invalid entries. Default is None.
6312 Returns
6313 -------
6314 result : list
6315 The Python list representation of the masked array.
6317 Examples
6318 --------
6319 >>> import numpy as np
6320 >>> x = np.ma.array([[1,2,3], [4,5,6], [7,8,9]], mask=[0] + [1,0]*4)
6321 >>> x.tolist()
6322 [[1, None, 3], [None, 5, None], [7, None, 9]]
6323 >>> x.tolist(-999)
6324 [[1, -999, 3], [-999, 5, -999], [7, -999, 9]]
6326 """
6327 _mask = self._mask
6328 # No mask ? Just return .data.tolist ?
6329 if _mask is nomask:
6330 return self._data.tolist()
6331 # Explicit fill_value: fill the array and get the list
6332 if fill_value is not None:
6333 return self.filled(fill_value).tolist()
6334 # Structured array.
6335 names = self.dtype.names
6336 if names:
6337 result = self._data.astype([(_, object) for _ in names])
6338 for n in names:
6339 result[n][_mask[n]] = None
6340 return result.tolist()
6341 # Standard arrays.
6342 if _mask is nomask:
6343 return [None]
6344 # Set temps to save time when dealing w/ marrays.
6345 inishape = self.shape
6346 result = np.array(self._data.ravel(), dtype=object)
6347 result[_mask.ravel()] = None
6348 result.shape = inishape
6349 return result.tolist()
6351 def tobytes(self, fill_value=None, order='C'):
6352 """
6353 Return the array data as a string containing the raw bytes in the array.
6355 The array is filled with a fill value before the string conversion.
6357 Parameters
6358 ----------
6359 fill_value : scalar, optional
6360 Value used to fill in the masked values. Default is None, in which
6361 case `MaskedArray.fill_value` is used.
6362 order : {'C','F','A'}, optional
6363 Order of the data item in the copy. Default is 'C'.
6365 - 'C' -- C order (row major).
6366 - 'F' -- Fortran order (column major).
6367 - 'A' -- Any, current order of array.
6368 - None -- Same as 'A'.
6370 See Also
6371 --------
6372 numpy.ndarray.tobytes
6373 tolist, tofile
6375 Notes
6376 -----
6377 As for `ndarray.tobytes`, information about the shape, dtype, etc.,
6378 but also about `fill_value`, will be lost.
6380 Examples
6381 --------
6382 >>> import numpy as np
6383 >>> x = np.ma.array(np.array([[1, 2], [3, 4]]), mask=[[0, 1], [1, 0]])
6384 >>> x.tobytes()
6385 b'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00?B\\x0f\\x00\\x00\\x00\\x00\\x00?B\\x0f\\x00\\x00\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x00'
6387 """
6388 return self.filled(fill_value).tobytes(order=order)
6390 def tofile(self, fid, sep="", format="%s"):
6391 """
6392 Save a masked array to a file in binary format.
6394 .. warning::
6395 This function is not implemented yet.
6397 Raises
6398 ------
6399 NotImplementedError
6400 When `tofile` is called.
6402 """
6403 raise NotImplementedError("MaskedArray.tofile() not implemented yet.")
6405 def toflex(self):
6406 """
6407 Transforms a masked array into a flexible-type array.
6409 The flexible type array that is returned will have two fields:
6411 * the ``_data`` field stores the ``_data`` part of the array.
6412 * the ``_mask`` field stores the ``_mask`` part of the array.
6414 Parameters
6415 ----------
6416 None
6418 Returns
6419 -------
6420 record : ndarray
6421 A new flexible-type `ndarray` with two fields: the first element
6422 containing a value, the second element containing the corresponding
6423 mask boolean. The returned record shape matches self.shape.
6425 Notes
6426 -----
6427 A side-effect of transforming a masked array into a flexible `ndarray` is
6428 that meta information (``fill_value``, ...) will be lost.
6430 Examples
6431 --------
6432 >>> import numpy as np
6433 >>> x = np.ma.array([[1,2,3],[4,5,6],[7,8,9]], mask=[0] + [1,0]*4)
6434 >>> x
6435 masked_array(
6436 data=[[1, --, 3],
6437 [--, 5, --],
6438 [7, --, 9]],
6439 mask=[[False, True, False],
6440 [ True, False, True],
6441 [False, True, False]],
6442 fill_value=999999)
6443 >>> x.toflex()
6444 array([[(1, False), (2, True), (3, False)],
6445 [(4, True), (5, False), (6, True)],
6446 [(7, False), (8, True), (9, False)]],
6447 dtype=[('_data', '<i8'), ('_mask', '?')])
6449 """
6450 # Get the basic dtype.
6451 ddtype = self.dtype
6452 # Make sure we have a mask
6453 _mask = self._mask
6454 if _mask is None:
6455 _mask = make_mask_none(self.shape, ddtype)
6456 # And get its dtype
6457 mdtype = self._mask.dtype
6459 record = np.ndarray(shape=self.shape,
6460 dtype=[('_data', ddtype), ('_mask', mdtype)])
6461 record['_data'] = self._data
6462 record['_mask'] = self._mask
6463 return record
6464 torecords = toflex
6466 # Pickling
6467 def __getstate__(self):
6468 """Return the internal state of the masked array, for pickling
6469 purposes.
6471 """
6472 cf = 'CF'[self.flags.fnc]
6473 data_state = super().__reduce__()[2]
6474 return data_state + (getmaskarray(self).tobytes(cf), self._fill_value)
6476 def __setstate__(self, state):
6477 """Restore the internal state of the masked array, for
6478 pickling purposes. ``state`` is typically the output of the
6479 ``__getstate__`` output, and is a 5-tuple:
6481 - class name
6482 - a tuple giving the shape of the data
6483 - a typecode for the data
6484 - a binary string for the data
6485 - a binary string for the mask.
6487 """
6488 (_, shp, typ, isf, raw, msk, flv) = state
6489 super().__setstate__((shp, typ, isf, raw))
6490 self._mask.__setstate__((shp, make_mask_descr(typ), isf, msk))
6491 self.fill_value = flv
6493 def __reduce__(self):
6494 """Return a 3-tuple for pickling a MaskedArray.
6496 """
6497 return (_mareconstruct,
6498 (self.__class__, self._baseclass, (0,), 'b',),
6499 self.__getstate__())
6501 def __deepcopy__(self, memo=None):
6502 from copy import deepcopy
6503 copied = MaskedArray.__new__(type(self), self, copy=True)
6504 if memo is None:
6505 memo = {}
6506 memo[id(self)] = copied
6507 for (k, v) in self.__dict__.items():
6508 copied.__dict__[k] = deepcopy(v, memo)
6509 # as clearly documented for np.copy(), you need to use
6510 # deepcopy() directly for arrays of object type that may
6511 # contain compound types--you cannot depend on normal
6512 # copy semantics to do the right thing here
6513 if self.dtype.hasobject:
6514 copied._data[...] = deepcopy(copied._data)
6515 return copied
6518def _mareconstruct(subtype, baseclass, baseshape, basetype,):
6519 """Internal function that builds a new MaskedArray from the
6520 information stored in a pickle.
6522 """
6523 _data = ndarray.__new__(baseclass, baseshape, basetype)
6524 _mask = ndarray.__new__(ndarray, baseshape, make_mask_descr(basetype))
6525 return subtype.__new__(subtype, _data, mask=_mask, dtype=basetype,)
6528class mvoid(MaskedArray):
6529 """
6530 Fake a 'void' object to use for masked array with structured dtypes.
6531 """
6533 def __new__(self, data, mask=nomask, dtype=None, fill_value=None,
6534 hardmask=False, copy=False, subok=True):
6535 copy = None if not copy else True
6536 _data = np.array(data, copy=copy, subok=subok, dtype=dtype)
6537 _data = _data.view(self)
6538 _data._hardmask = hardmask
6539 if mask is not nomask:
6540 if isinstance(mask, np.void):
6541 _data._mask = mask
6542 else:
6543 try:
6544 # Mask is already a 0D array
6545 _data._mask = np.void(mask)
6546 except TypeError:
6547 # Transform the mask to a void
6548 mdtype = make_mask_descr(dtype)
6549 _data._mask = np.array(mask, dtype=mdtype)[()]
6550 if fill_value is not None:
6551 _data.fill_value = fill_value
6552 return _data
6554 @property
6555 def _data(self):
6556 # Make sure that the _data part is a np.void
6557 return super()._data[()]
6559 def __getitem__(self, indx):
6560 """
6561 Get the index.
6563 """
6564 m = self._mask
6565 if isinstance(m[indx], ndarray):
6566 # Can happen when indx is a multi-dimensional field:
6567 # A = ma.masked_array(data=[([0,1],)], mask=[([True,
6568 # False],)], dtype=[("A", ">i2", (2,))])
6569 # x = A[0]; y = x["A"]; then y.mask["A"].size==2
6570 # and we can not say masked/unmasked.
6571 # The result is no longer mvoid!
6572 # See also issue #6724.
6573 return masked_array(
6574 data=self._data[indx], mask=m[indx],
6575 fill_value=self._fill_value[indx],
6576 hard_mask=self._hardmask)
6577 if m is not nomask and m[indx]:
6578 return masked
6579 return self._data[indx]
6581 def __setitem__(self, indx, value):
6582 self._data[indx] = value
6583 if self._hardmask:
6584 self._mask[indx] |= getattr(value, "_mask", False)
6585 else:
6586 self._mask[indx] = getattr(value, "_mask", False)
6588 def __str__(self):
6589 m = self._mask
6590 if m is nomask:
6591 return str(self._data)
6593 rdtype = _replace_dtype_fields(self._data.dtype, "O")
6594 data_arr = super()._data
6595 res = data_arr.astype(rdtype)
6596 _recursive_printoption(res, self._mask, masked_print_option)
6597 return str(res)
6599 __repr__ = __str__
6601 def __iter__(self):
6602 "Defines an iterator for mvoid"
6603 (_data, _mask) = (self._data, self._mask)
6604 if _mask is nomask:
6605 yield from _data
6606 else:
6607 for (d, m) in zip(_data, _mask):
6608 if m:
6609 yield masked
6610 else:
6611 yield d
6613 def __len__(self):
6614 return self._data.__len__()
6616 def filled(self, fill_value=None):
6617 """
6618 Return a copy with masked fields filled with a given value.
6620 Parameters
6621 ----------
6622 fill_value : array_like, optional
6623 The value to use for invalid entries. Can be scalar or
6624 non-scalar. If latter is the case, the filled array should
6625 be broadcastable over input array. Default is None, in
6626 which case the `fill_value` attribute is used instead.
6628 Returns
6629 -------
6630 filled_void
6631 A `np.void` object
6633 See Also
6634 --------
6635 MaskedArray.filled
6637 """
6638 return asarray(self).filled(fill_value)[()]
6640 def tolist(self):
6641 """
6642 Transforms the mvoid object into a tuple.
6644 Masked fields are replaced by None.
6646 Returns
6647 -------
6648 returned_tuple
6649 Tuple of fields
6650 """
6651 _mask = self._mask
6652 if _mask is nomask:
6653 return self._data.tolist()
6654 result = []
6655 for (d, m) in zip(self._data, self._mask):
6656 if m:
6657 result.append(None)
6658 else:
6659 # .item() makes sure we return a standard Python object
6660 result.append(d.item())
6661 return tuple(result)
6664##############################################################################
6665# Shortcuts #
6666##############################################################################
6669def isMaskedArray(x):
6670 """
6671 Test whether input is an instance of MaskedArray.
6673 This function returns True if `x` is an instance of MaskedArray
6674 and returns False otherwise. Any object is accepted as input.
6676 Parameters
6677 ----------
6678 x : object
6679 Object to test.
6681 Returns
6682 -------
6683 result : bool
6684 True if `x` is a MaskedArray.
6686 See Also
6687 --------
6688 isMA : Alias to isMaskedArray.
6689 isarray : Alias to isMaskedArray.
6691 Examples
6692 --------
6693 >>> import numpy as np
6694 >>> import numpy.ma as ma
6695 >>> a = np.eye(3, 3)
6696 >>> a
6697 array([[ 1., 0., 0.],
6698 [ 0., 1., 0.],
6699 [ 0., 0., 1.]])
6700 >>> m = ma.masked_values(a, 0)
6701 >>> m
6702 masked_array(
6703 data=[[1.0, --, --],
6704 [--, 1.0, --],
6705 [--, --, 1.0]],
6706 mask=[[False, True, True],
6707 [ True, False, True],
6708 [ True, True, False]],
6709 fill_value=0.0)
6710 >>> ma.isMaskedArray(a)
6711 False
6712 >>> ma.isMaskedArray(m)
6713 True
6714 >>> ma.isMaskedArray([0, 1, 2])
6715 False
6717 """
6718 return isinstance(x, MaskedArray)
6721isarray = isMaskedArray
6722isMA = isMaskedArray # backward compatibility
6725class MaskedConstant(MaskedArray):
6726 # the lone np.ma.masked instance
6727 __singleton = None
6729 @classmethod
6730 def __has_singleton(cls):
6731 # second case ensures `cls.__singleton` is not just a view on the
6732 # superclass singleton
6733 return cls.__singleton is not None and type(cls.__singleton) is cls
6735 def __new__(cls):
6736 if not cls.__has_singleton():
6737 # We define the masked singleton as a float for higher precedence.
6738 # Note that it can be tricky sometimes w/ type comparison
6739 data = np.array(0.)
6740 mask = np.array(True)
6742 # prevent any modifications
6743 data.flags.writeable = False
6744 mask.flags.writeable = False
6746 # don't fall back on MaskedArray.__new__(MaskedConstant), since
6747 # that might confuse it - this way, the construction is entirely
6748 # within our control
6749 cls.__singleton = MaskedArray(data, mask=mask).view(cls)
6751 return cls.__singleton
6753 def __array_finalize__(self, obj):
6754 if not self.__has_singleton():
6755 # this handles the `.view` in __new__, which we want to copy across
6756 # properties normally
6757 return super().__array_finalize__(obj)
6758 elif self is self.__singleton:
6759 # not clear how this can happen, play it safe
6760 pass
6761 else:
6762 # everywhere else, we want to downcast to MaskedArray, to prevent a
6763 # duplicate maskedconstant.
6764 self.__class__ = MaskedArray
6765 MaskedArray.__array_finalize__(self, obj)
6767 def __array_wrap__(self, obj, context=None, return_scalar=False):
6768 return self.view(MaskedArray).__array_wrap__(obj, context)
6770 def __str__(self):
6771 return str(masked_print_option._display)
6773 def __repr__(self):
6774 if self is MaskedConstant.__singleton:
6775 return 'masked'
6776 else:
6777 # it's a subclass, or something is wrong, make it obvious
6778 return object.__repr__(self)
6780 def __format__(self, format_spec):
6781 # Replace ndarray.__format__ with the default, which supports no
6782 # format characters.
6783 # Supporting format characters is unwise here, because we do not know
6784 # what type the user was expecting - better to not guess.
6785 try:
6786 return object.__format__(self, format_spec)
6787 except TypeError:
6788 # 2020-03-23, NumPy 1.19.0
6789 warnings.warn(
6790 "Format strings passed to MaskedConstant are ignored,"
6791 " but in future may error or produce different behavior",
6792 FutureWarning, stacklevel=2
6793 )
6794 return object.__format__(self, "")
6796 def __reduce__(self):
6797 """Override of MaskedArray's __reduce__.
6798 """
6799 return (self.__class__, ())
6801 # inplace operations have no effect. We have to override them to avoid
6802 # trying to modify the readonly data and mask arrays
6803 def __iop__(self, other):
6804 return self
6805 __iadd__ = \
6806 __isub__ = \
6807 __imul__ = \
6808 __ifloordiv__ = \
6809 __itruediv__ = \
6810 __ipow__ = \
6811 __iop__
6812 del __iop__ # don't leave this around
6814 def copy(self, *args, **kwargs):
6815 """ Copy is a no-op on the maskedconstant, as it is a scalar """
6816 # maskedconstant is a scalar, so copy doesn't need to copy. There's
6817 # precedent for this with `np.bool` scalars.
6818 return self
6820 def __copy__(self):
6821 return self
6823 def __deepcopy__(self, memo):
6824 return self
6826 def __setattr__(self, attr, value):
6827 if not self.__has_singleton():
6828 # allow the singleton to be initialized
6829 return super().__setattr__(attr, value)
6830 elif self is self.__singleton:
6831 raise AttributeError(
6832 f"attributes of {self!r} are not writeable")
6833 else:
6834 # duplicate instance - we can end up here from __array_finalize__,
6835 # where we set the __class__ attribute
6836 return super().__setattr__(attr, value)
6839masked = masked_singleton = MaskedConstant()
6840masked_array = MaskedArray
6843def array(data, dtype=None, copy=False, order=None,
6844 mask=nomask, fill_value=None, keep_mask=True,
6845 hard_mask=False, shrink=True, subok=True, ndmin=0):
6846 """
6847 Shortcut to MaskedArray.
6849 The options are in a different order for convenience and backwards
6850 compatibility.
6852 """
6853 return MaskedArray(data, mask=mask, dtype=dtype, copy=copy,
6854 subok=subok, keep_mask=keep_mask,
6855 hard_mask=hard_mask, fill_value=fill_value,
6856 ndmin=ndmin, shrink=shrink, order=order)
6859array.__doc__ = masked_array.__doc__
6862def is_masked(x):
6863 """
6864 Determine whether input has masked values.
6866 Accepts any object as input, but always returns False unless the
6867 input is a MaskedArray containing masked values.
6869 Parameters
6870 ----------
6871 x : array_like
6872 Array to check for masked values.
6874 Returns
6875 -------
6876 result : bool
6877 True if `x` is a MaskedArray with masked values, False otherwise.
6879 Examples
6880 --------
6881 >>> import numpy as np
6882 >>> import numpy.ma as ma
6883 >>> x = ma.masked_equal([0, 1, 0, 2, 3], 0)
6884 >>> x
6885 masked_array(data=[--, 1, --, 2, 3],
6886 mask=[ True, False, True, False, False],
6887 fill_value=0)
6888 >>> ma.is_masked(x)
6889 True
6890 >>> x = ma.masked_equal([0, 1, 0, 2, 3], 42)
6891 >>> x
6892 masked_array(data=[0, 1, 0, 2, 3],
6893 mask=False,
6894 fill_value=42)
6895 >>> ma.is_masked(x)
6896 False
6898 Always returns False if `x` isn't a MaskedArray.
6900 >>> x = [False, True, False]
6901 >>> ma.is_masked(x)
6902 False
6903 >>> x = 'a string'
6904 >>> ma.is_masked(x)
6905 False
6907 """
6908 m = getmask(x)
6909 if m is nomask:
6910 return False
6911 elif m.any():
6912 return True
6913 return False
6916##############################################################################
6917# Extrema functions #
6918##############################################################################
6921class _extrema_operation(_MaskedUFunc):
6922 """
6923 Generic class for maximum/minimum functions.
6925 .. note::
6926 This is the base class for `_maximum_operation` and
6927 `_minimum_operation`.
6929 """
6930 def __init__(self, ufunc, compare, fill_value):
6931 super().__init__(ufunc)
6932 self.compare = compare
6933 self.fill_value_func = fill_value
6935 def __call__(self, a, b):
6936 "Executes the call behavior."
6938 return where(self.compare(a, b), a, b)
6940 def reduce(self, target, axis=np._NoValue):
6941 "Reduce target along the given axis."
6942 target = narray(target, copy=None, subok=True)
6943 m = getmask(target)
6945 if axis is np._NoValue and target.ndim > 1:
6946 name = self.__name__
6947 # 2017-05-06, Numpy 1.13.0: warn on axis default
6948 warnings.warn(
6949 f"In the future the default for ma.{name}.reduce will be axis=0, "
6950 f"not the current None, to match np.{name}.reduce. "
6951 "Explicitly pass 0 or None to silence this warning.",
6952 MaskedArrayFutureWarning, stacklevel=2)
6953 axis = None
6955 if axis is not np._NoValue:
6956 kwargs = {'axis': axis}
6957 else:
6958 kwargs = {}
6960 if m is nomask:
6961 t = self.f.reduce(target, **kwargs)
6962 else:
6963 target = target.filled(
6964 self.fill_value_func(target)).view(type(target))
6965 t = self.f.reduce(target, **kwargs)
6966 m = umath.logical_and.reduce(m, **kwargs)
6967 if hasattr(t, '_mask'):
6968 t._mask = m
6969 elif m:
6970 t = masked
6971 return t
6973 def outer(self, a, b):
6974 "Return the function applied to the outer product of a and b."
6975 ma = getmask(a)
6976 mb = getmask(b)
6977 if ma is nomask and mb is nomask:
6978 m = nomask
6979 else:
6980 ma = getmaskarray(a)
6981 mb = getmaskarray(b)
6982 m = logical_or.outer(ma, mb)
6983 result = self.f.outer(filled(a), filled(b))
6984 if not isinstance(result, MaskedArray):
6985 result = result.view(MaskedArray)
6986 result._mask = m
6987 return result
6989def min(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
6990 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
6992 try:
6993 return obj.min(axis=axis, fill_value=fill_value, out=out, **kwargs)
6994 except (AttributeError, TypeError):
6995 # If obj doesn't have a min method, or if the method doesn't accept a
6996 # fill_value argument
6997 return asanyarray(obj).min(axis=axis, fill_value=fill_value,
6998 out=out, **kwargs)
7001min.__doc__ = MaskedArray.min.__doc__
7003def max(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
7004 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
7006 try:
7007 return obj.max(axis=axis, fill_value=fill_value, out=out, **kwargs)
7008 except (AttributeError, TypeError):
7009 # If obj doesn't have a max method, or if the method doesn't accept a
7010 # fill_value argument
7011 return asanyarray(obj).max(axis=axis, fill_value=fill_value,
7012 out=out, **kwargs)
7015max.__doc__ = MaskedArray.max.__doc__
7018def ptp(obj, axis=None, out=None, fill_value=None, keepdims=np._NoValue):
7019 kwargs = {} if keepdims is np._NoValue else {'keepdims': keepdims}
7020 try:
7021 return obj.ptp(axis, out=out, fill_value=fill_value, **kwargs)
7022 except (AttributeError, TypeError):
7023 # If obj doesn't have a ptp method or if the method doesn't accept
7024 # a fill_value argument
7025 return asanyarray(obj).ptp(axis=axis, fill_value=fill_value,
7026 out=out, **kwargs)
7029ptp.__doc__ = MaskedArray.ptp.__doc__
7032##############################################################################
7033# Definition of functions from the corresponding methods #
7034##############################################################################
7037def _frommethod(methodname: str, reversed: bool = False):
7038 """
7039 Define functions from existing MaskedArray methods.
7041 Parameters
7042 ----------
7043 methodname : str
7044 Name of the method to transform.
7045 reversed : bool, optional
7046 Whether to reverse the first two arguments of the method. Default is False.
7047 """
7048 method = getattr(MaskedArray, methodname)
7049 assert callable(method)
7051 signature = inspect.signature(method)
7052 params = list(signature.parameters.values())
7053 params[0] = params[0].replace(name="a") # rename 'self' to 'a'
7055 if reversed:
7056 assert len(params) >= 2
7057 params[0], params[1] = params[1], params[0]
7059 def wrapper(a, b, *args, **params):
7060 return getattr(asanyarray(b), methodname)(a, *args, **params)
7062 else:
7063 def wrapper(a, *args, **params):
7064 return getattr(asanyarray(a), methodname)(*args, **params)
7066 wrapper.__signature__ = signature.replace(parameters=params)
7067 wrapper.__name__ = wrapper.__qualname__ = methodname
7069 # __doc__ is None when using `python -OO ...`
7070 if method.__doc__ is not None:
7071 str_signature = f"{methodname}{signature}"
7072 # TODO: For methods with a docstring "Parameters" section, that do not already
7073 # mention `a` (see e.g. `MaskedArray.var.__doc__`), it should be inserted there.
7074 wrapper.__doc__ = f" {str_signature}\n{method.__doc__}"
7076 return wrapper
7079all = _frommethod('all')
7080anomalies = anom = _frommethod('anom')
7081any = _frommethod('any')
7082argmax = _frommethod('argmax')
7083argmin = _frommethod('argmin')
7084compress = _frommethod('compress', reversed=True)
7085count = _frommethod('count')
7086cumprod = _frommethod('cumprod')
7087cumsum = _frommethod('cumsum')
7088copy = _frommethod('copy')
7089diagonal = _frommethod('diagonal')
7090harden_mask = _frommethod('harden_mask')
7091ids = _frommethod('ids')
7092maximum = _extrema_operation(umath.maximum, greater, maximum_fill_value)
7093mean = _frommethod('mean')
7094minimum = _extrema_operation(umath.minimum, less, minimum_fill_value)
7095nonzero = _frommethod('nonzero')
7096prod = _frommethod('prod')
7097product = _frommethod('product')
7098ravel = _frommethod('ravel')
7099repeat = _frommethod('repeat')
7100shrink_mask = _frommethod('shrink_mask')
7101soften_mask = _frommethod('soften_mask')
7102std = _frommethod('std')
7103sum = _frommethod('sum')
7104swapaxes = _frommethod('swapaxes')
7105#take = _frommethod('take')
7106trace = _frommethod('trace')
7107var = _frommethod('var')
7110def take(a, indices, axis=None, out=None, mode='raise'):
7111 """
7113 """
7114 a = masked_array(a)
7115 return a.take(indices, axis=axis, out=out, mode=mode)
7118def power(a, b, third=None):
7119 """
7120 Returns element-wise base array raised to power from second array.
7122 This is the masked array version of `numpy.power`. For details see
7123 `numpy.power`.
7125 See Also
7126 --------
7127 numpy.power
7129 Notes
7130 -----
7131 The *out* argument to `numpy.power` is not supported, `third` has to be
7132 None.
7134 Examples
7135 --------
7136 >>> import numpy as np
7137 >>> import numpy.ma as ma
7138 >>> x = [11.2, -3.973, 0.801, -1.41]
7139 >>> mask = [0, 0, 0, 1]
7140 >>> masked_x = ma.masked_array(x, mask)
7141 >>> masked_x
7142 masked_array(data=[11.2, -3.973, 0.801, --],
7143 mask=[False, False, False, True],
7144 fill_value=1e+20)
7145 >>> ma.power(masked_x, 2)
7146 masked_array(data=[125.43999999999998, 15.784728999999999,
7147 0.6416010000000001, --],
7148 mask=[False, False, False, True],
7149 fill_value=1e+20)
7150 >>> y = [-0.5, 2, 0, 17]
7151 >>> masked_y = ma.masked_array(y, mask)
7152 >>> masked_y
7153 masked_array(data=[-0.5, 2.0, 0.0, --],
7154 mask=[False, False, False, True],
7155 fill_value=1e+20)
7156 >>> ma.power(masked_x, masked_y)
7157 masked_array(data=[0.2988071523335984, 15.784728999999999, 1.0, --],
7158 mask=[False, False, False, True],
7159 fill_value=1e+20)
7161 """
7162 if third is not None:
7163 raise MaskError("3-argument power not supported.")
7164 # Get the masks
7165 ma = getmask(a)
7166 mb = getmask(b)
7167 m = mask_or(ma, mb)
7168 # Get the rawdata
7169 fa = getdata(a)
7170 fb = getdata(b)
7171 # Get the type of the result (so that we preserve subclasses)
7172 if isinstance(a, MaskedArray):
7173 basetype = type(a)
7174 else:
7175 basetype = MaskedArray
7176 # Get the result and view it as a (subclass of) MaskedArray
7177 with np.errstate(divide='ignore', invalid='ignore'):
7178 result = np.where(m, fa, umath.power(fa, fb)).view(basetype)
7179 result._update_from(a)
7180 # Find where we're in trouble w/ NaNs and Infs
7181 invalid = np.logical_not(np.isfinite(result.view(ndarray)))
7182 # Add the initial mask
7183 if m is not nomask:
7184 if not result.ndim:
7185 return masked
7186 result._mask = np.logical_or(m, invalid)
7187 # Fix the invalid parts
7188 if invalid.any():
7189 if not result.ndim:
7190 return masked
7191 elif result._mask is nomask:
7192 result._mask = invalid
7193 result._data[invalid] = result.fill_value
7194 return result
7197def argsort(a, axis=np._NoValue, kind=None, order=None, endwith=True,
7198 fill_value=None, *, stable=None):
7199 "Function version of the eponymous method."
7200 a = np.asanyarray(a)
7202 # 2017-04-11, Numpy 1.13.0, gh-8701: warn on axis default
7203 if axis is np._NoValue:
7204 axis = _deprecate_argsort_axis(a)
7206 if isinstance(a, MaskedArray):
7207 return a.argsort(axis=axis, kind=kind, order=order, endwith=endwith,
7208 fill_value=fill_value, stable=None)
7209 else:
7210 return a.argsort(axis=axis, kind=kind, order=order, stable=None)
7213argsort.__doc__ = MaskedArray.argsort.__doc__
7215def sort(a, axis=-1, kind=None, order=None, endwith=True, fill_value=None, *,
7216 stable=None):
7217 """
7218 Return a sorted copy of the masked array.
7220 Equivalent to creating a copy of the array
7221 and applying the MaskedArray ``sort()`` method.
7223 Refer to ``MaskedArray.sort`` for the full documentation
7225 See Also
7226 --------
7227 MaskedArray.sort : equivalent method
7229 Examples
7230 --------
7231 >>> import numpy as np
7232 >>> import numpy.ma as ma
7233 >>> x = [11.2, -3.973, 0.801, -1.41]
7234 >>> mask = [0, 0, 0, 1]
7235 >>> masked_x = ma.masked_array(x, mask)
7236 >>> masked_x
7237 masked_array(data=[11.2, -3.973, 0.801, --],
7238 mask=[False, False, False, True],
7239 fill_value=1e+20)
7240 >>> ma.sort(masked_x)
7241 masked_array(data=[-3.973, 0.801, 11.2, --],
7242 mask=[False, False, False, True],
7243 fill_value=1e+20)
7244 """
7245 a = np.array(a, copy=True, subok=True)
7246 if axis is None:
7247 a = a.flatten()
7248 axis = 0
7250 if isinstance(a, MaskedArray):
7251 a.sort(axis=axis, kind=kind, order=order, endwith=endwith,
7252 fill_value=fill_value, stable=stable)
7253 else:
7254 a.sort(axis=axis, kind=kind, order=order, stable=stable)
7255 return a
7258def compressed(x):
7259 """
7260 Return all the non-masked data as a 1-D array.
7262 This function is equivalent to calling the "compressed" method of a
7263 `ma.MaskedArray`, see `ma.MaskedArray.compressed` for details.
7265 See Also
7266 --------
7267 ma.MaskedArray.compressed : Equivalent method.
7269 Examples
7270 --------
7271 >>> import numpy as np
7273 Create an array with negative values masked:
7275 >>> import numpy as np
7276 >>> x = np.array([[1, -1, 0], [2, -1, 3], [7, 4, -1]])
7277 >>> masked_x = np.ma.masked_array(x, mask=x < 0)
7278 >>> masked_x
7279 masked_array(
7280 data=[[1, --, 0],
7281 [2, --, 3],
7282 [7, 4, --]],
7283 mask=[[False, True, False],
7284 [False, True, False],
7285 [False, False, True]],
7286 fill_value=999999)
7288 Compress the masked array into a 1-D array of non-masked values:
7290 >>> np.ma.compressed(masked_x)
7291 array([1, 0, 2, 3, 7, 4])
7293 """
7294 return asanyarray(x).compressed()
7297def concatenate(arrays, axis=0):
7298 """
7299 Concatenate a sequence of arrays along the given axis.
7301 Parameters
7302 ----------
7303 arrays : sequence of array_like
7304 The arrays must have the same shape, except in the dimension
7305 corresponding to `axis` (the first, by default).
7306 axis : int, optional
7307 The axis along which the arrays will be joined. Default is 0.
7309 Returns
7310 -------
7311 result : MaskedArray
7312 The concatenated array with any masked entries preserved.
7314 See Also
7315 --------
7316 numpy.concatenate : Equivalent function in the top-level NumPy module.
7318 Examples
7319 --------
7320 >>> import numpy as np
7321 >>> import numpy.ma as ma
7322 >>> a = ma.arange(3)
7323 >>> a[1] = ma.masked
7324 >>> b = ma.arange(2, 5)
7325 >>> a
7326 masked_array(data=[0, --, 2],
7327 mask=[False, True, False],
7328 fill_value=999999)
7329 >>> b
7330 masked_array(data=[2, 3, 4],
7331 mask=False,
7332 fill_value=999999)
7333 >>> ma.concatenate([a, b])
7334 masked_array(data=[0, --, 2, 2, 3, 4],
7335 mask=[False, True, False, False, False, False],
7336 fill_value=999999)
7338 """
7339 d = np.concatenate([getdata(a) for a in arrays], axis)
7340 rcls = get_masked_subclass(*arrays)
7341 data = d.view(rcls)
7342 # Check whether one of the arrays has a non-empty mask.
7343 for x in arrays:
7344 if getmask(x) is not nomask:
7345 break
7346 else:
7347 return data
7348 # OK, so we have to concatenate the masks
7349 dm = np.concatenate([getmaskarray(a) for a in arrays], axis)
7350 dm = dm.reshape(d.shape)
7352 # If we decide to keep a '_shrinkmask' option, we want to check that
7353 # all of them are True, and then check for dm.any()
7354 data._mask = _shrink_mask(dm)
7355 return data
7358def diag(v, k=0):
7359 """
7360 Extract a diagonal or construct a diagonal array.
7362 This function is the equivalent of `numpy.diag` that takes masked
7363 values into account, see `numpy.diag` for details.
7365 See Also
7366 --------
7367 numpy.diag : Equivalent function for ndarrays.
7369 Examples
7370 --------
7371 >>> import numpy as np
7373 Create an array with negative values masked:
7375 >>> import numpy as np
7376 >>> x = np.array([[11.2, -3.973, 18], [0.801, -1.41, 12], [7, 33, -12]])
7377 >>> masked_x = np.ma.masked_array(x, mask=x < 0)
7378 >>> masked_x
7379 masked_array(
7380 data=[[11.2, --, 18.0],
7381 [0.801, --, 12.0],
7382 [7.0, 33.0, --]],
7383 mask=[[False, True, False],
7384 [False, True, False],
7385 [False, False, True]],
7386 fill_value=1e+20)
7388 Isolate the main diagonal from the masked array:
7390 >>> np.ma.diag(masked_x)
7391 masked_array(data=[11.2, --, --],
7392 mask=[False, True, True],
7393 fill_value=1e+20)
7395 Isolate the first diagonal below the main diagonal:
7397 >>> np.ma.diag(masked_x, -1)
7398 masked_array(data=[0.801, 33.0],
7399 mask=[False, False],
7400 fill_value=1e+20)
7402 """
7403 output = np.diag(v, k).view(MaskedArray)
7404 if getmask(v) is not nomask:
7405 output._mask = np.diag(v._mask, k)
7406 return output
7409def left_shift(a, n):
7410 """
7411 Shift the bits of an integer to the left.
7413 This is the masked array version of `numpy.left_shift`, for details
7414 see that function.
7416 See Also
7417 --------
7418 numpy.left_shift
7420 Examples
7421 --------
7422 Shift with a masked array:
7424 >>> arr = np.ma.array([10, 20, 30], mask=[False, True, False])
7425 >>> np.ma.left_shift(arr, 1)
7426 masked_array(data=[20, --, 60],
7427 mask=[False, True, False],
7428 fill_value=999999)
7430 Large shift:
7432 >>> np.ma.left_shift(10, 10)
7433 masked_array(data=10240,
7434 mask=False,
7435 fill_value=999999)
7437 Shift with a scalar and an array:
7439 >>> scalar = 10
7440 >>> arr = np.ma.array([1, 2, 3], mask=[False, True, False])
7441 >>> np.ma.left_shift(scalar, arr)
7442 masked_array(data=[20, --, 80],
7443 mask=[False, True, False],
7444 fill_value=999999)
7447 """
7448 m = getmask(a)
7449 if m is nomask:
7450 d = umath.left_shift(filled(a), n)
7451 return masked_array(d)
7452 else:
7453 d = umath.left_shift(filled(a, 0), n)
7454 return masked_array(d, mask=m)
7457def right_shift(a, n):
7458 """
7459 Shift the bits of an integer to the right.
7461 This is the masked array version of `numpy.right_shift`, for details
7462 see that function.
7464 See Also
7465 --------
7466 numpy.right_shift
7468 Examples
7469 --------
7470 >>> import numpy as np
7471 >>> import numpy.ma as ma
7472 >>> x = [11, 3, 8, 1]
7473 >>> mask = [0, 0, 0, 1]
7474 >>> masked_x = ma.masked_array(x, mask)
7475 >>> masked_x
7476 masked_array(data=[11, 3, 8, --],
7477 mask=[False, False, False, True],
7478 fill_value=999999)
7479 >>> ma.right_shift(masked_x,1)
7480 masked_array(data=[5, 1, 4, --],
7481 mask=[False, False, False, True],
7482 fill_value=999999)
7484 """
7485 m = getmask(a)
7486 if m is nomask:
7487 d = umath.right_shift(filled(a), n)
7488 return masked_array(d)
7489 else:
7490 d = umath.right_shift(filled(a, 0), n)
7491 return masked_array(d, mask=m)
7494def put(a, indices, values, mode='raise'):
7495 """
7496 Set storage-indexed locations to corresponding values.
7498 This function is equivalent to `MaskedArray.put`, see that method
7499 for details.
7501 See Also
7502 --------
7503 MaskedArray.put
7505 Examples
7506 --------
7507 Putting values in a masked array:
7509 >>> a = np.ma.array([1, 2, 3, 4], mask=[False, True, False, False])
7510 >>> np.ma.put(a, [1, 3], [10, 30])
7511 >>> a
7512 masked_array(data=[ 1, 10, 3, 30],
7513 mask=False,
7514 fill_value=999999)
7516 Using put with a 2D array:
7518 >>> b = np.ma.array([[1, 2], [3, 4]], mask=[[False, True], [False, False]])
7519 >>> np.ma.put(b, [[0, 1], [1, 0]], [[10, 20], [30, 40]])
7520 >>> b
7521 masked_array(
7522 data=[[40, 30],
7523 [ 3, 4]],
7524 mask=False,
7525 fill_value=999999)
7527 """
7528 # We can't use 'frommethod', the order of arguments is different
7529 try:
7530 return a.put(indices, values, mode=mode)
7531 except AttributeError:
7532 return np.asarray(a).put(indices, values, mode=mode)
7535def putmask(a, mask, values): # , mode='raise'):
7536 """
7537 Changes elements of an array based on conditional and input values.
7539 This is the masked array version of `numpy.putmask`, for details see
7540 `numpy.putmask`.
7542 See Also
7543 --------
7544 numpy.putmask
7546 Notes
7547 -----
7548 Using a masked array as `values` will **not** transform a `ndarray` into
7549 a `MaskedArray`.
7551 Examples
7552 --------
7553 >>> import numpy as np
7554 >>> arr = [[1, 2], [3, 4]]
7555 >>> mask = [[1, 0], [0, 0]]
7556 >>> x = np.ma.array(arr, mask=mask)
7557 >>> np.ma.putmask(x, x < 4, 10*x)
7558 >>> x
7559 masked_array(
7560 data=[[--, 20],
7561 [30, 4]],
7562 mask=[[ True, False],
7563 [False, False]],
7564 fill_value=999999)
7565 >>> x.data
7566 array([[10, 20],
7567 [30, 4]])
7569 """
7570 # We can't use 'frommethod', the order of arguments is different
7571 if not isinstance(a, MaskedArray):
7572 a = a.view(MaskedArray)
7573 (valdata, valmask) = (getdata(values), getmask(values))
7574 if getmask(a) is nomask:
7575 if valmask is not nomask:
7576 a._sharedmask = True
7577 a._mask = make_mask_none(a.shape, a.dtype)
7578 np.copyto(a._mask, valmask, where=mask)
7579 elif a._hardmask:
7580 if valmask is not nomask:
7581 m = a._mask.copy()
7582 np.copyto(m, valmask, where=mask)
7583 a.mask |= m
7584 else:
7585 if valmask is nomask:
7586 valmask = getmaskarray(values)
7587 np.copyto(a._mask, valmask, where=mask)
7588 np.copyto(a._data, valdata, where=mask)
7591def transpose(a, axes=None):
7592 """
7593 Permute the dimensions of an array.
7595 This function is exactly equivalent to `numpy.transpose`.
7597 See Also
7598 --------
7599 numpy.transpose : Equivalent function in top-level NumPy module.
7601 Examples
7602 --------
7603 >>> import numpy as np
7604 >>> import numpy.ma as ma
7605 >>> x = ma.arange(4).reshape((2,2))
7606 >>> x[1, 1] = ma.masked
7607 >>> x
7608 masked_array(
7609 data=[[0, 1],
7610 [2, --]],
7611 mask=[[False, False],
7612 [False, True]],
7613 fill_value=999999)
7615 >>> ma.transpose(x)
7616 masked_array(
7617 data=[[0, 2],
7618 [1, --]],
7619 mask=[[False, False],
7620 [False, True]],
7621 fill_value=999999)
7622 """
7623 # We can't use 'frommethod', as 'transpose' doesn't take keywords
7624 try:
7625 return a.transpose(axes)
7626 except AttributeError:
7627 return np.asarray(a).transpose(axes).view(MaskedArray)
7630def reshape(a, new_shape, order='C'):
7631 """
7632 Returns an array containing the same data with a new shape.
7634 Refer to `MaskedArray.reshape` for full documentation.
7636 See Also
7637 --------
7638 MaskedArray.reshape : equivalent function
7640 Examples
7641 --------
7642 Reshaping a 1-D array:
7644 >>> a = np.ma.array([1, 2, 3, 4])
7645 >>> np.ma.reshape(a, (2, 2))
7646 masked_array(
7647 data=[[1, 2],
7648 [3, 4]],
7649 mask=False,
7650 fill_value=999999)
7652 Reshaping a 2-D array:
7654 >>> b = np.ma.array([[1, 2], [3, 4]])
7655 >>> np.ma.reshape(b, (1, 4))
7656 masked_array(data=[[1, 2, 3, 4]],
7657 mask=False,
7658 fill_value=999999)
7660 Reshaping a 1-D array with a mask:
7662 >>> c = np.ma.array([1, 2, 3, 4], mask=[False, True, False, False])
7663 >>> np.ma.reshape(c, (2, 2))
7664 masked_array(
7665 data=[[1, --],
7666 [3, 4]],
7667 mask=[[False, True],
7668 [False, False]],
7669 fill_value=999999)
7671 """
7672 # We can't use 'frommethod', it whine about some parameters. Dmmit.
7673 try:
7674 return a.reshape(new_shape, order=order)
7675 except AttributeError:
7676 _tmp = np.asarray(a).reshape(new_shape, order=order)
7677 return _tmp.view(MaskedArray)
7680def resize(x, new_shape):
7681 """
7682 Return a new masked array with the specified size and shape.
7684 This is the masked equivalent of the `numpy.resize` function. The new
7685 array is filled with repeated copies of `x` (in the order that the
7686 data are stored in memory). If `x` is masked, the new array will be
7687 masked, and the new mask will be a repetition of the old one.
7689 See Also
7690 --------
7691 numpy.resize : Equivalent function in the top level NumPy module.
7693 Examples
7694 --------
7695 >>> import numpy as np
7696 >>> import numpy.ma as ma
7697 >>> a = ma.array([[1, 2] ,[3, 4]])
7698 >>> a[0, 1] = ma.masked
7699 >>> a
7700 masked_array(
7701 data=[[1, --],
7702 [3, 4]],
7703 mask=[[False, True],
7704 [False, False]],
7705 fill_value=999999)
7706 >>> np.resize(a, (3, 3))
7707 masked_array(
7708 data=[[1, 2, 3],
7709 [4, 1, 2],
7710 [3, 4, 1]],
7711 mask=False,
7712 fill_value=999999)
7713 >>> ma.resize(a, (3, 3))
7714 masked_array(
7715 data=[[1, --, 3],
7716 [4, 1, --],
7717 [3, 4, 1]],
7718 mask=[[False, True, False],
7719 [False, False, True],
7720 [False, False, False]],
7721 fill_value=999999)
7723 A MaskedArray is always returned, regardless of the input type.
7725 >>> a = np.array([[1, 2] ,[3, 4]])
7726 >>> ma.resize(a, (3, 3))
7727 masked_array(
7728 data=[[1, 2, 3],
7729 [4, 1, 2],
7730 [3, 4, 1]],
7731 mask=False,
7732 fill_value=999999)
7734 """
7735 # We can't use _frommethods here, as N.resize is notoriously whiny.
7736 m = getmask(x)
7737 if m is not nomask:
7738 m = np.resize(m, new_shape)
7739 result = np.resize(x, new_shape).view(get_masked_subclass(x))
7740 if result.ndim:
7741 result._mask = m
7742 return result
7745def ndim(obj):
7746 """
7747 maskedarray version of the numpy function.
7749 """
7750 return np.ndim(getdata(obj))
7753ndim.__doc__ = np.ndim.__doc__
7756def shape(obj):
7757 "maskedarray version of the numpy function."
7758 return np.shape(getdata(obj))
7761shape.__doc__ = np.shape.__doc__
7764def size(obj, axis=None):
7765 "maskedarray version of the numpy function."
7766 return np.size(getdata(obj), axis)
7769size.__doc__ = np.size.__doc__
7772def diff(a, /, n=1, axis=-1, prepend=np._NoValue, append=np._NoValue):
7773 """
7774 Calculate the n-th discrete difference along the given axis.
7775 The first difference is given by ``out[i] = a[i+1] - a[i]`` along
7776 the given axis, higher differences are calculated by using `diff`
7777 recursively.
7778 Preserves the input mask.
7780 Parameters
7781 ----------
7782 a : array_like
7783 Input array
7784 n : int, optional
7785 The number of times values are differenced. If zero, the input
7786 is returned as-is.
7787 axis : int, optional
7788 The axis along which the difference is taken, default is the
7789 last axis.
7790 prepend, append : array_like, optional
7791 Values to prepend or append to `a` along axis prior to
7792 performing the difference. Scalar values are expanded to
7793 arrays with length 1 in the direction of axis and the shape
7794 of the input array in along all other axes. Otherwise the
7795 dimension and shape must match `a` except along axis.
7797 Returns
7798 -------
7799 diff : MaskedArray
7800 The n-th differences. The shape of the output is the same as `a`
7801 except along `axis` where the dimension is smaller by `n`. The
7802 type of the output is the same as the type of the difference
7803 between any two elements of `a`. This is the same as the type of
7804 `a` in most cases. A notable exception is `datetime64`, which
7805 results in a `timedelta64` output array.
7807 See Also
7808 --------
7809 numpy.diff : Equivalent function in the top-level NumPy module.
7811 Notes
7812 -----
7813 Type is preserved for boolean arrays, so the result will contain
7814 `False` when consecutive elements are the same and `True` when they
7815 differ.
7817 For unsigned integer arrays, the results will also be unsigned. This
7818 should not be surprising, as the result is consistent with
7819 calculating the difference directly:
7821 >>> u8_arr = np.array([1, 0], dtype=np.uint8)
7822 >>> np.ma.diff(u8_arr)
7823 masked_array(data=[255],
7824 mask=False,
7825 fill_value=np.uint64(999999),
7826 dtype=uint8)
7827 >>> u8_arr[1,...] - u8_arr[0,...]
7828 np.uint8(255)
7830 If this is not desirable, then the array should be cast to a larger
7831 integer type first:
7833 >>> i16_arr = u8_arr.astype(np.int16)
7834 >>> np.ma.diff(i16_arr)
7835 masked_array(data=[-1],
7836 mask=False,
7837 fill_value=np.int64(999999),
7838 dtype=int16)
7840 Examples
7841 --------
7842 >>> import numpy as np
7843 >>> a = np.array([1, 2, 3, 4, 7, 0, 2, 3])
7844 >>> x = np.ma.masked_where(a < 2, a)
7845 >>> np.ma.diff(x)
7846 masked_array(data=[--, 1, 1, 3, --, --, 1],
7847 mask=[ True, False, False, False, True, True, False],
7848 fill_value=999999)
7850 >>> np.ma.diff(x, n=2)
7851 masked_array(data=[--, 0, 2, --, --, --],
7852 mask=[ True, False, False, True, True, True],
7853 fill_value=999999)
7855 >>> a = np.array([[1, 3, 1, 5, 10], [0, 1, 5, 6, 8]])
7856 >>> x = np.ma.masked_equal(a, value=1)
7857 >>> np.ma.diff(x)
7858 masked_array(
7859 data=[[--, --, --, 5],
7860 [--, --, 1, 2]],
7861 mask=[[ True, True, True, False],
7862 [ True, True, False, False]],
7863 fill_value=1)
7865 >>> np.ma.diff(x, axis=0)
7866 masked_array(data=[[--, --, --, 1, -2]],
7867 mask=[[ True, True, True, False, False]],
7868 fill_value=1)
7870 """
7871 if n == 0:
7872 return a
7873 if n < 0:
7874 raise ValueError("order must be non-negative but got " + repr(n))
7876 a = np.ma.asanyarray(a)
7877 if a.ndim == 0:
7878 raise ValueError(
7879 "diff requires input that is at least one dimensional"
7880 )
7882 combined = []
7883 if prepend is not np._NoValue:
7884 prepend = np.ma.asanyarray(prepend)
7885 if prepend.ndim == 0:
7886 shape = list(a.shape)
7887 shape[axis] = 1
7888 prepend = np.broadcast_to(prepend, tuple(shape))
7889 combined.append(prepend)
7891 combined.append(a)
7893 if append is not np._NoValue:
7894 append = np.ma.asanyarray(append)
7895 if append.ndim == 0:
7896 shape = list(a.shape)
7897 shape[axis] = 1
7898 append = np.broadcast_to(append, tuple(shape))
7899 combined.append(append)
7901 if len(combined) > 1:
7902 a = np.ma.concatenate(combined, axis)
7904 # GH 22465 np.diff without prepend/append preserves the mask
7905 return np.diff(a, n, axis)
7908##############################################################################
7909# Extra functions #
7910##############################################################################
7913def where(condition, x=_NoValue, y=_NoValue):
7914 """
7915 Return a masked array with elements from `x` or `y`, depending on condition.
7917 .. note::
7918 When only `condition` is provided, this function is identical to
7919 `nonzero`. The rest of this documentation covers only the case where
7920 all three arguments are provided.
7922 Parameters
7923 ----------
7924 condition : array_like, bool
7925 Where True, yield `x`, otherwise yield `y`.
7926 x, y : array_like, optional
7927 Values from which to choose. `x`, `y` and `condition` need to be
7928 broadcastable to some shape.
7930 Returns
7931 -------
7932 out : MaskedArray
7933 An masked array with `masked` elements where the condition is masked,
7934 elements from `x` where `condition` is True, and elements from `y`
7935 elsewhere.
7937 See Also
7938 --------
7939 numpy.where : Equivalent function in the top-level NumPy module.
7940 nonzero : The function that is called when x and y are omitted
7942 Examples
7943 --------
7944 >>> import numpy as np
7945 >>> x = np.ma.array(np.arange(9.).reshape(3, 3), mask=[[0, 1, 0],
7946 ... [1, 0, 1],
7947 ... [0, 1, 0]])
7948 >>> x
7949 masked_array(
7950 data=[[0.0, --, 2.0],
7951 [--, 4.0, --],
7952 [6.0, --, 8.0]],
7953 mask=[[False, True, False],
7954 [ True, False, True],
7955 [False, True, False]],
7956 fill_value=1e+20)
7957 >>> np.ma.where(x > 5, x, -3.1416)
7958 masked_array(
7959 data=[[-3.1416, --, -3.1416],
7960 [--, -3.1416, --],
7961 [6.0, --, 8.0]],
7962 mask=[[False, True, False],
7963 [ True, False, True],
7964 [False, True, False]],
7965 fill_value=1e+20)
7967 """
7969 # handle the single-argument case
7970 missing = (x is _NoValue, y is _NoValue).count(True)
7971 if missing == 1:
7972 raise ValueError("Must provide both 'x' and 'y' or neither.")
7973 if missing == 2:
7974 return nonzero(condition)
7976 # we only care if the condition is true - false or masked pick y
7977 cf = filled(condition, False)
7978 xd = getdata(x)
7979 yd = getdata(y)
7981 # we need the full arrays here for correct final dimensions
7982 cm = getmaskarray(condition)
7983 xm = getmaskarray(x)
7984 ym = getmaskarray(y)
7986 # deal with the fact that masked.dtype == float64, but we don't actually
7987 # want to treat it as that.
7988 if x is masked and y is not masked:
7989 xd = np.zeros((), dtype=yd.dtype)
7990 xm = np.ones((), dtype=ym.dtype)
7991 elif y is masked and x is not masked:
7992 yd = np.zeros((), dtype=xd.dtype)
7993 ym = np.ones((), dtype=xm.dtype)
7995 data = np.where(cf, xd, yd)
7996 mask = np.where(cf, xm, ym)
7997 mask = np.where(cm, np.ones((), dtype=mask.dtype), mask)
7999 # collapse the mask, for backwards compatibility
8000 mask = _shrink_mask(mask)
8002 return masked_array(data, mask=mask)
8005def choose(indices, choices, out=None, mode='raise'):
8006 """
8007 Use an index array to construct a new array from a list of choices.
8009 Given an array of integers and a list of n choice arrays, this method
8010 will create a new array that merges each of the choice arrays. Where a
8011 value in `index` is i, the new array will have the value that choices[i]
8012 contains in the same place.
8014 Parameters
8015 ----------
8016 indices : ndarray of ints
8017 This array must contain integers in ``[0, n-1]``, where n is the
8018 number of choices.
8019 choices : sequence of arrays
8020 Choice arrays. The index array and all of the choices should be
8021 broadcastable to the same shape.
8022 out : array, optional
8023 If provided, the result will be inserted into this array. It should
8024 be of the appropriate shape and `dtype`.
8025 mode : {'raise', 'wrap', 'clip'}, optional
8026 Specifies how out-of-bounds indices will behave.
8028 * 'raise' : raise an error
8029 * 'wrap' : wrap around
8030 * 'clip' : clip to the range
8032 Returns
8033 -------
8034 merged_array : array
8036 See Also
8037 --------
8038 choose : equivalent function
8040 Examples
8041 --------
8042 >>> import numpy as np
8043 >>> choice = np.array([[1,1,1], [2,2,2], [3,3,3]])
8044 >>> a = np.array([2, 1, 0])
8045 >>> np.ma.choose(a, choice)
8046 masked_array(data=[3, 2, 1],
8047 mask=False,
8048 fill_value=999999)
8050 """
8051 def fmask(x):
8052 "Returns the filled array, or True if masked."
8053 if x is masked:
8054 return True
8055 return filled(x)
8057 def nmask(x):
8058 "Returns the mask, True if ``masked``, False if ``nomask``."
8059 if x is masked:
8060 return True
8061 return getmask(x)
8062 # Get the indices.
8063 c = filled(indices, 0)
8064 # Get the masks.
8065 masks = [nmask(x) for x in choices]
8066 data = [fmask(x) for x in choices]
8067 # Construct the mask
8068 outputmask = np.choose(c, masks, mode=mode)
8069 outputmask = make_mask(mask_or(outputmask, getmask(indices)),
8070 copy=False, shrink=True)
8071 # Get the choices.
8072 d = np.choose(c, data, mode=mode, out=out).view(MaskedArray)
8073 if out is not None:
8074 if isinstance(out, MaskedArray):
8075 out.__setmask__(outputmask)
8076 return out
8077 d.__setmask__(outputmask)
8078 return d
8081def round_(a, decimals=0, out=None):
8082 """
8083 Return a copy of a, rounded to 'decimals' places.
8085 When 'decimals' is negative, it specifies the number of positions
8086 to the left of the decimal point. The real and imaginary parts of
8087 complex numbers are rounded separately. Nothing is done if the
8088 array is not of float type and 'decimals' is greater than or equal
8089 to 0.
8091 Parameters
8092 ----------
8093 decimals : int
8094 Number of decimals to round to. May be negative.
8095 out : array_like
8096 Existing array to use for output.
8097 If not given, returns a default copy of a.
8099 Notes
8100 -----
8101 If out is given and does not have a mask attribute, the mask of a
8102 is lost!
8104 Examples
8105 --------
8106 >>> import numpy as np
8107 >>> import numpy.ma as ma
8108 >>> x = [11.2, -3.973, 0.801, -1.41]
8109 >>> mask = [0, 0, 0, 1]
8110 >>> masked_x = ma.masked_array(x, mask)
8111 >>> masked_x
8112 masked_array(data=[11.2, -3.973, 0.801, --],
8113 mask=[False, False, False, True],
8114 fill_value=1e+20)
8115 >>> ma.round_(masked_x)
8116 masked_array(data=[11.0, -4.0, 1.0, --],
8117 mask=[False, False, False, True],
8118 fill_value=1e+20)
8119 >>> ma.round(masked_x, decimals=1)
8120 masked_array(data=[11.2, -4.0, 0.8, --],
8121 mask=[False, False, False, True],
8122 fill_value=1e+20)
8123 >>> ma.round_(masked_x, decimals=-1)
8124 masked_array(data=[10.0, -0.0, 0.0, --],
8125 mask=[False, False, False, True],
8126 fill_value=1e+20)
8127 """
8128 if out is None:
8129 return np.round(a, decimals, out)
8130 else:
8131 np.round(getdata(a), decimals, out)
8132 if hasattr(out, '_mask'):
8133 out._mask = getmask(a)
8134 return out
8137round = round_
8140def _mask_propagate(a, axis):
8141 """
8142 Mask whole 1-d vectors of an array that contain masked values.
8143 """
8144 a = array(a, subok=False)
8145 m = getmask(a)
8146 if m is nomask or not m.any() or axis is None:
8147 return a
8148 a._mask = a._mask.copy()
8149 axes = normalize_axis_tuple(axis, a.ndim)
8150 for ax in axes:
8151 a._mask |= m.any(axis=ax, keepdims=True)
8152 return a
8155# Include masked dot here to avoid import problems in getting it from
8156# extras.py. Note that it is not included in __all__, but rather exported
8157# from extras in order to avoid backward compatibility problems.
8158def dot(a, b, strict=False, out=None):
8159 """
8160 Return the dot product of two arrays.
8162 This function is the equivalent of `numpy.dot` that takes masked values
8163 into account. Note that `strict` and `out` are in different position
8164 than in the method version. In order to maintain compatibility with the
8165 corresponding method, it is recommended that the optional arguments be
8166 treated as keyword only. At some point that may be mandatory.
8168 Parameters
8169 ----------
8170 a, b : masked_array_like
8171 Inputs arrays.
8172 strict : bool, optional
8173 Whether masked data are propagated (True) or set to 0 (False) for
8174 the computation. Default is False. Propagating the mask means that
8175 if a masked value appears in a row or column, the whole row or
8176 column is considered masked.
8177 out : masked_array, optional
8178 Output argument. This must have the exact kind that would be returned
8179 if it was not used. In particular, it must have the right type, must be
8180 C-contiguous, and its dtype must be the dtype that would be returned
8181 for `dot(a,b)`. This is a performance feature. Therefore, if these
8182 conditions are not met, an exception is raised, instead of attempting
8183 to be flexible.
8185 See Also
8186 --------
8187 numpy.dot : Equivalent function for ndarrays.
8189 Examples
8190 --------
8191 >>> import numpy as np
8192 >>> a = np.ma.array([[1, 2, 3], [4, 5, 6]], mask=[[1, 0, 0], [0, 0, 0]])
8193 >>> b = np.ma.array([[1, 2], [3, 4], [5, 6]], mask=[[1, 0], [0, 0], [0, 0]])
8194 >>> np.ma.dot(a, b)
8195 masked_array(
8196 data=[[21, 26],
8197 [45, 64]],
8198 mask=[[False, False],
8199 [False, False]],
8200 fill_value=999999)
8201 >>> np.ma.dot(a, b, strict=True)
8202 masked_array(
8203 data=[[--, --],
8204 [--, 64]],
8205 mask=[[ True, True],
8206 [ True, False]],
8207 fill_value=999999)
8209 """
8210 if strict is True:
8211 if np.ndim(a) == 0 or np.ndim(b) == 0:
8212 pass
8213 elif b.ndim == 1:
8214 a = _mask_propagate(a, a.ndim - 1)
8215 b = _mask_propagate(b, b.ndim - 1)
8216 else:
8217 a = _mask_propagate(a, a.ndim - 1)
8218 b = _mask_propagate(b, b.ndim - 2)
8219 am = ~getmaskarray(a)
8220 bm = ~getmaskarray(b)
8222 if out is None:
8223 d = np.dot(filled(a, 0), filled(b, 0))
8224 m = ~np.dot(am, bm)
8225 if np.ndim(d) == 0:
8226 d = np.asarray(d)
8227 r = d.view(get_masked_subclass(a, b))
8228 r.__setmask__(m)
8229 return r
8230 else:
8231 d = np.dot(filled(a, 0), filled(b, 0), out._data)
8232 if out.mask.shape != d.shape:
8233 out._mask = np.empty(d.shape, MaskType)
8234 np.dot(am, bm, out._mask)
8235 np.logical_not(out._mask, out._mask)
8236 return out
8239def inner(a, b):
8240 """
8241 Returns the inner product of a and b for arrays of floating point types.
8243 Like the generic NumPy equivalent the product sum is over the last dimension
8244 of a and b. The first argument is not conjugated.
8246 """
8247 fa = filled(a, 0)
8248 fb = filled(b, 0)
8249 if fa.ndim == 0:
8250 fa.shape = (1,)
8251 if fb.ndim == 0:
8252 fb.shape = (1,)
8253 return np.inner(fa, fb).view(MaskedArray)
8256inner.__doc__ = doc_note(np.inner.__doc__,
8257 "Masked values are replaced by 0.")
8258innerproduct = inner
8261def outer(a, b):
8262 "maskedarray version of the numpy function."
8263 fa = filled(a, 0).ravel()
8264 fb = filled(b, 0).ravel()
8265 d = np.outer(fa, fb)
8266 ma = getmask(a)
8267 mb = getmask(b)
8268 if ma is nomask and mb is nomask:
8269 return masked_array(d)
8270 ma = getmaskarray(a)
8271 mb = getmaskarray(b)
8272 m = make_mask(1 - np.outer(1 - ma, 1 - mb), copy=False)
8273 return masked_array(d, mask=m)
8276outer.__doc__ = doc_note(np.outer.__doc__,
8277 "Masked values are replaced by 0.")
8278outerproduct = outer
8281def _convolve_or_correlate(f, a, v, mode, propagate_mask):
8282 """
8283 Helper function for ma.correlate and ma.convolve
8284 """
8285 if propagate_mask:
8286 # results which are contributed to by either item in any pair being invalid
8287 mask = (
8288 f(getmaskarray(a), np.ones(np.shape(v), dtype=bool), mode=mode)
8289 | f(np.ones(np.shape(a), dtype=bool), getmaskarray(v), mode=mode)
8290 )
8291 data = f(getdata(a), getdata(v), mode=mode)
8292 else:
8293 # results which are not contributed to by any pair of valid elements
8294 mask = ~f(~getmaskarray(a), ~getmaskarray(v), mode=mode)
8295 data = f(filled(a, 0), filled(v, 0), mode=mode)
8297 return masked_array(data, mask=mask)
8300def correlate(a, v, mode='valid', propagate_mask=True):
8301 """
8302 Cross-correlation of two 1-dimensional sequences.
8304 Parameters
8305 ----------
8306 a, v : array_like
8307 Input sequences.
8308 mode : {'valid', 'same', 'full'}, optional
8309 Refer to the `np.convolve` docstring. Note that the default
8310 is 'valid', unlike `convolve`, which uses 'full'.
8311 propagate_mask : bool
8312 If True, then a result element is masked if any masked element contributes
8313 towards it. If False, then a result element is only masked if no non-masked
8314 element contribute towards it
8316 Returns
8317 -------
8318 out : MaskedArray
8319 Discrete cross-correlation of `a` and `v`.
8321 See Also
8322 --------
8323 numpy.correlate : Equivalent function in the top-level NumPy module.
8325 Examples
8326 --------
8327 Basic correlation:
8329 >>> a = np.ma.array([1, 2, 3])
8330 >>> v = np.ma.array([0, 1, 0])
8331 >>> np.ma.correlate(a, v, mode='valid')
8332 masked_array(data=[2],
8333 mask=[False],
8334 fill_value=999999)
8336 Correlation with masked elements:
8338 >>> a = np.ma.array([1, 2, 3], mask=[False, True, False])
8339 >>> v = np.ma.array([0, 1, 0])
8340 >>> np.ma.correlate(a, v, mode='valid', propagate_mask=True)
8341 masked_array(data=[--],
8342 mask=[ True],
8343 fill_value=999999,
8344 dtype=int64)
8346 Correlation with different modes and mixed array types:
8348 >>> a = np.ma.array([1, 2, 3])
8349 >>> v = np.ma.array([0, 1, 0])
8350 >>> np.ma.correlate(a, v, mode='full')
8351 masked_array(data=[0, 1, 2, 3, 0],
8352 mask=[False, False, False, False, False],
8353 fill_value=999999)
8355 """
8356 return _convolve_or_correlate(np.correlate, a, v, mode, propagate_mask)
8359def convolve(a, v, mode='full', propagate_mask=True):
8360 """
8361 Returns the discrete, linear convolution of two one-dimensional sequences.
8363 Parameters
8364 ----------
8365 a, v : array_like
8366 Input sequences.
8367 mode : {'valid', 'same', 'full'}, optional
8368 Refer to the `np.convolve` docstring.
8369 propagate_mask : bool
8370 If True, then if any masked element is included in the sum for a result
8371 element, then the result is masked.
8372 If False, then the result element is only masked if no non-masked cells
8373 contribute towards it
8375 Returns
8376 -------
8377 out : MaskedArray
8378 Discrete, linear convolution of `a` and `v`.
8380 See Also
8381 --------
8382 numpy.convolve : Equivalent function in the top-level NumPy module.
8383 """
8384 return _convolve_or_correlate(np.convolve, a, v, mode, propagate_mask)
8387def allequal(a, b, fill_value=True):
8388 """
8389 Return True if all entries of a and b are equal, using
8390 fill_value as a truth value where either or both are masked.
8392 Parameters
8393 ----------
8394 a, b : array_like
8395 Input arrays to compare.
8396 fill_value : bool, optional
8397 Whether masked values in a or b are considered equal (True) or not
8398 (False).
8400 Returns
8401 -------
8402 y : bool
8403 Returns True if the two arrays are equal within the given
8404 tolerance, False otherwise. If either array contains NaN,
8405 then False is returned.
8407 See Also
8408 --------
8409 all, any
8410 numpy.ma.allclose
8412 Examples
8413 --------
8414 >>> import numpy as np
8415 >>> a = np.ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1])
8416 >>> a
8417 masked_array(data=[10000000000.0, 1e-07, --],
8418 mask=[False, False, True],
8419 fill_value=1e+20)
8421 >>> b = np.array([1e10, 1e-7, -42.0])
8422 >>> b
8423 array([ 1.00000000e+10, 1.00000000e-07, -4.20000000e+01])
8424 >>> np.ma.allequal(a, b, fill_value=False)
8425 False
8426 >>> np.ma.allequal(a, b)
8427 True
8429 """
8430 m = mask_or(getmask(a), getmask(b))
8431 if m is nomask:
8432 x = getdata(a)
8433 y = getdata(b)
8434 d = umath.equal(x, y)
8435 return d.all()
8436 elif fill_value:
8437 x = getdata(a)
8438 y = getdata(b)
8439 d = umath.equal(x, y)
8440 dm = array(d, mask=m, copy=False)
8441 return dm.filled(True).all(None)
8442 else:
8443 return False
8446def allclose(a, b, masked_equal=True, rtol=1e-5, atol=1e-8):
8447 """
8448 Returns True if two arrays are element-wise equal within a tolerance.
8450 This function is equivalent to `allclose` except that masked values
8451 are treated as equal (default) or unequal, depending on the `masked_equal`
8452 argument.
8454 Parameters
8455 ----------
8456 a, b : array_like
8457 Input arrays to compare.
8458 masked_equal : bool, optional
8459 Whether masked values in `a` and `b` are considered equal (True) or not
8460 (False). They are considered equal by default.
8461 rtol : float, optional
8462 Relative tolerance. The relative difference is equal to ``rtol * b``.
8463 Default is 1e-5.
8464 atol : float, optional
8465 Absolute tolerance. The absolute difference is equal to `atol`.
8466 Default is 1e-8.
8468 Returns
8469 -------
8470 y : bool
8471 Returns True if the two arrays are equal within the given
8472 tolerance, False otherwise. If either array contains NaN, then
8473 False is returned.
8475 See Also
8476 --------
8477 all, any
8478 numpy.allclose : the non-masked `allclose`.
8480 Notes
8481 -----
8482 If the following equation is element-wise True, then `allclose` returns
8483 True::
8485 absolute(`a` - `b`) <= (`atol` + `rtol` * absolute(`b`))
8487 Return True if all elements of `a` and `b` are equal subject to
8488 given tolerances.
8490 Examples
8491 --------
8492 >>> import numpy as np
8493 >>> a = np.ma.array([1e10, 1e-7, 42.0], mask=[0, 0, 1])
8494 >>> a
8495 masked_array(data=[10000000000.0, 1e-07, --],
8496 mask=[False, False, True],
8497 fill_value=1e+20)
8498 >>> b = np.ma.array([1e10, 1e-8, -42.0], mask=[0, 0, 1])
8499 >>> np.ma.allclose(a, b)
8500 False
8502 >>> a = np.ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1])
8503 >>> b = np.ma.array([1.00001e10, 1e-9, -42.0], mask=[0, 0, 1])
8504 >>> np.ma.allclose(a, b)
8505 True
8506 >>> np.ma.allclose(a, b, masked_equal=False)
8507 False
8509 Masked values are not compared directly.
8511 >>> a = np.ma.array([1e10, 1e-8, 42.0], mask=[0, 0, 1])
8512 >>> b = np.ma.array([1.00001e10, 1e-9, 42.0], mask=[0, 0, 1])
8513 >>> np.ma.allclose(a, b)
8514 True
8515 >>> np.ma.allclose(a, b, masked_equal=False)
8516 False
8518 """
8519 x = masked_array(a, copy=False)
8520 y = masked_array(b, copy=False)
8522 # make sure y is an inexact type to avoid abs(MIN_INT); will cause
8523 # casting of x later.
8524 # NOTE: We explicitly allow timedelta, which used to work. This could
8525 # possibly be deprecated. See also gh-18286.
8526 # timedelta works if `atol` is an integer or also a timedelta.
8527 # Although, the default tolerances are unlikely to be useful
8528 if y.dtype.kind != "m":
8529 dtype = np.result_type(y, 1.)
8530 if y.dtype != dtype:
8531 y = masked_array(y, dtype=dtype, copy=False)
8533 m = mask_or(getmask(x), getmask(y))
8534 xinf = np.isinf(masked_array(x, copy=False, mask=m)).filled(False)
8535 # If we have some infs, they should fall at the same place.
8536 if not np.all(xinf == filled(np.isinf(y), False)):
8537 return False
8538 # No infs at all
8539 if not np.any(xinf):
8540 d = filled(less_equal(absolute(x - y), atol + rtol * absolute(y)),
8541 masked_equal)
8542 return np.all(d)
8544 if not np.all(filled(x[xinf] == y[xinf], masked_equal)):
8545 return False
8546 x = x[~xinf]
8547 y = y[~xinf]
8549 d = filled(less_equal(absolute(x - y), atol + rtol * absolute(y)),
8550 masked_equal)
8552 return np.all(d)
8555def asarray(a, dtype=None, order=None):
8556 """
8557 Convert the input to a masked array of the given data-type.
8559 No copy is performed if the input is already an `ndarray`. If `a` is
8560 a subclass of `MaskedArray`, a base class `MaskedArray` is returned.
8562 Parameters
8563 ----------
8564 a : array_like
8565 Input data, in any form that can be converted to a masked array. This
8566 includes lists, lists of tuples, tuples, tuples of tuples, tuples
8567 of lists, ndarrays and masked arrays.
8568 dtype : dtype, optional
8569 By default, the data-type is inferred from the input data.
8570 order : {'C', 'F'}, optional
8571 Whether to use row-major ('C') or column-major ('FORTRAN') memory
8572 representation. Default is 'C'.
8574 Returns
8575 -------
8576 out : MaskedArray
8577 Masked array interpretation of `a`.
8579 See Also
8580 --------
8581 asanyarray : Similar to `asarray`, but conserves subclasses.
8583 Examples
8584 --------
8585 >>> import numpy as np
8586 >>> x = np.arange(10.).reshape(2, 5)
8587 >>> x
8588 array([[0., 1., 2., 3., 4.],
8589 [5., 6., 7., 8., 9.]])
8590 >>> np.ma.asarray(x)
8591 masked_array(
8592 data=[[0., 1., 2., 3., 4.],
8593 [5., 6., 7., 8., 9.]],
8594 mask=False,
8595 fill_value=1e+20)
8596 >>> type(np.ma.asarray(x))
8597 <class 'numpy.ma.MaskedArray'>
8599 """
8600 order = order or 'C'
8601 return masked_array(a, dtype=dtype, copy=False, keep_mask=True,
8602 subok=False, order=order)
8605def asanyarray(a, dtype=None, order=None):
8606 """
8607 Convert the input to a masked array, conserving subclasses.
8609 If `a` is a subclass of `MaskedArray`, its class is conserved.
8610 No copy is performed if the input is already an `ndarray`.
8612 Parameters
8613 ----------
8614 a : array_like
8615 Input data, in any form that can be converted to an array.
8616 dtype : dtype, optional
8617 By default, the data-type is inferred from the input data.
8618 order : {'C', 'F', 'A', 'K'}, optional
8619 Memory layout. 'A' and 'K' depend on the order of input array ``a``.
8620 'C' row-major (C-style),
8621 'F' column-major (Fortran-style) memory representation.
8622 'A' (any) means 'F' if ``a`` is Fortran contiguous, 'C' otherwise
8623 'K' (keep) preserve input order
8624 Defaults to 'K'.
8626 Returns
8627 -------
8628 out : MaskedArray
8629 MaskedArray interpretation of `a`.
8631 See Also
8632 --------
8633 asarray : Similar to `asanyarray`, but does not conserve subclass.
8635 Examples
8636 --------
8637 >>> import numpy as np
8638 >>> x = np.arange(10.).reshape(2, 5)
8639 >>> x
8640 array([[0., 1., 2., 3., 4.],
8641 [5., 6., 7., 8., 9.]])
8642 >>> np.ma.asanyarray(x)
8643 masked_array(
8644 data=[[0., 1., 2., 3., 4.],
8645 [5., 6., 7., 8., 9.]],
8646 mask=False,
8647 fill_value=1e+20)
8648 >>> type(np.ma.asanyarray(x))
8649 <class 'numpy.ma.MaskedArray'>
8651 """
8652 # workaround for #8666, to preserve identity. Ideally the bottom line
8653 # would handle this for us.
8654 if (
8655 isinstance(a, MaskedArray)
8656 and (dtype is None or dtype == a.dtype)
8657 and (
8658 order in {None, 'A', 'K'}
8659 or order == 'C' and a.flags.carray
8660 or order == 'F' and a.flags.f_contiguous
8661 )
8662 ):
8663 return a
8664 return masked_array(a, dtype=dtype, copy=False, keep_mask=True, subok=True,
8665 order=order)
8668##############################################################################
8669# Pickling #
8670##############################################################################
8673def fromfile(file, dtype=float, count=-1, sep=''):
8674 raise NotImplementedError(
8675 "fromfile() not yet implemented for a MaskedArray.")
8678def fromflex(fxarray):
8679 """
8680 Build a masked array from a suitable flexible-type array.
8682 The input array has to have a data-type with ``_data`` and ``_mask``
8683 fields. This type of array is output by `MaskedArray.toflex`.
8685 Parameters
8686 ----------
8687 fxarray : ndarray
8688 The structured input array, containing ``_data`` and ``_mask``
8689 fields. If present, other fields are discarded.
8691 Returns
8692 -------
8693 result : MaskedArray
8694 The constructed masked array.
8696 See Also
8697 --------
8698 MaskedArray.toflex : Build a flexible-type array from a masked array.
8700 Examples
8701 --------
8702 >>> import numpy as np
8703 >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[0] + [1, 0] * 4)
8704 >>> rec = x.toflex()
8705 >>> rec
8706 array([[(0, False), (1, True), (2, False)],
8707 [(3, True), (4, False), (5, True)],
8708 [(6, False), (7, True), (8, False)]],
8709 dtype=[('_data', '<i8'), ('_mask', '?')])
8710 >>> x2 = np.ma.fromflex(rec)
8711 >>> x2
8712 masked_array(
8713 data=[[0, --, 2],
8714 [--, 4, --],
8715 [6, --, 8]],
8716 mask=[[False, True, False],
8717 [ True, False, True],
8718 [False, True, False]],
8719 fill_value=999999)
8721 Extra fields can be present in the structured array but are discarded:
8723 >>> dt = [('_data', '<i4'), ('_mask', '|b1'), ('field3', '<f4')]
8724 >>> rec2 = np.zeros((2, 2), dtype=dt)
8725 >>> rec2
8726 array([[(0, False, 0.), (0, False, 0.)],
8727 [(0, False, 0.), (0, False, 0.)]],
8728 dtype=[('_data', '<i4'), ('_mask', '?'), ('field3', '<f4')])
8729 >>> y = np.ma.fromflex(rec2)
8730 >>> y
8731 masked_array(
8732 data=[[0, 0],
8733 [0, 0]],
8734 mask=[[False, False],
8735 [False, False]],
8736 fill_value=np.int64(999999),
8737 dtype=int32)
8739 """
8740 return masked_array(fxarray['_data'], mask=fxarray['_mask'])
8743def _convert2ma(funcname: str, np_ret: str, np_ma_ret: str,
8744 params: dict[str, str] | None = None):
8745 """Convert function from numpy to numpy.ma."""
8746 func = getattr(np, funcname)
8747 params = params or {}
8749 @functools.wraps(func, assigned=set(functools.WRAPPER_ASSIGNMENTS) - {"__module__"})
8750 def wrapper(*args, **kwargs):
8751 common_params = kwargs.keys() & params.keys()
8752 extras = params | {p: kwargs.pop(p) for p in common_params}
8754 result = func.__call__(*args, **kwargs).view(MaskedArray)
8756 if "fill_value" in common_params:
8757 result.fill_value = extras["fill_value"]
8758 if "hardmask" in common_params:
8759 result._hardmask = bool(extras["hardmask"])
8761 return result
8763 # workaround for a doctest bug in Python 3.11 that incorrectly assumes `__code__`
8764 # exists on wrapped functions
8765 del wrapper.__wrapped__
8767 # `arange`, `empty`, `empty_like`, `frombuffer`, and `zeros` have no signature
8768 try:
8769 signature = inspect.signature(func)
8770 except ValueError:
8771 signature = inspect.Signature([
8772 inspect.Parameter('args', inspect.Parameter.VAR_POSITIONAL),
8773 inspect.Parameter('kwargs', inspect.Parameter.VAR_KEYWORD),
8774 ])
8776 if params:
8777 sig_params = list(signature.parameters.values())
8779 # pop `**kwargs` if present
8780 sig_kwargs = None
8781 if sig_params[-1].kind is inspect.Parameter.VAR_KEYWORD:
8782 sig_kwargs = sig_params.pop()
8784 # add new keyword-only parameters
8785 for param_name, default in params.items():
8786 new_param = inspect.Parameter(
8787 param_name,
8788 inspect.Parameter.KEYWORD_ONLY,
8789 default=default,
8790 )
8791 sig_params.append(new_param)
8793 # re-append `**kwargs` if it was present
8794 if sig_kwargs:
8795 sig_params.append(sig_kwargs)
8797 signature = signature.replace(parameters=sig_params)
8799 wrapper.__signature__ = signature
8801 # __doc__ is None when using `python -OO ...`
8802 if func.__doc__ is not None:
8803 assert np_ret in func.__doc__, (
8804 f"Failed to replace `{np_ret}` with `{np_ma_ret}`. "
8805 f"The documentation string for return type, {np_ret}, is not "
8806 f"found in the docstring for `np.{func.__name__}`. "
8807 f"Fix the docstring for `np.{func.__name__}` or "
8808 "update the expected string for return type."
8809 )
8810 wrapper.__doc__ = inspect.cleandoc(func.__doc__).replace(np_ret, np_ma_ret)
8812 return wrapper
8815arange = _convert2ma(
8816 'arange',
8817 params={'fill_value': None, 'hardmask': False},
8818 np_ret='arange : ndarray',
8819 np_ma_ret='arange : MaskedArray',
8820)
8821clip = _convert2ma(
8822 'clip',
8823 params={'fill_value': None, 'hardmask': False},
8824 np_ret='clipped_array : ndarray',
8825 np_ma_ret='clipped_array : MaskedArray',
8826)
8827empty = _convert2ma(
8828 'empty',
8829 params={'fill_value': None, 'hardmask': False},
8830 np_ret='out : ndarray',
8831 np_ma_ret='out : MaskedArray',
8832)
8833empty_like = _convert2ma(
8834 'empty_like',
8835 np_ret='out : ndarray',
8836 np_ma_ret='out : MaskedArray',
8837)
8838frombuffer = _convert2ma(
8839 'frombuffer',
8840 np_ret='out : ndarray',
8841 np_ma_ret='out: MaskedArray',
8842)
8843fromfunction = _convert2ma(
8844 'fromfunction',
8845 np_ret='fromfunction : any',
8846 np_ma_ret='fromfunction: MaskedArray',
8847)
8848identity = _convert2ma(
8849 'identity',
8850 params={'fill_value': None, 'hardmask': False},
8851 np_ret='out : ndarray',
8852 np_ma_ret='out : MaskedArray',
8853)
8854indices = _convert2ma(
8855 'indices',
8856 params={'fill_value': None, 'hardmask': False},
8857 np_ret='grid : one ndarray or tuple of ndarrays',
8858 np_ma_ret='grid : one MaskedArray or tuple of MaskedArrays',
8859)
8860ones = _convert2ma(
8861 'ones',
8862 params={'fill_value': None, 'hardmask': False},
8863 np_ret='out : ndarray',
8864 np_ma_ret='out : MaskedArray',
8865)
8866ones_like = _convert2ma(
8867 'ones_like',
8868 np_ret='out : ndarray',
8869 np_ma_ret='out : MaskedArray',
8870)
8871squeeze = _convert2ma(
8872 'squeeze',
8873 params={'fill_value': None, 'hardmask': False},
8874 np_ret='squeezed : ndarray',
8875 np_ma_ret='squeezed : MaskedArray',
8876)
8877zeros = _convert2ma(
8878 'zeros',
8879 params={'fill_value': None, 'hardmask': False},
8880 np_ret='out : ndarray',
8881 np_ma_ret='out : MaskedArray',
8882)
8883zeros_like = _convert2ma(
8884 'zeros_like',
8885 np_ret='out : ndarray',
8886 np_ma_ret='out : MaskedArray',
8887)
8890def append(a, b, axis=None):
8891 """Append values to the end of an array.
8893 Parameters
8894 ----------
8895 a : array_like
8896 Values are appended to a copy of this array.
8897 b : array_like
8898 These values are appended to a copy of `a`. It must be of the
8899 correct shape (the same shape as `a`, excluding `axis`). If `axis`
8900 is not specified, `b` can be any shape and will be flattened
8901 before use.
8902 axis : int, optional
8903 The axis along which `v` are appended. If `axis` is not given,
8904 both `a` and `b` are flattened before use.
8906 Returns
8907 -------
8908 append : MaskedArray
8909 A copy of `a` with `b` appended to `axis`. Note that `append`
8910 does not occur in-place: a new array is allocated and filled. If
8911 `axis` is None, the result is a flattened array.
8913 See Also
8914 --------
8915 numpy.append : Equivalent function in the top-level NumPy module.
8917 Examples
8918 --------
8919 >>> import numpy as np
8920 >>> import numpy.ma as ma
8921 >>> a = ma.masked_values([1, 2, 3], 2)
8922 >>> b = ma.masked_values([[4, 5, 6], [7, 8, 9]], 7)
8923 >>> ma.append(a, b)
8924 masked_array(data=[1, --, 3, 4, 5, 6, --, 8, 9],
8925 mask=[False, True, False, False, False, False, True, False,
8926 False],
8927 fill_value=999999)
8928 """
8929 return concatenate([a, b], axis)