12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045 |
- """
- 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 $
- """
- __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_', 'ndenumerate',
- '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
- 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 : int or tuple of ints
- Shape of the required MaskedArray, e.g., ``(2, 3)`` or ``2``.
- 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,
- dtype=float64)
- 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,
- dtype=float32)
- 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:
- """
- 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.
- Parameters
- ----------
- None
- """
- npfunc = getattr(np, self.__name__, None)
- doc = getattr(npfunc, '__doc__', None)
- if doc:
- sig = self.__name__ + ma.get_object_signature(npfunc)
- doc = ma.doc_note(doc, "The function is applied to both the _data "
- "and the _mask, if any.")
- return '\n\n'.join((sig, doc))
- 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)
- 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 = np.ma.arange(24).reshape(2,3,4)
- >>> a[:,0,1] = np.ma.masked
- >>> a[:,1,:] = np.ma.masked
- >>> a
- masked_array(
- data=[[[0, --, 2, 3],
- [--, --, --, --],
- [8, 9, 10, 11]],
- [[12, --, 14, 15],
- [--, --, --, --],
- [20, 21, 22, 23]]],
- mask=[[[False, True, False, False],
- [ True, True, True, True],
- [False, False, False, False]],
- [[False, True, False, False],
- [ True, True, True, True],
- [False, False, False, False]]],
- fill_value=999999)
- >>> np.ma.apply_over_axes(np.ma.sum, a, [0,2])
- masked_array(
- data=[[[46],
- [--],
- [124]]],
- mask=[[[False],
- [ True],
- [False]]],
- fill_value=999999)
- Tuple axis arguments to ufuncs are equivalent:
- >>> np.ma.sum(a, axis=(0,2)).reshape((1,-1,1))
- masked_array(
- data=[[[46],
- [--],
- [124]]],
- mask=[[[False],
- [ True],
- [False]]],
- fill_value=999999)
- """
- def average(a, axis=None, weights=None, returned=False, *,
- keepdims=np._NoValue):
- """
- 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. The 1-D calculation is::
- avg = sum(a * weights) / sum(weights)
- The only constraint on `weights` is that `sum(weights)` must not be 0.
- 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.
- 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 original `a`.
- *Note:* `keepdims` will not work with instances of `numpy.matrix`
- or other classes whose methods do not support `keepdims`.
- .. versionadded:: 1.23.0
- 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)
- >>> x
- masked_array(
- data=[[0., 1.],
- [2., 3.],
- [4., 5.]],
- mask=False,
- fill_value=1e+20)
- >>> avg, sumweights = np.ma.average(x, axis=0, weights=[1, 2, 3],
- ... returned=True)
- >>> avg
- masked_array(data=[2.6666666666666665, 3.6666666666666665],
- mask=[False, False],
- fill_value=1e+20)
- With ``keepdims=True``, the following result has shape (3, 1).
- >>> np.ma.average(x, axis=1, keepdims=True)
- masked_array(
- data=[[0.5],
- [2.5],
- [4.5]],
- mask=False,
- fill_value=1e+20)
- """
- a = asarray(a)
- m = getmask(a)
- # inspired by 'average' in numpy/lib/function_base.py
- if keepdims is np._NoValue:
- # Don't pass on the keepdims argument if one wasn't given.
- keepdims_kw = {}
- else:
- keepdims_kw = {'keepdims': keepdims}
- if weights is None:
- avg = a.mean(axis, **keepdims_kw)
- scl = avg.dtype.type(a.count(axis))
- else:
- wgt = asarray(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, subok=True)
- wgt = wgt.swapaxes(-1, axis)
- if m is not nomask:
- wgt = wgt*(~a.mask)
- wgt.mask |= a.mask
- scl = wgt.sum(axis=axis, dtype=result_dtype, **keepdims_kw)
- avg = np.multiply(a, wgt,
- dtype=result_dtype).sum(axis, **keepdims_kw) / 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.0, 5.0],
- mask=[False, 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
- return _ureduce(a, func=_median, keepdims=keepdims, axis=axis, out=out,
- overwrite_input=overwrite_input)
- 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:
- 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)
- 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)
- 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
- `compress_rowcols` for details.
- See Also
- --------
- 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
- `compress_rowcols` for details.
- See Also
- --------
- 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=np._NoValue):
- """
- 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=1)
- >>> 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=1)
- """
- if axis is not np._NoValue:
- # remove the axis argument when this deprecation expires
- # NumPy 1.18.0, 2019-11-28
- warnings.warn(
- "The axis argument has always been ignored, in future passing it "
- "will raise TypeError", DeprecationWarning, stacklevel=2)
- return mask_rowcols(a, 0)
- def mask_cols(a, axis=np._NoValue):
- """
- 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=1)
- >>> 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=1)
- """
- if axis is not np._NoValue:
- # remove the axis argument when this deprecation expires
- # NumPy 1.18.0, 2019-11-28
- warnings.warn(
- "The axis argument has always been ignored, in future passing it "
- "will raise TypeError", DeprecationWarning, stacklevel=2)
- 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.
- Examples
- --------
- >>> import numpy.ma as ma
- >>> a = [1, 2, 1000, 2, 3]
- >>> mask = [0, 0, 1, 0, 0]
- >>> masked_a = ma.masked_array(a, mask)
- >>> masked_a
- masked_array(data=[1, 2, --, 2, 3],
- mask=[False, False, True, False, False],
- fill_value=999999)
- >>> ma.unique(masked_a)
- masked_array(data=[1, 2, 3, --],
- mask=[False, False, False, True],
- fill_value=999999)
- >>> ma.unique(masked_a, return_index=True)
- (masked_array(data=[1, 2, 3, --],
- mask=[False, False, False, True],
- fill_value=999999), array([0, 1, 4, 2]))
- >>> ma.unique(masked_a, return_inverse=True)
- (masked_array(data=[1, 2, 3, --],
- mask=[False, False, False, True],
- fill_value=999999), array([0, 1, 3, 1, 2]))
- >>> ma.unique(masked_a, return_index=True, return_inverse=True)
- (masked_array(data=[1, 2, 3, --],
- mask=[False, False, False, True],
- fill_value=999999), array([0, 1, 4, 2]), array([0, 1, 3, 1, 2]))
- """
- 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 = np.ma.array([1, 3, 3, 3], mask=[0, 0, 0, 1])
- >>> y = np.ma.array([3, 1, 1, 1], mask=[0, 0, 0, 1])
- >>> np.ma.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
- 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 : 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().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().__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])]
- masked_array(data=[1, 2, 3, ..., 4, 5, 6],
- mask=False,
- fill_value=999999)
- """
- def __init__(self):
- MAxisConcatenator.__init__(self, 0)
- mr_ = mr_class()
- #####--------------------------------------------------------------------------
- #---- Find unmasked data ---
- #####--------------------------------------------------------------------------
- def ndenumerate(a, compressed=True):
- """
- Multidimensional index iterator.
- Return an iterator yielding pairs of array coordinates and values,
- skipping elements that are masked. With `compressed=False`,
- `ma.masked` is yielded as the value of masked elements. This
- behavior differs from that of `numpy.ndenumerate`, which yields the
- value of the underlying data array.
- Notes
- -----
- .. versionadded:: 1.23.0
- Parameters
- ----------
- a : array_like
- An array with (possibly) masked elements.
- compressed : bool, optional
- If True (default), masked elements are skipped.
- See Also
- --------
- numpy.ndenumerate : Equivalent function ignoring any mask.
- Examples
- --------
- >>> a = np.ma.arange(9).reshape((3, 3))
- >>> a[1, 0] = np.ma.masked
- >>> a[1, 2] = np.ma.masked
- >>> a[2, 1] = np.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)
- >>> for index, x in np.ma.ndenumerate(a):
- ... print(index, x)
- (0, 0) 0
- (0, 1) 1
- (0, 2) 2
- (1, 1) 4
- (2, 0) 6
- (2, 2) 8
- >>> for index, x in np.ma.ndenumerate(a, compressed=False):
- ... print(index, x)
- (0, 0) 0
- (0, 1) 1
- (0, 2) 2
- (1, 0) --
- (1, 1) 4
- (1, 2) --
- (2, 0) 6
- (2, 1) --
- (2, 2) 8
- """
- for it, mask in zip(np.ndenumerate(a), getmaskarray(a).flat):
- if not mask:
- yield it
- elif not compressed:
- yield it[0], masked
- 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)
- >>> np.ma.flatnotmasked_edges(a)
- array([0, 9])
- >>> 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_edges(a)
- array([3, 8])
- >>> a[:] = np.ma.masked
- >>> print(np.ma.flatnotmasked_edges(a))
- 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(am)
- 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.
- Parameters
- ----------
- a : array_like
- 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)], [], [slice(0, 1, None)], [slice(0, 3, None)]]
- >>> np.ma.notmasked_contiguous(ma, axis=1)
- [[slice(0, 1, None), slice(2, 4, None)], [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 at most 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__)
|