123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902 |
- """
- Masked arrays add-ons.
- A collection of utilities for `numpy.ma`.
- :author: Pierre Gerard-Marchant
- :contact: pierregm_at_uga_dot_edu
- :version: $Id: extras.py 3473 2007-10-29 15:18:13Z jarrod.millman $
- """
- from __future__ import division, absolute_import, print_function
- __all__ = [
- 'apply_along_axis', 'apply_over_axes', 'atleast_1d', 'atleast_2d',
- 'atleast_3d', 'average', 'clump_masked', 'clump_unmasked',
- 'column_stack', 'compress_cols', 'compress_nd', 'compress_rowcols',
- 'compress_rows', 'count_masked', 'corrcoef', 'cov', 'diagflat', 'dot',
- 'dstack', 'ediff1d', 'flatnotmasked_contiguous', 'flatnotmasked_edges',
- 'hsplit', 'hstack', 'isin', 'in1d', 'intersect1d', 'mask_cols', 'mask_rowcols',
- 'mask_rows', 'masked_all', 'masked_all_like', 'median', 'mr_',
- 'notmasked_contiguous', 'notmasked_edges', 'polyfit', 'row_stack',
- 'setdiff1d', 'setxor1d', 'stack', 'unique', 'union1d', 'vander', 'vstack',
- ]
- import itertools
- import warnings
- from . import core as ma
- from .core import (
- MaskedArray, MAError, add, array, asarray, concatenate, filled, count,
- getmask, getmaskarray, make_mask_descr, masked, masked_array, mask_or,
- nomask, ones, sort, zeros, getdata, get_masked_subclass, dot,
- mask_rowcols
- )
- import numpy as np
- from numpy import ndarray, array as nxarray
- import numpy.core.umath as umath
- from numpy.core.multiarray import normalize_axis_index
- from numpy.core.numeric import normalize_axis_tuple
- from numpy.lib.function_base import _ureduce
- from numpy.lib.index_tricks import AxisConcatenator
- def issequence(seq):
- """
- Is seq a sequence (ndarray, list or tuple)?
- """
- return isinstance(seq, (ndarray, tuple, list))
- def count_masked(arr, axis=None):
- """
- Count the number of masked elements along the given axis.
- Parameters
- ----------
- arr : array_like
- An array with (possibly) masked elements.
- axis : int, optional
- Axis along which to count. If None (default), a flattened
- version of the array is used.
- Returns
- -------
- count : int, ndarray
- The total number of masked elements (axis=None) or the number
- of masked elements along each slice of the given axis.
- See Also
- --------
- MaskedArray.count : Count non-masked elements.
- Examples
- --------
- >>> import numpy.ma as ma
- >>> a = np.arange(9).reshape((3,3))
- >>> a = ma.array(a)
- >>> a[1, 0] = ma.masked
- >>> a[1, 2] = ma.masked
- >>> a[2, 1] = ma.masked
- >>> a
- masked_array(data =
- [[0 1 2]
- [-- 4 --]
- [6 -- 8]],
- mask =
- [[False False False]
- [ True False True]
- [False True False]],
- fill_value=999999)
- >>> ma.count_masked(a)
- 3
- When the `axis` keyword is used an array is returned.
- >>> ma.count_masked(a, axis=0)
- array([1, 1, 1])
- >>> ma.count_masked(a, axis=1)
- array([0, 2, 1])
- """
- m = getmaskarray(arr)
- return m.sum(axis)
- def masked_all(shape, dtype=float):
- """
- Empty masked array with all elements masked.
- Return an empty masked array of the given shape and dtype, where all the
- data are masked.
- Parameters
- ----------
- shape : tuple
- Shape of the required MaskedArray.
- dtype : dtype, optional
- Data type of the output.
- Returns
- -------
- a : MaskedArray
- A masked array with all data masked.
- See Also
- --------
- masked_all_like : Empty masked array modelled on an existing array.
- Examples
- --------
- >>> import numpy.ma as ma
- >>> ma.masked_all((3, 3))
- masked_array(data =
- [[-- -- --]
- [-- -- --]
- [-- -- --]],
- mask =
- [[ True True True]
- [ True True True]
- [ True True True]],
- fill_value=1e+20)
- The `dtype` parameter defines the underlying data type.
- >>> a = ma.masked_all((3, 3))
- >>> a.dtype
- dtype('float64')
- >>> a = ma.masked_all((3, 3), dtype=np.int32)
- >>> a.dtype
- dtype('int32')
- """
- a = masked_array(np.empty(shape, dtype),
- mask=np.ones(shape, make_mask_descr(dtype)))
- return a
- def masked_all_like(arr):
- """
- Empty masked array with the properties of an existing array.
- Return an empty masked array of the same shape and dtype as
- the array `arr`, where all the data are masked.
- Parameters
- ----------
- arr : ndarray
- An array describing the shape and dtype of the required MaskedArray.
- Returns
- -------
- a : MaskedArray
- A masked array with all data masked.
- Raises
- ------
- AttributeError
- If `arr` doesn't have a shape attribute (i.e. not an ndarray)
- See Also
- --------
- masked_all : Empty masked array with all elements masked.
- Examples
- --------
- >>> import numpy.ma as ma
- >>> arr = np.zeros((2, 3), dtype=np.float32)
- >>> arr
- array([[ 0., 0., 0.],
- [ 0., 0., 0.]], dtype=float32)
- >>> ma.masked_all_like(arr)
- masked_array(data =
- [[-- -- --]
- [-- -- --]],
- mask =
- [[ True True True]
- [ True True True]],
- fill_value=1e+20)
- The dtype of the masked array matches the dtype of `arr`.
- >>> arr.dtype
- dtype('float32')
- >>> ma.masked_all_like(arr).dtype
- dtype('float32')
- """
- a = np.empty_like(arr).view(MaskedArray)
- a._mask = np.ones(a.shape, dtype=make_mask_descr(a.dtype))
- return a
- #####--------------------------------------------------------------------------
- #---- --- Standard functions ---
- #####--------------------------------------------------------------------------
- class _fromnxfunction(object):
- """
- Defines a wrapper to adapt NumPy functions to masked arrays.
- An instance of `_fromnxfunction` can be called with the same parameters
- as the wrapped NumPy function. The docstring of `newfunc` is adapted from
- the wrapped function as well, see `getdoc`.
- This class should not be used directly. Instead, one of its extensions that
- provides support for a specific type of input should be used.
- Parameters
- ----------
- funcname : str
- The name of the function to be adapted. The function should be
- in the NumPy namespace (i.e. ``np.funcname``).
- """
- def __init__(self, funcname):
- self.__name__ = funcname
- self.__doc__ = self.getdoc()
- def getdoc(self):
- """
- Retrieve the docstring and signature from the function.
- The ``__doc__`` attribute of the function is used as the docstring for
- the new masked array version of the function. A note on application
- of the function to the mask is appended.
- .. warning::
- If the function docstring already contained a Notes section, the
- new docstring will have two Notes sections instead of appending a note
- to the existing section.
- Parameters
- ----------
- None
- """
- npfunc = getattr(np, self.__name__, None)
- doc = getattr(npfunc, '__doc__', None)
- if doc:
- sig = self.__name__ + ma.get_object_signature(npfunc)
- locdoc = "Notes\n-----\nThe function is applied to both the _data"\
- " and the _mask, if any."
- return '\n'.join((sig, doc, locdoc))
- return
- def __call__(self, *args, **params):
- pass
- class _fromnxfunction_single(_fromnxfunction):
- """
- A version of `_fromnxfunction` that is called with a single array
- argument followed by auxiliary args that are passed verbatim for
- both the data and mask calls.
- """
- def __call__(self, x, *args, **params):
- func = getattr(np, self.__name__)
- if isinstance(x, ndarray):
- _d = func(x.__array__(), *args, **params)
- _m = func(getmaskarray(x), *args, **params)
- return masked_array(_d, mask=_m)
- else:
- _d = func(np.asarray(x), *args, **params)
- _m = func(getmaskarray(x), *args, **params)
- return masked_array(_d, mask=_m)
- class _fromnxfunction_seq(_fromnxfunction):
- """
- A version of `_fromnxfunction` that is called with a single sequence
- of arrays followed by auxiliary args that are passed verbatim for
- both the data and mask calls.
- """
- def __call__(self, x, *args, **params):
- func = getattr(np, self.__name__)
- _d = func(tuple([np.asarray(a) for a in x]), *args, **params)
- _m = func(tuple([getmaskarray(a) for a in x]), *args, **params)
- return masked_array(_d, mask=_m)
- class _fromnxfunction_args(_fromnxfunction):
- """
- A version of `_fromnxfunction` that is called with multiple array
- arguments. The first non-array-like input marks the beginning of the
- arguments that are passed verbatim for both the data and mask calls.
- Array arguments are processed independently and the results are
- returned in a list. If only one array is found, the return value is
- just the processed array instead of a list.
- """
- def __call__(self, *args, **params):
- func = getattr(np, self.__name__)
- arrays = []
- args = list(args)
- while len(args) > 0 and issequence(args[0]):
- arrays.append(args.pop(0))
- res = []
- for x in arrays:
- _d = func(np.asarray(x), *args, **params)
- _m = func(getmaskarray(x), *args, **params)
- res.append(masked_array(_d, mask=_m))
- if len(arrays) == 1:
- return res[0]
- return res
- class _fromnxfunction_allargs(_fromnxfunction):
- """
- A version of `_fromnxfunction` that is called with multiple array
- arguments. Similar to `_fromnxfunction_args` except that all args
- are converted to arrays even if they are not so already. This makes
- it possible to process scalars as 1-D arrays. Only keyword arguments
- are passed through verbatim for the data and mask calls. Arrays
- arguments are processed independently and the results are returned
- in a list. If only one arg is present, the return value is just the
- processed array instead of a list.
- """
- def __call__(self, *args, **params):
- func = getattr(np, self.__name__)
- res = []
- for x in args:
- _d = func(np.asarray(x), **params)
- _m = func(getmaskarray(x), **params)
- res.append(masked_array(_d, mask=_m))
- if len(args) == 1:
- return res[0]
- return res
- atleast_1d = _fromnxfunction_allargs('atleast_1d')
- atleast_2d = _fromnxfunction_allargs('atleast_2d')
- atleast_3d = _fromnxfunction_allargs('atleast_3d')
- vstack = row_stack = _fromnxfunction_seq('vstack')
- hstack = _fromnxfunction_seq('hstack')
- column_stack = _fromnxfunction_seq('column_stack')
- dstack = _fromnxfunction_seq('dstack')
- stack = _fromnxfunction_seq('stack')
- hsplit = _fromnxfunction_single('hsplit')
- diagflat = _fromnxfunction_single('diagflat')
- #####--------------------------------------------------------------------------
- #----
- #####--------------------------------------------------------------------------
- def flatten_inplace(seq):
- """Flatten a sequence in place."""
- k = 0
- while (k != len(seq)):
- while hasattr(seq[k], '__iter__'):
- seq[k:(k + 1)] = seq[k]
- k += 1
- return seq
- def apply_along_axis(func1d, axis, arr, *args, **kwargs):
- """
- (This docstring should be overwritten)
- """
- arr = array(arr, copy=False, subok=True)
- nd = arr.ndim
- axis = normalize_axis_index(axis, nd)
- ind = [0] * (nd - 1)
- i = np.zeros(nd, 'O')
- indlist = list(range(nd))
- indlist.remove(axis)
- i[axis] = slice(None, None)
- outshape = np.asarray(arr.shape).take(indlist)
- i.put(indlist, ind)
- j = i.copy()
- res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
- # if res is a number, then we have a smaller output array
- asscalar = np.isscalar(res)
- if not asscalar:
- try:
- len(res)
- except TypeError:
- asscalar = True
- # Note: we shouldn't set the dtype of the output from the first result
- # so we force the type to object, and build a list of dtypes. We'll
- # just take the largest, to avoid some downcasting
- dtypes = []
- if asscalar:
- dtypes.append(np.asarray(res).dtype)
- outarr = zeros(outshape, object)
- outarr[tuple(ind)] = res
- Ntot = np.product(outshape)
- k = 1
- while k < Ntot:
- # increment the index
- ind[-1] += 1
- n = -1
- while (ind[n] >= outshape[n]) and (n > (1 - nd)):
- ind[n - 1] += 1
- ind[n] = 0
- n -= 1
- i.put(indlist, ind)
- res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
- outarr[tuple(ind)] = res
- dtypes.append(asarray(res).dtype)
- k += 1
- else:
- res = array(res, copy=False, subok=True)
- j = i.copy()
- j[axis] = ([slice(None, None)] * res.ndim)
- j.put(indlist, ind)
- Ntot = np.product(outshape)
- holdshape = outshape
- outshape = list(arr.shape)
- outshape[axis] = res.shape
- dtypes.append(asarray(res).dtype)
- outshape = flatten_inplace(outshape)
- outarr = zeros(outshape, object)
- outarr[tuple(flatten_inplace(j.tolist()))] = res
- k = 1
- while k < Ntot:
- # increment the index
- ind[-1] += 1
- n = -1
- while (ind[n] >= holdshape[n]) and (n > (1 - nd)):
- ind[n - 1] += 1
- ind[n] = 0
- n -= 1
- i.put(indlist, ind)
- j.put(indlist, ind)
- res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
- outarr[tuple(flatten_inplace(j.tolist()))] = res
- dtypes.append(asarray(res).dtype)
- k += 1
- max_dtypes = np.dtype(np.asarray(dtypes).max())
- if not hasattr(arr, '_mask'):
- result = np.asarray(outarr, dtype=max_dtypes)
- else:
- result = asarray(outarr, dtype=max_dtypes)
- result.fill_value = ma.default_fill_value(result)
- return result
- apply_along_axis.__doc__ = np.apply_along_axis.__doc__
- def apply_over_axes(func, a, axes):
- """
- (This docstring will be overwritten)
- """
- val = asarray(a)
- N = a.ndim
- if array(axes).ndim == 0:
- axes = (axes,)
- for axis in axes:
- if axis < 0:
- axis = N + axis
- args = (val, axis)
- res = func(*args)
- if res.ndim == val.ndim:
- val = res
- else:
- res = ma.expand_dims(res, axis)
- if res.ndim == val.ndim:
- val = res
- else:
- raise ValueError("function is not returning "
- "an array of the correct shape")
- return val
- if apply_over_axes.__doc__ is not None:
- apply_over_axes.__doc__ = np.apply_over_axes.__doc__[
- :np.apply_over_axes.__doc__.find('Notes')].rstrip() + \
- """
- Examples
- --------
- >>> a = ma.arange(24).reshape(2,3,4)
- >>> a[:,0,1] = ma.masked
- >>> a[:,1,:] = ma.masked
- >>> print(a)
- [[[0 -- 2 3]
- [-- -- -- --]
- [8 9 10 11]]
- [[12 -- 14 15]
- [-- -- -- --]
- [20 21 22 23]]]
- >>> print(ma.apply_over_axes(ma.sum, a, [0,2]))
- [[[46]
- [--]
- [124]]]
- Tuple axis arguments to ufuncs are equivalent:
- >>> print(ma.sum(a, axis=(0,2)).reshape((1,-1,1)))
- [[[46]
- [--]
- [124]]]
- """
- def average(a, axis=None, weights=None, returned=False):
- """
- Return the weighted average of array over the given axis.
- Parameters
- ----------
- a : array_like
- Data to be averaged.
- Masked entries are not taken into account in the computation.
- axis : int, optional
- Axis along which to average `a`. If `None`, averaging is done over
- the flattened array.
- weights : array_like, optional
- The importance that each element has in the computation of the average.
- The weights array can either be 1-D (in which case its length must be
- the size of `a` along the given axis) or of the same shape as `a`.
- If ``weights=None``, then all data in `a` are assumed to have a
- weight equal to one. If `weights` is complex, the imaginary parts
- are ignored.
- returned : bool, optional
- Flag indicating whether a tuple ``(result, sum of weights)``
- should be returned as output (True), or just the result (False).
- Default is False.
- Returns
- -------
- average, [sum_of_weights] : (tuple of) scalar or MaskedArray
- The average along the specified axis. When returned is `True`,
- return a tuple with the average as the first element and the sum
- of the weights as the second element. The return type is `np.float64`
- if `a` is of integer type and floats smaller than `float64`, or the
- input data-type, otherwise. If returned, `sum_of_weights` is always
- `float64`.
- Examples
- --------
- >>> a = np.ma.array([1., 2., 3., 4.], mask=[False, False, True, True])
- >>> np.ma.average(a, weights=[3, 1, 0, 0])
- 1.25
- >>> x = np.ma.arange(6.).reshape(3, 2)
- >>> print(x)
- [[ 0. 1.]
- [ 2. 3.]
- [ 4. 5.]]
- >>> avg, sumweights = np.ma.average(x, axis=0, weights=[1, 2, 3],
- ... returned=True)
- >>> print(avg)
- [2.66666666667 3.66666666667]
- """
- a = asarray(a)
- m = getmask(a)
- # inspired by 'average' in numpy/lib/function_base.py
- if weights is None:
- avg = a.mean(axis)
- scl = avg.dtype.type(a.count(axis))
- else:
- wgt = np.asanyarray(weights)
- if issubclass(a.dtype.type, (np.integer, np.bool_)):
- result_dtype = np.result_type(a.dtype, wgt.dtype, 'f8')
- else:
- result_dtype = np.result_type(a.dtype, wgt.dtype)
- # Sanity checks
- if a.shape != wgt.shape:
- if axis is None:
- raise TypeError(
- "Axis must be specified when shapes of a and weights "
- "differ.")
- if wgt.ndim != 1:
- raise TypeError(
- "1D weights expected when shapes of a and weights differ.")
- if wgt.shape[0] != a.shape[axis]:
- raise ValueError(
- "Length of weights not compatible with specified axis.")
- # setup wgt to broadcast along axis
- wgt = np.broadcast_to(wgt, (a.ndim-1)*(1,) + wgt.shape)
- wgt = wgt.swapaxes(-1, axis)
- if m is not nomask:
- wgt = wgt*(~a.mask)
- scl = wgt.sum(axis=axis, dtype=result_dtype)
- avg = np.multiply(a, wgt, dtype=result_dtype).sum(axis)/scl
- if returned:
- if scl.shape != avg.shape:
- scl = np.broadcast_to(scl, avg.shape).copy()
- return avg, scl
- else:
- return avg
- def median(a, axis=None, out=None, overwrite_input=False, keepdims=False):
- """
- Compute the median along the specified axis.
- Returns the median of the array elements.
- Parameters
- ----------
- a : array_like
- Input array or object that can be converted to an array.
- axis : int, optional
- Axis along which the medians are computed. The default (None) is
- to compute the median along a flattened version of the array.
- out : ndarray, optional
- Alternative output array in which to place the result. It must
- have the same shape and buffer length as the expected output
- but the type will be cast if necessary.
- overwrite_input : bool, optional
- If True, then allow use of memory of input array (a) for
- calculations. The input array will be modified by the call to
- median. This will save memory when you do not need to preserve
- the contents of the input array. Treat the input as undefined,
- but it will probably be fully or partially sorted. Default is
- False. Note that, if `overwrite_input` is True, and the input
- is not already an `ndarray`, an error will be raised.
- keepdims : bool, optional
- If this is set to True, the axes which are reduced are left
- in the result as dimensions with size one. With this option,
- the result will broadcast correctly against the input array.
- .. versionadded:: 1.10.0
- Returns
- -------
- median : ndarray
- A new array holding the result is returned unless out is
- specified, in which case a reference to out is returned.
- Return data-type is `float64` for integers and floats smaller than
- `float64`, or the input data-type, otherwise.
- See Also
- --------
- mean
- Notes
- -----
- Given a vector ``V`` with ``N`` non masked values, the median of ``V``
- is the middle value of a sorted copy of ``V`` (``Vs``) - i.e.
- ``Vs[(N-1)/2]``, when ``N`` is odd, or ``{Vs[N/2 - 1] + Vs[N/2]}/2``
- when ``N`` is even.
- Examples
- --------
- >>> x = np.ma.array(np.arange(8), mask=[0]*4 + [1]*4)
- >>> np.ma.median(x)
- 1.5
- >>> x = np.ma.array(np.arange(10).reshape(2, 5), mask=[0]*6 + [1]*4)
- >>> np.ma.median(x)
- 2.5
- >>> np.ma.median(x, axis=-1, overwrite_input=True)
- masked_array(data = [ 2. 5.],
- mask = False,
- fill_value = 1e+20)
- """
- if not hasattr(a, 'mask'):
- m = np.median(getdata(a, subok=True), axis=axis,
- out=out, overwrite_input=overwrite_input,
- keepdims=keepdims)
- if isinstance(m, np.ndarray) and 1 <= m.ndim:
- return masked_array(m, copy=False)
- else:
- return m
- r, k = _ureduce(a, func=_median, axis=axis, out=out,
- overwrite_input=overwrite_input)
- if keepdims:
- return r.reshape(k)
- else:
- return r
- def _median(a, axis=None, out=None, overwrite_input=False):
- # when an unmasked NaN is present return it, so we need to sort the NaN
- # values behind the mask
- if np.issubdtype(a.dtype, np.inexact):
- fill_value = np.inf
- else:
- fill_value = None
- if overwrite_input:
- if axis is None:
- asorted = a.ravel()
- asorted.sort(fill_value=fill_value)
- else:
- a.sort(axis=axis, fill_value=fill_value)
- asorted = a
- else:
- asorted = sort(a, axis=axis, fill_value=fill_value)
- if axis is None:
- axis = 0
- else:
- axis = normalize_axis_index(axis, asorted.ndim)
- if asorted.shape[axis] == 0:
- # for empty axis integer indices fail so use slicing to get same result
- # as median (which is mean of empty slice = nan)
- indexer = [slice(None)] * asorted.ndim
- indexer[axis] = slice(0, 0)
- indexer = tuple(indexer)
- return np.ma.mean(asorted[indexer], axis=axis, out=out)
- if asorted.ndim == 1:
- counts = count(asorted)
- idx, odd = divmod(count(asorted), 2)
- mid = asorted[idx + odd - 1:idx + 1]
- if np.issubdtype(asorted.dtype, np.inexact) and asorted.size > 0:
- # avoid inf / x = masked
- s = mid.sum(out=out)
- if not odd:
- s = np.true_divide(s, 2., casting='safe', out=out)
- s = np.lib.utils._median_nancheck(asorted, s, axis, out)
- else:
- s = mid.mean(out=out)
- # if result is masked either the input contained enough
- # minimum_fill_value so that it would be the median or all values
- # masked
- if np.ma.is_masked(s) and not np.all(asorted.mask):
- return np.ma.minimum_fill_value(asorted)
- return s
- counts = count(asorted, axis=axis, keepdims=True)
- h = counts // 2
- # duplicate high if odd number of elements so mean does nothing
- odd = counts % 2 == 1
- l = np.where(odd, h, h-1)
- lh = np.concatenate([l,h], axis=axis)
- # get low and high median
- low_high = np.take_along_axis(asorted, lh, axis=axis)
- def replace_masked(s):
- # Replace masked entries with minimum_full_value unless it all values
- # are masked. This is required as the sort order of values equal or
- # larger than the fill value is undefined and a valid value placed
- # elsewhere, e.g. [4, --, inf].
- if np.ma.is_masked(s):
- rep = (~np.all(asorted.mask, axis=axis, keepdims=True)) & s.mask
- s.data[rep] = np.ma.minimum_fill_value(asorted)
- s.mask[rep] = False
- replace_masked(low_high)
- if np.issubdtype(asorted.dtype, np.inexact):
- # avoid inf / x = masked
- s = np.ma.sum(low_high, axis=axis, out=out)
- np.true_divide(s.data, 2., casting='unsafe', out=s.data)
- s = np.lib.utils._median_nancheck(asorted, s, axis, out)
- else:
- s = np.ma.mean(low_high, axis=axis, out=out)
- return s
- def compress_nd(x, axis=None):
- """Suppress slices from multiple dimensions which contain masked values.
- Parameters
- ----------
- x : array_like, MaskedArray
- The array to operate on. If not a MaskedArray instance (or if no array
- elements are masked, `x` is interpreted as a MaskedArray with `mask`
- set to `nomask`.
- axis : tuple of ints or int, optional
- Which dimensions to suppress slices from can be configured with this
- parameter.
- - If axis is a tuple of ints, those are the axes to suppress slices from.
- - If axis is an int, then that is the only axis to suppress slices from.
- - If axis is None, all axis are selected.
- Returns
- -------
- compress_array : ndarray
- The compressed array.
- """
- x = asarray(x)
- m = getmask(x)
- # Set axis to tuple of ints
- if axis is None:
- axis = tuple(range(x.ndim))
- else:
- axis = normalize_axis_tuple(axis, x.ndim)
- # Nothing is masked: return x
- if m is nomask or not m.any():
- return x._data
- # All is masked: return empty
- if m.all():
- return nxarray([])
- # Filter elements through boolean indexing
- data = x._data
- for ax in axis:
- axes = tuple(list(range(ax)) + list(range(ax + 1, x.ndim)))
- data = data[(slice(None),)*ax + (~m.any(axis=axes),)]
- return data
- def compress_rowcols(x, axis=None):
- """
- Suppress the rows and/or columns of a 2-D array that contain
- masked values.
- The suppression behavior is selected with the `axis` parameter.
- - If axis is None, both rows and columns are suppressed.
- - If axis is 0, only rows are suppressed.
- - If axis is 1 or -1, only columns are suppressed.
- Parameters
- ----------
- x : array_like, MaskedArray
- The array to operate on. If not a MaskedArray instance (or if no array
- elements are masked), `x` is interpreted as a MaskedArray with
- `mask` set to `nomask`. Must be a 2D array.
- axis : int, optional
- Axis along which to perform the operation. Default is None.
- Returns
- -------
- compressed_array : ndarray
- The compressed array.
- Examples
- --------
- >>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0],
- ... [1, 0, 0],
- ... [0, 0, 0]])
- >>> x
- masked_array(data =
- [[-- 1 2]
- [-- 4 5]
- [6 7 8]],
- mask =
- [[ True False False]
- [ True False False]
- [False False False]],
- fill_value = 999999)
- >>> np.ma.compress_rowcols(x)
- array([[7, 8]])
- >>> np.ma.compress_rowcols(x, 0)
- array([[6, 7, 8]])
- >>> np.ma.compress_rowcols(x, 1)
- array([[1, 2],
- [4, 5],
- [7, 8]])
- """
- if asarray(x).ndim != 2:
- raise NotImplementedError("compress_rowcols works for 2D arrays only.")
- return compress_nd(x, axis=axis)
- def compress_rows(a):
- """
- Suppress whole rows of a 2-D array that contain masked values.
- This is equivalent to ``np.ma.compress_rowcols(a, 0)``, see
- `extras.compress_rowcols` for details.
- See Also
- --------
- extras.compress_rowcols
- """
- a = asarray(a)
- if a.ndim != 2:
- raise NotImplementedError("compress_rows works for 2D arrays only.")
- return compress_rowcols(a, 0)
- def compress_cols(a):
- """
- Suppress whole columns of a 2-D array that contain masked values.
- This is equivalent to ``np.ma.compress_rowcols(a, 1)``, see
- `extras.compress_rowcols` for details.
- See Also
- --------
- extras.compress_rowcols
- """
- a = asarray(a)
- if a.ndim != 2:
- raise NotImplementedError("compress_cols works for 2D arrays only.")
- return compress_rowcols(a, 1)
- def mask_rows(a, axis=None):
- """
- Mask rows of a 2D array that contain masked values.
- This function is a shortcut to ``mask_rowcols`` with `axis` equal to 0.
- See Also
- --------
- mask_rowcols : Mask rows and/or columns of a 2D array.
- masked_where : Mask where a condition is met.
- Examples
- --------
- >>> import numpy.ma as ma
- >>> a = np.zeros((3, 3), dtype=int)
- >>> a[1, 1] = 1
- >>> a
- array([[0, 0, 0],
- [0, 1, 0],
- [0, 0, 0]])
- >>> a = ma.masked_equal(a, 1)
- >>> a
- masked_array(data =
- [[0 0 0]
- [0 -- 0]
- [0 0 0]],
- mask =
- [[False False False]
- [False True False]
- [False False False]],
- fill_value=999999)
- >>> ma.mask_rows(a)
- masked_array(data =
- [[0 0 0]
- [-- -- --]
- [0 0 0]],
- mask =
- [[False False False]
- [ True True True]
- [False False False]],
- fill_value=999999)
- """
- return mask_rowcols(a, 0)
- def mask_cols(a, axis=None):
- """
- Mask columns of a 2D array that contain masked values.
- This function is a shortcut to ``mask_rowcols`` with `axis` equal to 1.
- See Also
- --------
- mask_rowcols : Mask rows and/or columns of a 2D array.
- masked_where : Mask where a condition is met.
- Examples
- --------
- >>> import numpy.ma as ma
- >>> a = np.zeros((3, 3), dtype=int)
- >>> a[1, 1] = 1
- >>> a
- array([[0, 0, 0],
- [0, 1, 0],
- [0, 0, 0]])
- >>> a = ma.masked_equal(a, 1)
- >>> a
- masked_array(data =
- [[0 0 0]
- [0 -- 0]
- [0 0 0]],
- mask =
- [[False False False]
- [False True False]
- [False False False]],
- fill_value=999999)
- >>> ma.mask_cols(a)
- masked_array(data =
- [[0 -- 0]
- [0 -- 0]
- [0 -- 0]],
- mask =
- [[False True False]
- [False True False]
- [False True False]],
- fill_value=999999)
- """
- return mask_rowcols(a, 1)
- #####--------------------------------------------------------------------------
- #---- --- arraysetops ---
- #####--------------------------------------------------------------------------
- def ediff1d(arr, to_end=None, to_begin=None):
- """
- Compute the differences between consecutive elements of an array.
- This function is the equivalent of `numpy.ediff1d` that takes masked
- values into account, see `numpy.ediff1d` for details.
- See Also
- --------
- numpy.ediff1d : Equivalent function for ndarrays.
- """
- arr = ma.asanyarray(arr).flat
- ed = arr[1:] - arr[:-1]
- arrays = [ed]
- #
- if to_begin is not None:
- arrays.insert(0, to_begin)
- if to_end is not None:
- arrays.append(to_end)
- #
- if len(arrays) != 1:
- # We'll save ourselves a copy of a potentially large array in the common
- # case where neither to_begin or to_end was given.
- ed = hstack(arrays)
- #
- return ed
- def unique(ar1, return_index=False, return_inverse=False):
- """
- Finds the unique elements of an array.
- Masked values are considered the same element (masked). The output array
- is always a masked array. See `numpy.unique` for more details.
- See Also
- --------
- numpy.unique : Equivalent function for ndarrays.
- """
- output = np.unique(ar1,
- return_index=return_index,
- return_inverse=return_inverse)
- if isinstance(output, tuple):
- output = list(output)
- output[0] = output[0].view(MaskedArray)
- output = tuple(output)
- else:
- output = output.view(MaskedArray)
- return output
- def intersect1d(ar1, ar2, assume_unique=False):
- """
- Returns the unique elements common to both arrays.
- Masked values are considered equal one to the other.
- The output is always a masked array.
- See `numpy.intersect1d` for more details.
- See Also
- --------
- numpy.intersect1d : Equivalent function for ndarrays.
- Examples
- --------
- >>> x = array([1, 3, 3, 3], mask=[0, 0, 0, 1])
- >>> y = array([3, 1, 1, 1], mask=[0, 0, 0, 1])
- >>> intersect1d(x, y)
- masked_array(data = [1 3 --],
- mask = [False False True],
- fill_value = 999999)
- """
- if assume_unique:
- aux = ma.concatenate((ar1, ar2))
- else:
- # Might be faster than unique( intersect1d( ar1, ar2 ) )?
- aux = ma.concatenate((unique(ar1), unique(ar2)))
- aux.sort()
- return aux[:-1][aux[1:] == aux[:-1]]
- def setxor1d(ar1, ar2, assume_unique=False):
- """
- Set exclusive-or of 1-D arrays with unique elements.
- The output is always a masked array. See `numpy.setxor1d` for more details.
- See Also
- --------
- numpy.setxor1d : Equivalent function for ndarrays.
- """
- if not assume_unique:
- ar1 = unique(ar1)
- ar2 = unique(ar2)
- aux = ma.concatenate((ar1, ar2))
- if aux.size == 0:
- return aux
- aux.sort()
- auxf = aux.filled()
- # flag = ediff1d( aux, to_end = 1, to_begin = 1 ) == 0
- flag = ma.concatenate(([True], (auxf[1:] != auxf[:-1]), [True]))
- # flag2 = ediff1d( flag ) == 0
- flag2 = (flag[1:] == flag[:-1])
- return aux[flag2]
- def in1d(ar1, ar2, assume_unique=False, invert=False):
- """
- Test whether each element of an array is also present in a second
- array.
- The output is always a masked array. See `numpy.in1d` for more details.
- We recommend using :func:`isin` instead of `in1d` for new code.
- See Also
- --------
- isin : Version of this function that preserves the shape of ar1.
- numpy.in1d : Equivalent function for ndarrays.
- Notes
- -----
- .. versionadded:: 1.4.0
- """
- if not assume_unique:
- ar1, rev_idx = unique(ar1, return_inverse=True)
- ar2 = unique(ar2)
- ar = ma.concatenate((ar1, ar2))
- # We need this to be a stable sort, so always use 'mergesort'
- # here. The values from the first array should always come before
- # the values from the second array.
- order = ar.argsort(kind='mergesort')
- sar = ar[order]
- if invert:
- bool_ar = (sar[1:] != sar[:-1])
- else:
- bool_ar = (sar[1:] == sar[:-1])
- flag = ma.concatenate((bool_ar, [invert]))
- indx = order.argsort(kind='mergesort')[:len(ar1)]
- if assume_unique:
- return flag[indx]
- else:
- return flag[indx][rev_idx]
- def isin(element, test_elements, assume_unique=False, invert=False):
- """
- Calculates `element in test_elements`, broadcasting over
- `element` only.
- The output is always a masked array of the same shape as `element`.
- See `numpy.isin` for more details.
- See Also
- --------
- in1d : Flattened version of this function.
- numpy.isin : Equivalent function for ndarrays.
- Notes
- -----
- .. versionadded:: 1.13.0
- """
- element = ma.asarray(element)
- return in1d(element, test_elements, assume_unique=assume_unique,
- invert=invert).reshape(element.shape)
- def union1d(ar1, ar2):
- """
- Union of two arrays.
- The output is always a masked array. See `numpy.union1d` for more details.
- See also
- --------
- numpy.union1d : Equivalent function for ndarrays.
- """
- return unique(ma.concatenate((ar1, ar2), axis=None))
- def setdiff1d(ar1, ar2, assume_unique=False):
- """
- Set difference of 1D arrays with unique elements.
- The output is always a masked array. See `numpy.setdiff1d` for more
- details.
- See Also
- --------
- numpy.setdiff1d : Equivalent function for ndarrays.
- Examples
- --------
- >>> x = np.ma.array([1, 2, 3, 4], mask=[0, 1, 0, 1])
- >>> np.ma.setdiff1d(x, [1, 2])
- masked_array(data = [3 --],
- mask = [False True],
- fill_value = 999999)
- """
- if assume_unique:
- ar1 = ma.asarray(ar1).ravel()
- else:
- ar1 = unique(ar1)
- ar2 = unique(ar2)
- return ar1[in1d(ar1, ar2, assume_unique=True, invert=True)]
- ###############################################################################
- # Covariance #
- ###############################################################################
- def _covhelper(x, y=None, rowvar=True, allow_masked=True):
- """
- Private function for the computation of covariance and correlation
- coefficients.
- """
- x = ma.array(x, ndmin=2, copy=True, dtype=float)
- xmask = ma.getmaskarray(x)
- # Quick exit if we can't process masked data
- if not allow_masked and xmask.any():
- raise ValueError("Cannot process masked data.")
- #
- if x.shape[0] == 1:
- rowvar = True
- # Make sure that rowvar is either 0 or 1
- rowvar = int(bool(rowvar))
- axis = 1 - rowvar
- if rowvar:
- tup = (slice(None), None)
- else:
- tup = (None, slice(None))
- #
- if y is None:
- xnotmask = np.logical_not(xmask).astype(int)
- else:
- y = array(y, copy=False, ndmin=2, dtype=float)
- ymask = ma.getmaskarray(y)
- if not allow_masked and ymask.any():
- raise ValueError("Cannot process masked data.")
- if xmask.any() or ymask.any():
- if y.shape == x.shape:
- # Define some common mask
- common_mask = np.logical_or(xmask, ymask)
- if common_mask is not nomask:
- xmask = x._mask = y._mask = ymask = common_mask
- x._sharedmask = False
- y._sharedmask = False
- x = ma.concatenate((x, y), axis)
- xnotmask = np.logical_not(np.concatenate((xmask, ymask), axis)).astype(int)
- x -= x.mean(axis=rowvar)[tup]
- return (x, xnotmask, rowvar)
- def cov(x, y=None, rowvar=True, bias=False, allow_masked=True, ddof=None):
- """
- Estimate the covariance matrix.
- Except for the handling of missing data this function does the same as
- `numpy.cov`. For more details and examples, see `numpy.cov`.
- By default, masked values are recognized as such. If `x` and `y` have the
- same shape, a common mask is allocated: if ``x[i,j]`` is masked, then
- ``y[i,j]`` will also be masked.
- Setting `allow_masked` to False will raise an exception if values are
- missing in either of the input arrays.
- Parameters
- ----------
- x : array_like
- A 1-D or 2-D array containing multiple variables and observations.
- Each row of `x` represents a variable, and each column a single
- observation of all those variables. Also see `rowvar` below.
- y : array_like, optional
- An additional set of variables and observations. `y` has the same
- form as `x`.
- rowvar : bool, optional
- If `rowvar` is True (default), then each row represents a
- variable, with observations in the columns. Otherwise, the relationship
- is transposed: each column represents a variable, while the rows
- contain observations.
- bias : bool, optional
- Default normalization (False) is by ``(N-1)``, where ``N`` is the
- number of observations given (unbiased estimate). If `bias` is True,
- then normalization is by ``N``. This keyword can be overridden by
- the keyword ``ddof`` in numpy versions >= 1.5.
- allow_masked : bool, optional
- If True, masked values are propagated pair-wise: if a value is masked
- in `x`, the corresponding value is masked in `y`.
- If False, raises a `ValueError` exception when some values are missing.
- ddof : {None, int}, optional
- If not ``None`` normalization is by ``(N - ddof)``, where ``N`` is
- the number of observations; this overrides the value implied by
- ``bias``. The default value is ``None``.
- .. versionadded:: 1.5
- Raises
- ------
- ValueError
- Raised if some values are missing and `allow_masked` is False.
- See Also
- --------
- numpy.cov
- """
- # Check inputs
- if ddof is not None and ddof != int(ddof):
- raise ValueError("ddof must be an integer")
- # Set up ddof
- if ddof is None:
- if bias:
- ddof = 0
- else:
- ddof = 1
- (x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked)
- if not rowvar:
- fact = np.dot(xnotmask.T, xnotmask) * 1. - ddof
- result = (dot(x.T, x.conj(), strict=False) / fact).squeeze()
- else:
- fact = np.dot(xnotmask, xnotmask.T) * 1. - ddof
- result = (dot(x, x.T.conj(), strict=False) / fact).squeeze()
- return result
- def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, allow_masked=True,
- ddof=np._NoValue):
- """
- Return Pearson product-moment correlation coefficients.
- Except for the handling of missing data this function does the same as
- `numpy.corrcoef`. For more details and examples, see `numpy.corrcoef`.
- Parameters
- ----------
- x : array_like
- A 1-D or 2-D array containing multiple variables and observations.
- Each row of `x` represents a variable, and each column a single
- observation of all those variables. Also see `rowvar` below.
- y : array_like, optional
- An additional set of variables and observations. `y` has the same
- shape as `x`.
- rowvar : bool, optional
- If `rowvar` is True (default), then each row represents a
- variable, with observations in the columns. Otherwise, the relationship
- is transposed: each column represents a variable, while the rows
- contain observations.
- bias : _NoValue, optional
- Has no effect, do not use.
- .. deprecated:: 1.10.0
- allow_masked : bool, optional
- If True, masked values are propagated pair-wise: if a value is masked
- in `x`, the corresponding value is masked in `y`.
- If False, raises an exception. Because `bias` is deprecated, this
- argument needs to be treated as keyword only to avoid a warning.
- ddof : _NoValue, optional
- Has no effect, do not use.
- .. deprecated:: 1.10.0
- See Also
- --------
- numpy.corrcoef : Equivalent function in top-level NumPy module.
- cov : Estimate the covariance matrix.
- Notes
- -----
- This function accepts but discards arguments `bias` and `ddof`. This is
- for backwards compatibility with previous versions of this function. These
- arguments had no effect on the return values of the function and can be
- safely ignored in this and previous versions of numpy.
- """
- msg = 'bias and ddof have no effect and are deprecated'
- if bias is not np._NoValue or ddof is not np._NoValue:
- # 2015-03-15, 1.10
- warnings.warn(msg, DeprecationWarning, stacklevel=2)
- # Get the data
- (x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked)
- # Compute the covariance matrix
- if not rowvar:
- fact = np.dot(xnotmask.T, xnotmask) * 1.
- c = (dot(x.T, x.conj(), strict=False) / fact).squeeze()
- else:
- fact = np.dot(xnotmask, xnotmask.T) * 1.
- c = (dot(x, x.T.conj(), strict=False) / fact).squeeze()
- # Check whether we have a scalar
- try:
- diag = ma.diagonal(c)
- except ValueError:
- return 1
- #
- if xnotmask.all():
- _denom = ma.sqrt(ma.multiply.outer(diag, diag))
- else:
- _denom = diagflat(diag)
- _denom._sharedmask = False # We know return is always a copy
- n = x.shape[1 - rowvar]
- if rowvar:
- for i in range(n - 1):
- for j in range(i + 1, n):
- _x = mask_cols(vstack((x[i], x[j]))).var(axis=1)
- _denom[i, j] = _denom[j, i] = ma.sqrt(ma.multiply.reduce(_x))
- else:
- for i in range(n - 1):
- for j in range(i + 1, n):
- _x = mask_cols(
- vstack((x[:, i], x[:, j]))).var(axis=1)
- _denom[i, j] = _denom[j, i] = ma.sqrt(ma.multiply.reduce(_x))
- return c / _denom
- #####--------------------------------------------------------------------------
- #---- --- Concatenation helpers ---
- #####--------------------------------------------------------------------------
- class MAxisConcatenator(AxisConcatenator):
- """
- Translate slice objects to concatenation along an axis.
- For documentation on usage, see `mr_class`.
- See Also
- --------
- mr_class
- """
- concatenate = staticmethod(concatenate)
- @classmethod
- def makemat(cls, arr):
- # There used to be a view as np.matrix here, but we may eventually
- # deprecate that class. In preparation, we use the unmasked version
- # to construct the matrix (with copy=False for backwards compatibility
- # with the .view)
- data = super(MAxisConcatenator, cls).makemat(arr.data, copy=False)
- return array(data, mask=arr.mask)
- def __getitem__(self, key):
- # matrix builder syntax, like 'a, b; c, d'
- if isinstance(key, str):
- raise MAError("Unavailable for masked array.")
- return super(MAxisConcatenator, self).__getitem__(key)
- class mr_class(MAxisConcatenator):
- """
- Translate slice objects to concatenation along the first axis.
- This is the masked array version of `lib.index_tricks.RClass`.
- See Also
- --------
- lib.index_tricks.RClass
- Examples
- --------
- >>> np.ma.mr_[np.ma.array([1,2,3]), 0, 0, np.ma.array([4,5,6])]
- array([1, 2, 3, 0, 0, 4, 5, 6])
- """
- def __init__(self):
- MAxisConcatenator.__init__(self, 0)
- mr_ = mr_class()
- #####--------------------------------------------------------------------------
- #---- Find unmasked data ---
- #####--------------------------------------------------------------------------
- def flatnotmasked_edges(a):
- """
- Find the indices of the first and last unmasked values.
- Expects a 1-D `MaskedArray`, returns None if all values are masked.
- Parameters
- ----------
- a : array_like
- Input 1-D `MaskedArray`
- Returns
- -------
- edges : ndarray or None
- The indices of first and last non-masked value in the array.
- Returns None if all values are masked.
- See Also
- --------
- flatnotmasked_contiguous, notmasked_contiguous, notmasked_edges,
- clump_masked, clump_unmasked
- Notes
- -----
- Only accepts 1-D arrays.
- Examples
- --------
- >>> a = np.ma.arange(10)
- >>> flatnotmasked_edges(a)
- [0,-1]
- >>> mask = (a < 3) | (a > 8) | (a == 5)
- >>> a[mask] = np.ma.masked
- >>> np.array(a[~a.mask])
- array([3, 4, 6, 7, 8])
- >>> flatnotmasked_edges(a)
- array([3, 8])
- >>> a[:] = np.ma.masked
- >>> print(flatnotmasked_edges(ma))
- None
- """
- m = getmask(a)
- if m is nomask or not np.any(m):
- return np.array([0, a.size - 1])
- unmasked = np.flatnonzero(~m)
- if len(unmasked) > 0:
- return unmasked[[0, -1]]
- else:
- return None
- def notmasked_edges(a, axis=None):
- """
- Find the indices of the first and last unmasked values along an axis.
- If all values are masked, return None. Otherwise, return a list
- of two tuples, corresponding to the indices of the first and last
- unmasked values respectively.
- Parameters
- ----------
- a : array_like
- The input array.
- axis : int, optional
- Axis along which to perform the operation.
- If None (default), applies to a flattened version of the array.
- Returns
- -------
- edges : ndarray or list
- An array of start and end indexes if there are any masked data in
- the array. If there are no masked data in the array, `edges` is a
- list of the first and last index.
- See Also
- --------
- flatnotmasked_contiguous, flatnotmasked_edges, notmasked_contiguous,
- clump_masked, clump_unmasked
- Examples
- --------
- >>> a = np.arange(9).reshape((3, 3))
- >>> m = np.zeros_like(a)
- >>> m[1:, 1:] = 1
- >>> am = np.ma.array(a, mask=m)
- >>> np.array(am[~am.mask])
- array([0, 1, 2, 3, 6])
- >>> np.ma.notmasked_edges(ma)
- array([0, 6])
- """
- a = asarray(a)
- if axis is None or a.ndim == 1:
- return flatnotmasked_edges(a)
- m = getmaskarray(a)
- idx = array(np.indices(a.shape), mask=np.asarray([m] * a.ndim))
- return [tuple([idx[i].min(axis).compressed() for i in range(a.ndim)]),
- tuple([idx[i].max(axis).compressed() for i in range(a.ndim)]), ]
- def flatnotmasked_contiguous(a):
- """
- Find contiguous unmasked data in a masked array along the given axis.
- Parameters
- ----------
- a : narray
- The input array.
- Returns
- -------
- slice_list : list
- A sorted sequence of `slice` objects (start index, end index).
- ..versionchanged:: 1.15.0
- Now returns an empty list instead of None for a fully masked array
- See Also
- --------
- flatnotmasked_edges, notmasked_contiguous, notmasked_edges,
- clump_masked, clump_unmasked
- Notes
- -----
- Only accepts 2-D arrays at most.
- Examples
- --------
- >>> a = np.ma.arange(10)
- >>> np.ma.flatnotmasked_contiguous(a)
- [slice(0, 10, None)]
- >>> mask = (a < 3) | (a > 8) | (a == 5)
- >>> a[mask] = np.ma.masked
- >>> np.array(a[~a.mask])
- array([3, 4, 6, 7, 8])
- >>> np.ma.flatnotmasked_contiguous(a)
- [slice(3, 5, None), slice(6, 9, None)]
- >>> a[:] = np.ma.masked
- >>> np.ma.flatnotmasked_contiguous(a)
- []
- """
- m = getmask(a)
- if m is nomask:
- return [slice(0, a.size)]
- i = 0
- result = []
- for (k, g) in itertools.groupby(m.ravel()):
- n = len(list(g))
- if not k:
- result.append(slice(i, i + n))
- i += n
- return result
- def notmasked_contiguous(a, axis=None):
- """
- Find contiguous unmasked data in a masked array along the given axis.
- Parameters
- ----------
- a : array_like
- The input array.
- axis : int, optional
- Axis along which to perform the operation.
- If None (default), applies to a flattened version of the array, and this
- is the same as `flatnotmasked_contiguous`.
- Returns
- -------
- endpoints : list
- A list of slices (start and end indexes) of unmasked indexes
- in the array.
- If the input is 2d and axis is specified, the result is a list of lists.
- See Also
- --------
- flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges,
- clump_masked, clump_unmasked
- Notes
- -----
- Only accepts 2-D arrays at most.
- Examples
- --------
- >>> a = np.arange(12).reshape((3, 4))
- >>> mask = np.zeros_like(a)
- >>> mask[1:, :-1] = 1; mask[0, 1] = 1; mask[-1, 0] = 0
- >>> ma = np.ma.array(a, mask=mask)
- >>> ma
- masked_array(
- data=[[0, --, 2, 3],
- [--, --, --, 7],
- [8, --, --, 11]],
- mask=[[False, True, False, False],
- [ True, True, True, False],
- [False, True, True, False]],
- fill_value=999999)
- >>> np.array(ma[~ma.mask])
- array([ 0, 2, 3, 7, 8, 11])
- >>> np.ma.notmasked_contiguous(ma)
- [slice(0, 1, None), slice(2, 4, None), slice(7, 9, None), slice(11, 12, None)]
- >>> np.ma.notmasked_contiguous(ma, axis=0)
- [[slice(0, 1, None), slice(2, 3, None)], # column broken into two segments
- [], # fully masked column
- [slice(0, 1, None)],
- [slice(0, 3, None)]]
- >>> np.ma.notmasked_contiguous(ma, axis=1)
- [[slice(0, 1, None), slice(2, 4, None)], # row broken into two segments
- [slice(3, 4, None)],
- [slice(0, 1, None), slice(3, 4, None)]]
- """
- a = asarray(a)
- nd = a.ndim
- if nd > 2:
- raise NotImplementedError("Currently limited to atmost 2D array.")
- if axis is None or nd == 1:
- return flatnotmasked_contiguous(a)
- #
- result = []
- #
- other = (axis + 1) % 2
- idx = [0, 0]
- idx[axis] = slice(None, None)
- #
- for i in range(a.shape[other]):
- idx[other] = i
- result.append(flatnotmasked_contiguous(a[tuple(idx)]))
- return result
- def _ezclump(mask):
- """
- Finds the clumps (groups of data with the same values) for a 1D bool array.
- Returns a series of slices.
- """
- if mask.ndim > 1:
- mask = mask.ravel()
- idx = (mask[1:] ^ mask[:-1]).nonzero()
- idx = idx[0] + 1
- if mask[0]:
- if len(idx) == 0:
- return [slice(0, mask.size)]
- r = [slice(0, idx[0])]
- r.extend((slice(left, right)
- for left, right in zip(idx[1:-1:2], idx[2::2])))
- else:
- if len(idx) == 0:
- return []
- r = [slice(left, right) for left, right in zip(idx[:-1:2], idx[1::2])]
- if mask[-1]:
- r.append(slice(idx[-1], mask.size))
- return r
- def clump_unmasked(a):
- """
- Return list of slices corresponding to the unmasked clumps of a 1-D array.
- (A "clump" is defined as a contiguous region of the array).
- Parameters
- ----------
- a : ndarray
- A one-dimensional masked array.
- Returns
- -------
- slices : list of slice
- The list of slices, one for each continuous region of unmasked
- elements in `a`.
- Notes
- -----
- .. versionadded:: 1.4.0
- See Also
- --------
- flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges,
- notmasked_contiguous, clump_masked
- Examples
- --------
- >>> a = np.ma.masked_array(np.arange(10))
- >>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked
- >>> np.ma.clump_unmasked(a)
- [slice(3, 6, None), slice(7, 8, None)]
- """
- mask = getattr(a, '_mask', nomask)
- if mask is nomask:
- return [slice(0, a.size)]
- return _ezclump(~mask)
- def clump_masked(a):
- """
- Returns a list of slices corresponding to the masked clumps of a 1-D array.
- (A "clump" is defined as a contiguous region of the array).
- Parameters
- ----------
- a : ndarray
- A one-dimensional masked array.
- Returns
- -------
- slices : list of slice
- The list of slices, one for each continuous region of masked elements
- in `a`.
- Notes
- -----
- .. versionadded:: 1.4.0
- See Also
- --------
- flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges,
- notmasked_contiguous, clump_unmasked
- Examples
- --------
- >>> a = np.ma.masked_array(np.arange(10))
- >>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked
- >>> np.ma.clump_masked(a)
- [slice(0, 3, None), slice(6, 7, None), slice(8, 10, None)]
- """
- mask = ma.getmask(a)
- if mask is nomask:
- return []
- return _ezclump(mask)
- ###############################################################################
- # Polynomial fit #
- ###############################################################################
- def vander(x, n=None):
- """
- Masked values in the input array result in rows of zeros.
- """
- _vander = np.vander(x, n)
- m = getmask(x)
- if m is not nomask:
- _vander[m] = 0
- return _vander
- vander.__doc__ = ma.doc_note(np.vander.__doc__, vander.__doc__)
- def polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False):
- """
- Any masked values in x is propagated in y, and vice-versa.
- """
- x = asarray(x)
- y = asarray(y)
- m = getmask(x)
- if y.ndim == 1:
- m = mask_or(m, getmask(y))
- elif y.ndim == 2:
- my = getmask(mask_rows(y))
- if my is not nomask:
- m = mask_or(m, my[:, 0])
- else:
- raise TypeError("Expected a 1D or 2D array for y!")
- if w is not None:
- w = asarray(w)
- if w.ndim != 1:
- raise TypeError("expected a 1-d array for weights")
- if w.shape[0] != y.shape[0]:
- raise TypeError("expected w and y to have the same length")
- m = mask_or(m, getmask(w))
- if m is not nomask:
- not_m = ~m
- if w is not None:
- w = w[not_m]
- return np.polyfit(x[not_m], y[not_m], deg, rcond, full, w, cov)
- else:
- return np.polyfit(x, y, deg, rcond, full, w, cov)
- polyfit.__doc__ = ma.doc_note(np.polyfit.__doc__, polyfit.__doc__)
|