|
""" |
|
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 |
|
) |
|
|
|
import numpy as np |
|
from numpy import ndarray, array as nxarray |
|
from numpy.lib.array_utils import normalize_axis_index, normalize_axis_tuple |
|
from numpy.lib._function_base_impl import _ureduce |
|
from numpy.lib._index_tricks_impl import AxisConcatenator |
|
from numpy._core.numeric import normalize_axis_tuple |
|
|
|
|
|
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 as np |
|
>>> a = np.arange(9).reshape((3,3)) |
|
>>> a = np.ma.array(a) |
|
>>> 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) |
|
>>> np.ma.count_masked(a) |
|
3 |
|
|
|
When the `axis` keyword is used an array is returned. |
|
|
|
>>> np.ma.count_masked(a, axis=0) |
|
array([1, 1, 1]) |
|
>>> np.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. |
|
|
|
Notes |
|
----- |
|
Unlike other masked array creation functions (e.g. `numpy.ma.zeros`, |
|
`numpy.ma.ones`, `numpy.ma.full`), `masked_all` does not initialize the |
|
values of the array, and may therefore be marginally faster. However, |
|
the values stored in the newly allocated array are arbitrary. For |
|
reproducible behavior, be sure to set each element of the array before |
|
reading. |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> np.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 = np.ma.masked_all((3, 3)) |
|
>>> a.dtype |
|
dtype('float64') |
|
>>> a = np.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. |
|
|
|
Notes |
|
----- |
|
Unlike other masked array creation functions (e.g. `numpy.ma.zeros_like`, |
|
`numpy.ma.ones_like`, `numpy.ma.full_like`), `masked_all_like` does not |
|
initialize the values of the array, and may therefore be marginally |
|
faster. However, the values stored in the newly allocated array are |
|
arbitrary. For reproducible behavior, be sure to set each element of the |
|
array before reading. |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> arr = np.zeros((2, 3), dtype=np.float32) |
|
>>> arr |
|
array([[0., 0., 0.], |
|
[0., 0., 0.]], dtype=float32) |
|
>>> np.ma.masked_all_like(arr) |
|
masked_array( |
|
data=[[--, --, --], |
|
[--, --, --]], |
|
mask=[[ True, True, True], |
|
[ True, True, True]], |
|
fill_value=np.float64(1e+20), |
|
dtype=float32) |
|
|
|
The dtype of the masked array matches the dtype of `arr`. |
|
|
|
>>> arr.dtype |
|
dtype('float32') |
|
>>> np.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 |
|
|
|
|
|
|
|
|
|
|
|
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 = ma.get_object_signature(npfunc) |
|
doc = ma.doc_note(doc, "The function is applied to both the _data " |
|
"and the _mask, if any.") |
|
if sig: |
|
sig = self.__name__ + sig + "\n\n" |
|
return 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) |
|
|
|
asscalar = np.isscalar(res) |
|
if not asscalar: |
|
try: |
|
len(res) |
|
except TypeError: |
|
asscalar = True |
|
|
|
|
|
|
|
dtypes = [] |
|
if asscalar: |
|
dtypes.append(np.asarray(res).dtype) |
|
outarr = zeros(outshape, object) |
|
outarr[tuple(ind)] = res |
|
Ntot = np.prod(outshape) |
|
k = 1 |
|
while k < Ntot: |
|
|
|
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.prod(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: |
|
|
|
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 |
|
-------- |
|
>>> import numpy as np |
|
>>> 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 : None or int or tuple of ints, optional |
|
Axis or axes along which to average `a`. The default, |
|
`axis=None`, will average over all of the elements of the input array. |
|
If axis is a tuple of ints, averaging is performed on all of the axes |
|
specified in the tuple instead of a single axis or all the axes as |
|
before. |
|
weights : array_like, optional |
|
An array of weights associated with the values in `a`. Each value in |
|
`a` contributes to the average according to its associated weight. |
|
The array of weights must be the same shape as `a` if no axis is |
|
specified, otherwise the weights must have dimensions and shape |
|
consistent with `a` along the specified axis. |
|
If `weights=None`, then all data in `a` are assumed to have a |
|
weight equal to one. |
|
The calculation is:: |
|
|
|
avg = sum(a * weights) / sum(weights) |
|
|
|
where the sum is over all included elements. |
|
The only constraint on the values of `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`. |
|
|
|
Raises |
|
------ |
|
ZeroDivisionError |
|
When all weights along axis are zero. See `numpy.ma.average` for a |
|
version robust to this type of error. |
|
TypeError |
|
When `weights` does not have the same shape as `a`, and `axis=None`. |
|
ValueError |
|
When `weights` does not have dimensions and shape consistent with `a` |
|
along specified `axis`. |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> 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) |
|
>>> data = np.arange(8).reshape((2, 2, 2)) |
|
>>> data |
|
array([[[0, 1], |
|
[2, 3]], |
|
[[4, 5], |
|
[6, 7]]]) |
|
>>> np.ma.average(data, axis=(0, 1), weights=[[1./4, 3./4], [1., 1./2]]) |
|
masked_array(data=[3.4, 4.4], |
|
mask=[False, False], |
|
fill_value=1e+20) |
|
>>> np.ma.average(data, axis=0, weights=[[1./4, 3./4], [1., 1./2]]) |
|
Traceback (most recent call last): |
|
... |
|
ValueError: Shape of weights must be consistent |
|
with shape of a along specified axis. |
|
|
|
>>> 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) |
|
|
|
if axis is not None: |
|
axis = normalize_axis_tuple(axis, a.ndim, argname="axis") |
|
|
|
if keepdims is np._NoValue: |
|
|
|
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) |
|
|
|
|
|
if a.shape != wgt.shape: |
|
if axis is None: |
|
raise TypeError( |
|
"Axis must be specified when shapes of a and weights " |
|
"differ.") |
|
if wgt.shape != tuple(a.shape[ax] for ax in axis): |
|
raise ValueError( |
|
"Shape of weights must be consistent with " |
|
"shape of a along specified axis.") |
|
|
|
|
|
wgt = wgt.transpose(np.argsort(axis)) |
|
wgt = wgt.reshape(tuple((s if ax in axis else 1) |
|
for ax, s in enumerate(a.shape))) |
|
|
|
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 |
|
-------- |
|
>>> import numpy as np |
|
>>> 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): |
|
|
|
|
|
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: |
|
|
|
|
|
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: |
|
|
|
s = mid.sum(out=out) |
|
if not odd: |
|
s = np.true_divide(s, 2., casting='safe', out=out) |
|
s = np.lib._utils_impl._median_nancheck(asorted, s, axis) |
|
else: |
|
s = mid.mean(out=out) |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
odd = counts % 2 == 1 |
|
l = np.where(odd, h, h-1) |
|
|
|
lh = np.concatenate([l,h], axis=axis) |
|
|
|
|
|
low_high = np.take_along_axis(asorted, lh, axis=axis) |
|
|
|
def replace_masked(s): |
|
|
|
|
|
|
|
|
|
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): |
|
|
|
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_impl._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. |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> arr = [[1, 2], [3, 4]] |
|
>>> mask = [[0, 1], [0, 0]] |
|
>>> x = np.ma.array(arr, mask=mask) |
|
>>> np.ma.compress_nd(x, axis=0) |
|
array([[3, 4]]) |
|
>>> np.ma.compress_nd(x, axis=1) |
|
array([[1], |
|
[3]]) |
|
>>> np.ma.compress_nd(x) |
|
array([[3]]) |
|
|
|
""" |
|
x = asarray(x) |
|
m = getmask(x) |
|
|
|
if axis is None: |
|
axis = tuple(range(x.ndim)) |
|
else: |
|
axis = normalize_axis_tuple(axis, x.ndim) |
|
|
|
|
|
if m is nomask or not m.any(): |
|
return x._data |
|
|
|
if m.all(): |
|
return nxarray([]) |
|
|
|
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 |
|
-------- |
|
>>> import numpy as np |
|
>>> 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. |
|
|
|
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. |
|
|
|
Returns |
|
------- |
|
compressed_array : ndarray |
|
The compressed array. |
|
|
|
See Also |
|
-------- |
|
compress_rowcols |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> a = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0], |
|
... [1, 0, 0], |
|
... [0, 0, 0]]) |
|
>>> np.ma.compress_rows(a) |
|
array([[6, 7, 8]]) |
|
|
|
""" |
|
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. |
|
|
|
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. |
|
|
|
Returns |
|
------- |
|
compressed_array : ndarray |
|
The compressed array. |
|
|
|
See Also |
|
-------- |
|
compress_rowcols |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> a = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0], |
|
... [1, 0, 0], |
|
... [0, 0, 0]]) |
|
>>> np.ma.compress_cols(a) |
|
array([[1, 2], |
|
[4, 5], |
|
[7, 8]]) |
|
|
|
""" |
|
a = asarray(a) |
|
if a.ndim != 2: |
|
raise NotImplementedError("compress_cols works for 2D arrays only.") |
|
return compress_rowcols(a, 1) |
|
|
|
|
|
def mask_rowcols(a, axis=None): |
|
""" |
|
Mask rows and/or columns of a 2D array that contain masked values. |
|
|
|
Mask whole rows and/or columns of a 2D array that contain |
|
masked values. The masking behavior is selected using the |
|
`axis` parameter. |
|
|
|
- If `axis` is None, rows *and* columns are masked. |
|
- If `axis` is 0, only rows are masked. |
|
- If `axis` is 1 or -1, only columns are masked. |
|
|
|
Parameters |
|
---------- |
|
a : array_like, MaskedArray |
|
The array to mask. If not a MaskedArray instance (or if no array |
|
elements are masked), the result is a MaskedArray with `mask` set |
|
to `nomask` (False). Must be a 2D array. |
|
axis : int, optional |
|
Axis along which to perform the operation. If None, applies to a |
|
flattened version of the array. |
|
|
|
Returns |
|
------- |
|
a : MaskedArray |
|
A modified version of the input array, masked depending on the value |
|
of the `axis` parameter. |
|
|
|
Raises |
|
------ |
|
NotImplementedError |
|
If input array `a` is not 2D. |
|
|
|
See Also |
|
-------- |
|
mask_rows : Mask rows of a 2D array that contain masked values. |
|
mask_cols : Mask cols of a 2D array that contain masked values. |
|
masked_where : Mask where a condition is met. |
|
|
|
Notes |
|
----- |
|
The input array's mask is modified by this function. |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> a = np.zeros((3, 3), dtype=int) |
|
>>> a[1, 1] = 1 |
|
>>> a |
|
array([[0, 0, 0], |
|
[0, 1, 0], |
|
[0, 0, 0]]) |
|
>>> a = np.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) |
|
>>> np.ma.mask_rowcols(a) |
|
masked_array( |
|
data=[[0, --, 0], |
|
[--, --, --], |
|
[0, --, 0]], |
|
mask=[[False, True, False], |
|
[ True, True, True], |
|
[False, True, False]], |
|
fill_value=1) |
|
|
|
""" |
|
a = array(a, subok=False) |
|
if a.ndim != 2: |
|
raise NotImplementedError("mask_rowcols works for 2D arrays only.") |
|
m = getmask(a) |
|
|
|
if m is nomask or not m.any(): |
|
return a |
|
maskedval = m.nonzero() |
|
a._mask = a._mask.copy() |
|
if not axis: |
|
a[np.unique(maskedval[0])] = masked |
|
if axis in [None, 1, -1]: |
|
a[:, np.unique(maskedval[1])] = masked |
|
return a |
|
|
|
|
|
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 as np |
|
>>> a = np.zeros((3, 3), dtype=int) |
|
>>> a[1, 1] = 1 |
|
>>> a |
|
array([[0, 0, 0], |
|
[0, 1, 0], |
|
[0, 0, 0]]) |
|
>>> a = np.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) |
|
|
|
>>> np.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: |
|
|
|
|
|
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 as np |
|
>>> a = np.zeros((3, 3), dtype=int) |
|
>>> a[1, 1] = 1 |
|
>>> a |
|
array([[0, 0, 0], |
|
[0, 1, 0], |
|
[0, 0, 0]]) |
|
>>> a = np.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) |
|
>>> np.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: |
|
|
|
|
|
warnings.warn( |
|
"The axis argument has always been ignored, in future passing it " |
|
"will raise TypeError", DeprecationWarning, stacklevel=2) |
|
return mask_rowcols(a, 1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
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. |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> arr = np.ma.array([1, 2, 4, 7, 0]) |
|
>>> np.ma.ediff1d(arr) |
|
masked_array(data=[ 1, 2, 3, -7], |
|
mask=False, |
|
fill_value=999999) |
|
|
|
""" |
|
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: |
|
|
|
|
|
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 as np |
|
>>> a = [1, 2, 1000, 2, 3] |
|
>>> mask = [0, 0, 1, 0, 0] |
|
>>> masked_a = np.ma.masked_array(a, mask) |
|
>>> masked_a |
|
masked_array(data=[1, 2, --, 2, 3], |
|
mask=[False, False, True, False, False], |
|
fill_value=999999) |
|
>>> np.ma.unique(masked_a) |
|
masked_array(data=[1, 2, 3, --], |
|
mask=[False, False, False, True], |
|
fill_value=999999) |
|
>>> np.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])) |
|
>>> np.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])) |
|
>>> np.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 |
|
-------- |
|
>>> import numpy as np |
|
>>> 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: |
|
|
|
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. |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> ar1 = np.ma.array([1, 2, 3, 2, 4]) |
|
>>> ar2 = np.ma.array([2, 3, 5, 7, 5]) |
|
>>> np.ma.setxor1d(ar1, ar2) |
|
masked_array(data=[1, 4, 5, 7], |
|
mask=False, |
|
fill_value=999999) |
|
|
|
""" |
|
if not assume_unique: |
|
ar1 = unique(ar1) |
|
ar2 = unique(ar2) |
|
|
|
aux = ma.concatenate((ar1, ar2), axis=None) |
|
if aux.size == 0: |
|
return aux |
|
aux.sort() |
|
auxf = aux.filled() |
|
|
|
flag = ma.concatenate(([True], (auxf[1:] != auxf[:-1]), [True])) |
|
|
|
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 |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> ar1 = np.ma.array([0, 1, 2, 5, 0]) |
|
>>> ar2 = [0, 2] |
|
>>> np.ma.in1d(ar1, ar2) |
|
masked_array(data=[ True, False, True, False, True], |
|
mask=False, |
|
fill_value=True) |
|
|
|
""" |
|
if not assume_unique: |
|
ar1, rev_idx = unique(ar1, return_inverse=True) |
|
ar2 = unique(ar2) |
|
|
|
ar = ma.concatenate((ar1, ar2)) |
|
|
|
|
|
|
|
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 |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> element = np.ma.array([1, 2, 3, 4, 5, 6]) |
|
>>> test_elements = [0, 2] |
|
>>> np.ma.isin(element, test_elements) |
|
masked_array(data=[False, True, False, False, False, False], |
|
mask=False, |
|
fill_value=True) |
|
|
|
""" |
|
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. |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> ar1 = np.ma.array([1, 2, 3, 4]) |
|
>>> ar2 = np.ma.array([3, 4, 5, 6]) |
|
>>> np.ma.union1d(ar1, ar2) |
|
masked_array(data=[1, 2, 3, 4, 5, 6], |
|
mask=False, |
|
fill_value=999999) |
|
|
|
""" |
|
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 |
|
-------- |
|
>>> import numpy as np |
|
>>> 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)] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) |
|
|
|
if not allow_masked and xmask.any(): |
|
raise ValueError("Cannot process masked data.") |
|
|
|
if x.shape[0] == 1: |
|
rowvar = True |
|
|
|
rowvar = int(bool(rowvar)) |
|
axis = 1 - rowvar |
|
if rowvar: |
|
tup = (slice(None), None) |
|
else: |
|
tup = (None, slice(None)) |
|
|
|
if y is None: |
|
|
|
|
|
|
|
if x.shape[0] > 2 ** 24 or x.shape[1] > 2 ** 24: |
|
xnm_dtype = np.float64 |
|
else: |
|
xnm_dtype = np.float32 |
|
xnotmask = np.logical_not(xmask).astype(xnm_dtype) |
|
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: |
|
|
|
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) |
|
|
|
|
|
|
|
if x.shape[0] > 2 ** 24 or x.shape[1] > 2 ** 24: |
|
xnm_dtype = np.float64 |
|
else: |
|
xnm_dtype = np.float32 |
|
xnotmask = np.logical_not(np.concatenate((xmask, ymask), axis)).astype( |
|
xnm_dtype |
|
) |
|
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 |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> x = np.ma.array([[0, 1], [1, 1]], mask=[0, 1, 0, 1]) |
|
>>> y = np.ma.array([[1, 0], [0, 1]], mask=[0, 0, 1, 1]) |
|
>>> np.ma.cov(x, y) |
|
masked_array( |
|
data=[[--, --, --, --], |
|
[--, --, --, --], |
|
[--, --, --, --], |
|
[--, --, --, --]], |
|
mask=[[ True, True, True, True], |
|
[ True, True, True, True], |
|
[ True, True, True, True], |
|
[ True, True, True, True]], |
|
fill_value=1e+20, |
|
dtype=float64) |
|
|
|
""" |
|
|
|
if ddof is not None and ddof != int(ddof): |
|
raise ValueError("ddof must be an integer") |
|
|
|
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) - ddof |
|
mask = np.less_equal(fact, 0, dtype=bool) |
|
with np.errstate(divide="ignore", invalid="ignore"): |
|
data = np.dot(filled(x.T, 0), filled(x.conj(), 0)) / fact |
|
result = ma.array(data, mask=mask).squeeze() |
|
else: |
|
fact = np.dot(xnotmask, xnotmask.T) - ddof |
|
mask = np.less_equal(fact, 0, dtype=bool) |
|
with np.errstate(divide="ignore", invalid="ignore"): |
|
data = np.dot(filled(x, 0), filled(x.T.conj(), 0)) / fact |
|
result = ma.array(data, mask=mask).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. |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> x = np.ma.array([[0, 1], [1, 1]], mask=[0, 1, 0, 1]) |
|
>>> np.ma.corrcoef(x) |
|
masked_array( |
|
data=[[--, --], |
|
[--, --]], |
|
mask=[[ True, True], |
|
[ True, True]], |
|
fill_value=1e+20, |
|
dtype=float64) |
|
|
|
""" |
|
msg = 'bias and ddof have no effect and are deprecated' |
|
if bias is not np._NoValue or ddof is not np._NoValue: |
|
|
|
warnings.warn(msg, DeprecationWarning, stacklevel=2) |
|
|
|
corr = cov(x, y, rowvar, allow_masked=allow_masked) |
|
|
|
try: |
|
std = ma.sqrt(ma.diagonal(corr)) |
|
except ValueError: |
|
return ma.MaskedConstant() |
|
corr /= ma.multiply.outer(std, std) |
|
return corr |
|
|
|
|
|
|
|
|
|
|
|
class MAxisConcatenator(AxisConcatenator): |
|
""" |
|
Translate slice objects to concatenation along an axis. |
|
|
|
For documentation on usage, see `mr_class`. |
|
|
|
See Also |
|
-------- |
|
mr_class |
|
|
|
""" |
|
__slots__ = () |
|
|
|
concatenate = staticmethod(concatenate) |
|
|
|
@classmethod |
|
def makemat(cls, arr): |
|
|
|
|
|
|
|
|
|
data = super().makemat(arr.data, copy=False) |
|
return array(data, mask=arr.mask) |
|
|
|
def __getitem__(self, key): |
|
|
|
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 `r_`. |
|
|
|
See Also |
|
-------- |
|
r_ |
|
|
|
Examples |
|
-------- |
|
>>> import numpy as np |
|
>>> 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) |
|
|
|
""" |
|
__slots__ = () |
|
|
|
def __init__(self): |
|
MAxisConcatenator.__init__(self, 0) |
|
|
|
mr_ = mr_class() |
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
|
-------- |
|
>>> import numpy as np |
|
>>> 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 |
|
-------- |
|
>>> import numpy as np |
|
>>> 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 |
|
-------- |
|
>>> import numpy as np |
|
>>> 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 |
|
-------- |
|
>>> import numpy as np |
|
>>> 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 |
|
-------- |
|
>>> import numpy as np |
|
>>> 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 |
|
-------- |
|
>>> import numpy as np |
|
>>> 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 |
|
-------- |
|
>>> import numpy as np |
|
>>> 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) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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__) |
|
|