Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wiseplat
GitHub Repository: wiseplat/python-code
Path: blob/master/ invest-robot-contest_TinkoffBotTwitch-main/venv/lib/python3.8/site-packages/numpy/ma/extras.py
7763 views
1
"""
2
Masked arrays add-ons.
3
4
A collection of utilities for `numpy.ma`.
5
6
:author: Pierre Gerard-Marchant
7
:contact: pierregm_at_uga_dot_edu
8
:version: $Id: extras.py 3473 2007-10-29 15:18:13Z jarrod.millman $
9
10
"""
11
__all__ = [
12
'apply_along_axis', 'apply_over_axes', 'atleast_1d', 'atleast_2d',
13
'atleast_3d', 'average', 'clump_masked', 'clump_unmasked',
14
'column_stack', 'compress_cols', 'compress_nd', 'compress_rowcols',
15
'compress_rows', 'count_masked', 'corrcoef', 'cov', 'diagflat', 'dot',
16
'dstack', 'ediff1d', 'flatnotmasked_contiguous', 'flatnotmasked_edges',
17
'hsplit', 'hstack', 'isin', 'in1d', 'intersect1d', 'mask_cols', 'mask_rowcols',
18
'mask_rows', 'masked_all', 'masked_all_like', 'median', 'mr_',
19
'notmasked_contiguous', 'notmasked_edges', 'polyfit', 'row_stack',
20
'setdiff1d', 'setxor1d', 'stack', 'unique', 'union1d', 'vander', 'vstack',
21
]
22
23
import itertools
24
import warnings
25
26
from . import core as ma
27
from .core import (
28
MaskedArray, MAError, add, array, asarray, concatenate, filled, count,
29
getmask, getmaskarray, make_mask_descr, masked, masked_array, mask_or,
30
nomask, ones, sort, zeros, getdata, get_masked_subclass, dot,
31
mask_rowcols
32
)
33
34
import numpy as np
35
from numpy import ndarray, array as nxarray
36
from numpy.core.multiarray import normalize_axis_index
37
from numpy.core.numeric import normalize_axis_tuple
38
from numpy.lib.function_base import _ureduce
39
from numpy.lib.index_tricks import AxisConcatenator
40
41
42
def issequence(seq):
43
"""
44
Is seq a sequence (ndarray, list or tuple)?
45
46
"""
47
return isinstance(seq, (ndarray, tuple, list))
48
49
50
def count_masked(arr, axis=None):
51
"""
52
Count the number of masked elements along the given axis.
53
54
Parameters
55
----------
56
arr : array_like
57
An array with (possibly) masked elements.
58
axis : int, optional
59
Axis along which to count. If None (default), a flattened
60
version of the array is used.
61
62
Returns
63
-------
64
count : int, ndarray
65
The total number of masked elements (axis=None) or the number
66
of masked elements along each slice of the given axis.
67
68
See Also
69
--------
70
MaskedArray.count : Count non-masked elements.
71
72
Examples
73
--------
74
>>> import numpy.ma as ma
75
>>> a = np.arange(9).reshape((3,3))
76
>>> a = ma.array(a)
77
>>> a[1, 0] = ma.masked
78
>>> a[1, 2] = ma.masked
79
>>> a[2, 1] = ma.masked
80
>>> a
81
masked_array(
82
data=[[0, 1, 2],
83
[--, 4, --],
84
[6, --, 8]],
85
mask=[[False, False, False],
86
[ True, False, True],
87
[False, True, False]],
88
fill_value=999999)
89
>>> ma.count_masked(a)
90
3
91
92
When the `axis` keyword is used an array is returned.
93
94
>>> ma.count_masked(a, axis=0)
95
array([1, 1, 1])
96
>>> ma.count_masked(a, axis=1)
97
array([0, 2, 1])
98
99
"""
100
m = getmaskarray(arr)
101
return m.sum(axis)
102
103
104
def masked_all(shape, dtype=float):
105
"""
106
Empty masked array with all elements masked.
107
108
Return an empty masked array of the given shape and dtype, where all the
109
data are masked.
110
111
Parameters
112
----------
113
shape : tuple
114
Shape of the required MaskedArray.
115
dtype : dtype, optional
116
Data type of the output.
117
118
Returns
119
-------
120
a : MaskedArray
121
A masked array with all data masked.
122
123
See Also
124
--------
125
masked_all_like : Empty masked array modelled on an existing array.
126
127
Examples
128
--------
129
>>> import numpy.ma as ma
130
>>> ma.masked_all((3, 3))
131
masked_array(
132
data=[[--, --, --],
133
[--, --, --],
134
[--, --, --]],
135
mask=[[ True, True, True],
136
[ True, True, True],
137
[ True, True, True]],
138
fill_value=1e+20,
139
dtype=float64)
140
141
The `dtype` parameter defines the underlying data type.
142
143
>>> a = ma.masked_all((3, 3))
144
>>> a.dtype
145
dtype('float64')
146
>>> a = ma.masked_all((3, 3), dtype=np.int32)
147
>>> a.dtype
148
dtype('int32')
149
150
"""
151
a = masked_array(np.empty(shape, dtype),
152
mask=np.ones(shape, make_mask_descr(dtype)))
153
return a
154
155
156
def masked_all_like(arr):
157
"""
158
Empty masked array with the properties of an existing array.
159
160
Return an empty masked array of the same shape and dtype as
161
the array `arr`, where all the data are masked.
162
163
Parameters
164
----------
165
arr : ndarray
166
An array describing the shape and dtype of the required MaskedArray.
167
168
Returns
169
-------
170
a : MaskedArray
171
A masked array with all data masked.
172
173
Raises
174
------
175
AttributeError
176
If `arr` doesn't have a shape attribute (i.e. not an ndarray)
177
178
See Also
179
--------
180
masked_all : Empty masked array with all elements masked.
181
182
Examples
183
--------
184
>>> import numpy.ma as ma
185
>>> arr = np.zeros((2, 3), dtype=np.float32)
186
>>> arr
187
array([[0., 0., 0.],
188
[0., 0., 0.]], dtype=float32)
189
>>> ma.masked_all_like(arr)
190
masked_array(
191
data=[[--, --, --],
192
[--, --, --]],
193
mask=[[ True, True, True],
194
[ True, True, True]],
195
fill_value=1e+20,
196
dtype=float32)
197
198
The dtype of the masked array matches the dtype of `arr`.
199
200
>>> arr.dtype
201
dtype('float32')
202
>>> ma.masked_all_like(arr).dtype
203
dtype('float32')
204
205
"""
206
a = np.empty_like(arr).view(MaskedArray)
207
a._mask = np.ones(a.shape, dtype=make_mask_descr(a.dtype))
208
return a
209
210
211
#####--------------------------------------------------------------------------
212
#---- --- Standard functions ---
213
#####--------------------------------------------------------------------------
214
class _fromnxfunction:
215
"""
216
Defines a wrapper to adapt NumPy functions to masked arrays.
217
218
219
An instance of `_fromnxfunction` can be called with the same parameters
220
as the wrapped NumPy function. The docstring of `newfunc` is adapted from
221
the wrapped function as well, see `getdoc`.
222
223
This class should not be used directly. Instead, one of its extensions that
224
provides support for a specific type of input should be used.
225
226
Parameters
227
----------
228
funcname : str
229
The name of the function to be adapted. The function should be
230
in the NumPy namespace (i.e. ``np.funcname``).
231
232
"""
233
234
def __init__(self, funcname):
235
self.__name__ = funcname
236
self.__doc__ = self.getdoc()
237
238
def getdoc(self):
239
"""
240
Retrieve the docstring and signature from the function.
241
242
The ``__doc__`` attribute of the function is used as the docstring for
243
the new masked array version of the function. A note on application
244
of the function to the mask is appended.
245
246
Parameters
247
----------
248
None
249
250
"""
251
npfunc = getattr(np, self.__name__, None)
252
doc = getattr(npfunc, '__doc__', None)
253
if doc:
254
sig = self.__name__ + ma.get_object_signature(npfunc)
255
doc = ma.doc_note(doc, "The function is applied to both the _data "
256
"and the _mask, if any.")
257
return '\n\n'.join((sig, doc))
258
return
259
260
def __call__(self, *args, **params):
261
pass
262
263
264
class _fromnxfunction_single(_fromnxfunction):
265
"""
266
A version of `_fromnxfunction` that is called with a single array
267
argument followed by auxiliary args that are passed verbatim for
268
both the data and mask calls.
269
"""
270
def __call__(self, x, *args, **params):
271
func = getattr(np, self.__name__)
272
if isinstance(x, ndarray):
273
_d = func(x.__array__(), *args, **params)
274
_m = func(getmaskarray(x), *args, **params)
275
return masked_array(_d, mask=_m)
276
else:
277
_d = func(np.asarray(x), *args, **params)
278
_m = func(getmaskarray(x), *args, **params)
279
return masked_array(_d, mask=_m)
280
281
282
class _fromnxfunction_seq(_fromnxfunction):
283
"""
284
A version of `_fromnxfunction` that is called with a single sequence
285
of arrays followed by auxiliary args that are passed verbatim for
286
both the data and mask calls.
287
"""
288
def __call__(self, x, *args, **params):
289
func = getattr(np, self.__name__)
290
_d = func(tuple([np.asarray(a) for a in x]), *args, **params)
291
_m = func(tuple([getmaskarray(a) for a in x]), *args, **params)
292
return masked_array(_d, mask=_m)
293
294
295
class _fromnxfunction_args(_fromnxfunction):
296
"""
297
A version of `_fromnxfunction` that is called with multiple array
298
arguments. The first non-array-like input marks the beginning of the
299
arguments that are passed verbatim for both the data and mask calls.
300
Array arguments are processed independently and the results are
301
returned in a list. If only one array is found, the return value is
302
just the processed array instead of a list.
303
"""
304
def __call__(self, *args, **params):
305
func = getattr(np, self.__name__)
306
arrays = []
307
args = list(args)
308
while len(args) > 0 and issequence(args[0]):
309
arrays.append(args.pop(0))
310
res = []
311
for x in arrays:
312
_d = func(np.asarray(x), *args, **params)
313
_m = func(getmaskarray(x), *args, **params)
314
res.append(masked_array(_d, mask=_m))
315
if len(arrays) == 1:
316
return res[0]
317
return res
318
319
320
class _fromnxfunction_allargs(_fromnxfunction):
321
"""
322
A version of `_fromnxfunction` that is called with multiple array
323
arguments. Similar to `_fromnxfunction_args` except that all args
324
are converted to arrays even if they are not so already. This makes
325
it possible to process scalars as 1-D arrays. Only keyword arguments
326
are passed through verbatim for the data and mask calls. Arrays
327
arguments are processed independently and the results are returned
328
in a list. If only one arg is present, the return value is just the
329
processed array instead of a list.
330
"""
331
def __call__(self, *args, **params):
332
func = getattr(np, self.__name__)
333
res = []
334
for x in args:
335
_d = func(np.asarray(x), **params)
336
_m = func(getmaskarray(x), **params)
337
res.append(masked_array(_d, mask=_m))
338
if len(args) == 1:
339
return res[0]
340
return res
341
342
343
atleast_1d = _fromnxfunction_allargs('atleast_1d')
344
atleast_2d = _fromnxfunction_allargs('atleast_2d')
345
atleast_3d = _fromnxfunction_allargs('atleast_3d')
346
347
vstack = row_stack = _fromnxfunction_seq('vstack')
348
hstack = _fromnxfunction_seq('hstack')
349
column_stack = _fromnxfunction_seq('column_stack')
350
dstack = _fromnxfunction_seq('dstack')
351
stack = _fromnxfunction_seq('stack')
352
353
hsplit = _fromnxfunction_single('hsplit')
354
355
diagflat = _fromnxfunction_single('diagflat')
356
357
358
#####--------------------------------------------------------------------------
359
#----
360
#####--------------------------------------------------------------------------
361
def flatten_inplace(seq):
362
"""Flatten a sequence in place."""
363
k = 0
364
while (k != len(seq)):
365
while hasattr(seq[k], '__iter__'):
366
seq[k:(k + 1)] = seq[k]
367
k += 1
368
return seq
369
370
371
def apply_along_axis(func1d, axis, arr, *args, **kwargs):
372
"""
373
(This docstring should be overwritten)
374
"""
375
arr = array(arr, copy=False, subok=True)
376
nd = arr.ndim
377
axis = normalize_axis_index(axis, nd)
378
ind = [0] * (nd - 1)
379
i = np.zeros(nd, 'O')
380
indlist = list(range(nd))
381
indlist.remove(axis)
382
i[axis] = slice(None, None)
383
outshape = np.asarray(arr.shape).take(indlist)
384
i.put(indlist, ind)
385
res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
386
# if res is a number, then we have a smaller output array
387
asscalar = np.isscalar(res)
388
if not asscalar:
389
try:
390
len(res)
391
except TypeError:
392
asscalar = True
393
# Note: we shouldn't set the dtype of the output from the first result
394
# so we force the type to object, and build a list of dtypes. We'll
395
# just take the largest, to avoid some downcasting
396
dtypes = []
397
if asscalar:
398
dtypes.append(np.asarray(res).dtype)
399
outarr = zeros(outshape, object)
400
outarr[tuple(ind)] = res
401
Ntot = np.product(outshape)
402
k = 1
403
while k < Ntot:
404
# increment the index
405
ind[-1] += 1
406
n = -1
407
while (ind[n] >= outshape[n]) and (n > (1 - nd)):
408
ind[n - 1] += 1
409
ind[n] = 0
410
n -= 1
411
i.put(indlist, ind)
412
res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
413
outarr[tuple(ind)] = res
414
dtypes.append(asarray(res).dtype)
415
k += 1
416
else:
417
res = array(res, copy=False, subok=True)
418
j = i.copy()
419
j[axis] = ([slice(None, None)] * res.ndim)
420
j.put(indlist, ind)
421
Ntot = np.product(outshape)
422
holdshape = outshape
423
outshape = list(arr.shape)
424
outshape[axis] = res.shape
425
dtypes.append(asarray(res).dtype)
426
outshape = flatten_inplace(outshape)
427
outarr = zeros(outshape, object)
428
outarr[tuple(flatten_inplace(j.tolist()))] = res
429
k = 1
430
while k < Ntot:
431
# increment the index
432
ind[-1] += 1
433
n = -1
434
while (ind[n] >= holdshape[n]) and (n > (1 - nd)):
435
ind[n - 1] += 1
436
ind[n] = 0
437
n -= 1
438
i.put(indlist, ind)
439
j.put(indlist, ind)
440
res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
441
outarr[tuple(flatten_inplace(j.tolist()))] = res
442
dtypes.append(asarray(res).dtype)
443
k += 1
444
max_dtypes = np.dtype(np.asarray(dtypes).max())
445
if not hasattr(arr, '_mask'):
446
result = np.asarray(outarr, dtype=max_dtypes)
447
else:
448
result = asarray(outarr, dtype=max_dtypes)
449
result.fill_value = ma.default_fill_value(result)
450
return result
451
apply_along_axis.__doc__ = np.apply_along_axis.__doc__
452
453
454
def apply_over_axes(func, a, axes):
455
"""
456
(This docstring will be overwritten)
457
"""
458
val = asarray(a)
459
N = a.ndim
460
if array(axes).ndim == 0:
461
axes = (axes,)
462
for axis in axes:
463
if axis < 0:
464
axis = N + axis
465
args = (val, axis)
466
res = func(*args)
467
if res.ndim == val.ndim:
468
val = res
469
else:
470
res = ma.expand_dims(res, axis)
471
if res.ndim == val.ndim:
472
val = res
473
else:
474
raise ValueError("function is not returning "
475
"an array of the correct shape")
476
return val
477
478
if apply_over_axes.__doc__ is not None:
479
apply_over_axes.__doc__ = np.apply_over_axes.__doc__[
480
:np.apply_over_axes.__doc__.find('Notes')].rstrip() + \
481
"""
482
483
Examples
484
--------
485
>>> a = np.ma.arange(24).reshape(2,3,4)
486
>>> a[:,0,1] = np.ma.masked
487
>>> a[:,1,:] = np.ma.masked
488
>>> a
489
masked_array(
490
data=[[[0, --, 2, 3],
491
[--, --, --, --],
492
[8, 9, 10, 11]],
493
[[12, --, 14, 15],
494
[--, --, --, --],
495
[20, 21, 22, 23]]],
496
mask=[[[False, True, False, False],
497
[ True, True, True, True],
498
[False, False, False, False]],
499
[[False, True, False, False],
500
[ True, True, True, True],
501
[False, False, False, False]]],
502
fill_value=999999)
503
>>> np.ma.apply_over_axes(np.ma.sum, a, [0,2])
504
masked_array(
505
data=[[[46],
506
[--],
507
[124]]],
508
mask=[[[False],
509
[ True],
510
[False]]],
511
fill_value=999999)
512
513
Tuple axis arguments to ufuncs are equivalent:
514
515
>>> np.ma.sum(a, axis=(0,2)).reshape((1,-1,1))
516
masked_array(
517
data=[[[46],
518
[--],
519
[124]]],
520
mask=[[[False],
521
[ True],
522
[False]]],
523
fill_value=999999)
524
"""
525
526
527
def average(a, axis=None, weights=None, returned=False):
528
"""
529
Return the weighted average of array over the given axis.
530
531
Parameters
532
----------
533
a : array_like
534
Data to be averaged.
535
Masked entries are not taken into account in the computation.
536
axis : int, optional
537
Axis along which to average `a`. If None, averaging is done over
538
the flattened array.
539
weights : array_like, optional
540
The importance that each element has in the computation of the average.
541
The weights array can either be 1-D (in which case its length must be
542
the size of `a` along the given axis) or of the same shape as `a`.
543
If ``weights=None``, then all data in `a` are assumed to have a
544
weight equal to one. The 1-D calculation is::
545
546
avg = sum(a * weights) / sum(weights)
547
548
The only constraint on `weights` is that `sum(weights)` must not be 0.
549
returned : bool, optional
550
Flag indicating whether a tuple ``(result, sum of weights)``
551
should be returned as output (True), or just the result (False).
552
Default is False.
553
554
Returns
555
-------
556
average, [sum_of_weights] : (tuple of) scalar or MaskedArray
557
The average along the specified axis. When returned is `True`,
558
return a tuple with the average as the first element and the sum
559
of the weights as the second element. The return type is `np.float64`
560
if `a` is of integer type and floats smaller than `float64`, or the
561
input data-type, otherwise. If returned, `sum_of_weights` is always
562
`float64`.
563
564
Examples
565
--------
566
>>> a = np.ma.array([1., 2., 3., 4.], mask=[False, False, True, True])
567
>>> np.ma.average(a, weights=[3, 1, 0, 0])
568
1.25
569
570
>>> x = np.ma.arange(6.).reshape(3, 2)
571
>>> x
572
masked_array(
573
data=[[0., 1.],
574
[2., 3.],
575
[4., 5.]],
576
mask=False,
577
fill_value=1e+20)
578
>>> avg, sumweights = np.ma.average(x, axis=0, weights=[1, 2, 3],
579
... returned=True)
580
>>> avg
581
masked_array(data=[2.6666666666666665, 3.6666666666666665],
582
mask=[False, False],
583
fill_value=1e+20)
584
585
"""
586
a = asarray(a)
587
m = getmask(a)
588
589
# inspired by 'average' in numpy/lib/function_base.py
590
591
if weights is None:
592
avg = a.mean(axis)
593
scl = avg.dtype.type(a.count(axis))
594
else:
595
wgt = np.asanyarray(weights)
596
597
if issubclass(a.dtype.type, (np.integer, np.bool_)):
598
result_dtype = np.result_type(a.dtype, wgt.dtype, 'f8')
599
else:
600
result_dtype = np.result_type(a.dtype, wgt.dtype)
601
602
# Sanity checks
603
if a.shape != wgt.shape:
604
if axis is None:
605
raise TypeError(
606
"Axis must be specified when shapes of a and weights "
607
"differ.")
608
if wgt.ndim != 1:
609
raise TypeError(
610
"1D weights expected when shapes of a and weights differ.")
611
if wgt.shape[0] != a.shape[axis]:
612
raise ValueError(
613
"Length of weights not compatible with specified axis.")
614
615
# setup wgt to broadcast along axis
616
wgt = np.broadcast_to(wgt, (a.ndim-1)*(1,) + wgt.shape, subok=True)
617
wgt = wgt.swapaxes(-1, axis)
618
619
if m is not nomask:
620
wgt = wgt*(~a.mask)
621
622
scl = wgt.sum(axis=axis, dtype=result_dtype)
623
avg = np.multiply(a, wgt, dtype=result_dtype).sum(axis)/scl
624
625
if returned:
626
if scl.shape != avg.shape:
627
scl = np.broadcast_to(scl, avg.shape).copy()
628
return avg, scl
629
else:
630
return avg
631
632
633
def median(a, axis=None, out=None, overwrite_input=False, keepdims=False):
634
"""
635
Compute the median along the specified axis.
636
637
Returns the median of the array elements.
638
639
Parameters
640
----------
641
a : array_like
642
Input array or object that can be converted to an array.
643
axis : int, optional
644
Axis along which the medians are computed. The default (None) is
645
to compute the median along a flattened version of the array.
646
out : ndarray, optional
647
Alternative output array in which to place the result. It must
648
have the same shape and buffer length as the expected output
649
but the type will be cast if necessary.
650
overwrite_input : bool, optional
651
If True, then allow use of memory of input array (a) for
652
calculations. The input array will be modified by the call to
653
median. This will save memory when you do not need to preserve
654
the contents of the input array. Treat the input as undefined,
655
but it will probably be fully or partially sorted. Default is
656
False. Note that, if `overwrite_input` is True, and the input
657
is not already an `ndarray`, an error will be raised.
658
keepdims : bool, optional
659
If this is set to True, the axes which are reduced are left
660
in the result as dimensions with size one. With this option,
661
the result will broadcast correctly against the input array.
662
663
.. versionadded:: 1.10.0
664
665
Returns
666
-------
667
median : ndarray
668
A new array holding the result is returned unless out is
669
specified, in which case a reference to out is returned.
670
Return data-type is `float64` for integers and floats smaller than
671
`float64`, or the input data-type, otherwise.
672
673
See Also
674
--------
675
mean
676
677
Notes
678
-----
679
Given a vector ``V`` with ``N`` non masked values, the median of ``V``
680
is the middle value of a sorted copy of ``V`` (``Vs``) - i.e.
681
``Vs[(N-1)/2]``, when ``N`` is odd, or ``{Vs[N/2 - 1] + Vs[N/2]}/2``
682
when ``N`` is even.
683
684
Examples
685
--------
686
>>> x = np.ma.array(np.arange(8), mask=[0]*4 + [1]*4)
687
>>> np.ma.median(x)
688
1.5
689
690
>>> x = np.ma.array(np.arange(10).reshape(2, 5), mask=[0]*6 + [1]*4)
691
>>> np.ma.median(x)
692
2.5
693
>>> np.ma.median(x, axis=-1, overwrite_input=True)
694
masked_array(data=[2.0, 5.0],
695
mask=[False, False],
696
fill_value=1e+20)
697
698
"""
699
if not hasattr(a, 'mask'):
700
m = np.median(getdata(a, subok=True), axis=axis,
701
out=out, overwrite_input=overwrite_input,
702
keepdims=keepdims)
703
if isinstance(m, np.ndarray) and 1 <= m.ndim:
704
return masked_array(m, copy=False)
705
else:
706
return m
707
708
r, k = _ureduce(a, func=_median, axis=axis, out=out,
709
overwrite_input=overwrite_input)
710
if keepdims:
711
return r.reshape(k)
712
else:
713
return r
714
715
def _median(a, axis=None, out=None, overwrite_input=False):
716
# when an unmasked NaN is present return it, so we need to sort the NaN
717
# values behind the mask
718
if np.issubdtype(a.dtype, np.inexact):
719
fill_value = np.inf
720
else:
721
fill_value = None
722
if overwrite_input:
723
if axis is None:
724
asorted = a.ravel()
725
asorted.sort(fill_value=fill_value)
726
else:
727
a.sort(axis=axis, fill_value=fill_value)
728
asorted = a
729
else:
730
asorted = sort(a, axis=axis, fill_value=fill_value)
731
732
if axis is None:
733
axis = 0
734
else:
735
axis = normalize_axis_index(axis, asorted.ndim)
736
737
if asorted.shape[axis] == 0:
738
# for empty axis integer indices fail so use slicing to get same result
739
# as median (which is mean of empty slice = nan)
740
indexer = [slice(None)] * asorted.ndim
741
indexer[axis] = slice(0, 0)
742
indexer = tuple(indexer)
743
return np.ma.mean(asorted[indexer], axis=axis, out=out)
744
745
if asorted.ndim == 1:
746
idx, odd = divmod(count(asorted), 2)
747
mid = asorted[idx + odd - 1:idx + 1]
748
if np.issubdtype(asorted.dtype, np.inexact) and asorted.size > 0:
749
# avoid inf / x = masked
750
s = mid.sum(out=out)
751
if not odd:
752
s = np.true_divide(s, 2., casting='safe', out=out)
753
s = np.lib.utils._median_nancheck(asorted, s, axis)
754
else:
755
s = mid.mean(out=out)
756
757
# if result is masked either the input contained enough
758
# minimum_fill_value so that it would be the median or all values
759
# masked
760
if np.ma.is_masked(s) and not np.all(asorted.mask):
761
return np.ma.minimum_fill_value(asorted)
762
return s
763
764
counts = count(asorted, axis=axis, keepdims=True)
765
h = counts // 2
766
767
# duplicate high if odd number of elements so mean does nothing
768
odd = counts % 2 == 1
769
l = np.where(odd, h, h-1)
770
771
lh = np.concatenate([l,h], axis=axis)
772
773
# get low and high median
774
low_high = np.take_along_axis(asorted, lh, axis=axis)
775
776
def replace_masked(s):
777
# Replace masked entries with minimum_full_value unless it all values
778
# are masked. This is required as the sort order of values equal or
779
# larger than the fill value is undefined and a valid value placed
780
# elsewhere, e.g. [4, --, inf].
781
if np.ma.is_masked(s):
782
rep = (~np.all(asorted.mask, axis=axis, keepdims=True)) & s.mask
783
s.data[rep] = np.ma.minimum_fill_value(asorted)
784
s.mask[rep] = False
785
786
replace_masked(low_high)
787
788
if np.issubdtype(asorted.dtype, np.inexact):
789
# avoid inf / x = masked
790
s = np.ma.sum(low_high, axis=axis, out=out)
791
np.true_divide(s.data, 2., casting='unsafe', out=s.data)
792
793
s = np.lib.utils._median_nancheck(asorted, s, axis)
794
else:
795
s = np.ma.mean(low_high, axis=axis, out=out)
796
797
return s
798
799
800
def compress_nd(x, axis=None):
801
"""Suppress slices from multiple dimensions which contain masked values.
802
803
Parameters
804
----------
805
x : array_like, MaskedArray
806
The array to operate on. If not a MaskedArray instance (or if no array
807
elements are masked), `x` is interpreted as a MaskedArray with `mask`
808
set to `nomask`.
809
axis : tuple of ints or int, optional
810
Which dimensions to suppress slices from can be configured with this
811
parameter.
812
- If axis is a tuple of ints, those are the axes to suppress slices from.
813
- If axis is an int, then that is the only axis to suppress slices from.
814
- If axis is None, all axis are selected.
815
816
Returns
817
-------
818
compress_array : ndarray
819
The compressed array.
820
"""
821
x = asarray(x)
822
m = getmask(x)
823
# Set axis to tuple of ints
824
if axis is None:
825
axis = tuple(range(x.ndim))
826
else:
827
axis = normalize_axis_tuple(axis, x.ndim)
828
829
# Nothing is masked: return x
830
if m is nomask or not m.any():
831
return x._data
832
# All is masked: return empty
833
if m.all():
834
return nxarray([])
835
# Filter elements through boolean indexing
836
data = x._data
837
for ax in axis:
838
axes = tuple(list(range(ax)) + list(range(ax + 1, x.ndim)))
839
data = data[(slice(None),)*ax + (~m.any(axis=axes),)]
840
return data
841
842
def compress_rowcols(x, axis=None):
843
"""
844
Suppress the rows and/or columns of a 2-D array that contain
845
masked values.
846
847
The suppression behavior is selected with the `axis` parameter.
848
849
- If axis is None, both rows and columns are suppressed.
850
- If axis is 0, only rows are suppressed.
851
- If axis is 1 or -1, only columns are suppressed.
852
853
Parameters
854
----------
855
x : array_like, MaskedArray
856
The array to operate on. If not a MaskedArray instance (or if no array
857
elements are masked), `x` is interpreted as a MaskedArray with
858
`mask` set to `nomask`. Must be a 2D array.
859
axis : int, optional
860
Axis along which to perform the operation. Default is None.
861
862
Returns
863
-------
864
compressed_array : ndarray
865
The compressed array.
866
867
Examples
868
--------
869
>>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0],
870
... [1, 0, 0],
871
... [0, 0, 0]])
872
>>> x
873
masked_array(
874
data=[[--, 1, 2],
875
[--, 4, 5],
876
[6, 7, 8]],
877
mask=[[ True, False, False],
878
[ True, False, False],
879
[False, False, False]],
880
fill_value=999999)
881
882
>>> np.ma.compress_rowcols(x)
883
array([[7, 8]])
884
>>> np.ma.compress_rowcols(x, 0)
885
array([[6, 7, 8]])
886
>>> np.ma.compress_rowcols(x, 1)
887
array([[1, 2],
888
[4, 5],
889
[7, 8]])
890
891
"""
892
if asarray(x).ndim != 2:
893
raise NotImplementedError("compress_rowcols works for 2D arrays only.")
894
return compress_nd(x, axis=axis)
895
896
897
def compress_rows(a):
898
"""
899
Suppress whole rows of a 2-D array that contain masked values.
900
901
This is equivalent to ``np.ma.compress_rowcols(a, 0)``, see
902
`compress_rowcols` for details.
903
904
See Also
905
--------
906
compress_rowcols
907
908
"""
909
a = asarray(a)
910
if a.ndim != 2:
911
raise NotImplementedError("compress_rows works for 2D arrays only.")
912
return compress_rowcols(a, 0)
913
914
def compress_cols(a):
915
"""
916
Suppress whole columns of a 2-D array that contain masked values.
917
918
This is equivalent to ``np.ma.compress_rowcols(a, 1)``, see
919
`compress_rowcols` for details.
920
921
See Also
922
--------
923
compress_rowcols
924
925
"""
926
a = asarray(a)
927
if a.ndim != 2:
928
raise NotImplementedError("compress_cols works for 2D arrays only.")
929
return compress_rowcols(a, 1)
930
931
def mask_rows(a, axis=np._NoValue):
932
"""
933
Mask rows of a 2D array that contain masked values.
934
935
This function is a shortcut to ``mask_rowcols`` with `axis` equal to 0.
936
937
See Also
938
--------
939
mask_rowcols : Mask rows and/or columns of a 2D array.
940
masked_where : Mask where a condition is met.
941
942
Examples
943
--------
944
>>> import numpy.ma as ma
945
>>> a = np.zeros((3, 3), dtype=int)
946
>>> a[1, 1] = 1
947
>>> a
948
array([[0, 0, 0],
949
[0, 1, 0],
950
[0, 0, 0]])
951
>>> a = ma.masked_equal(a, 1)
952
>>> a
953
masked_array(
954
data=[[0, 0, 0],
955
[0, --, 0],
956
[0, 0, 0]],
957
mask=[[False, False, False],
958
[False, True, False],
959
[False, False, False]],
960
fill_value=1)
961
962
>>> ma.mask_rows(a)
963
masked_array(
964
data=[[0, 0, 0],
965
[--, --, --],
966
[0, 0, 0]],
967
mask=[[False, False, False],
968
[ True, True, True],
969
[False, False, False]],
970
fill_value=1)
971
972
"""
973
if axis is not np._NoValue:
974
# remove the axis argument when this deprecation expires
975
# NumPy 1.18.0, 2019-11-28
976
warnings.warn(
977
"The axis argument has always been ignored, in future passing it "
978
"will raise TypeError", DeprecationWarning, stacklevel=2)
979
return mask_rowcols(a, 0)
980
981
def mask_cols(a, axis=np._NoValue):
982
"""
983
Mask columns of a 2D array that contain masked values.
984
985
This function is a shortcut to ``mask_rowcols`` with `axis` equal to 1.
986
987
See Also
988
--------
989
mask_rowcols : Mask rows and/or columns of a 2D array.
990
masked_where : Mask where a condition is met.
991
992
Examples
993
--------
994
>>> import numpy.ma as ma
995
>>> a = np.zeros((3, 3), dtype=int)
996
>>> a[1, 1] = 1
997
>>> a
998
array([[0, 0, 0],
999
[0, 1, 0],
1000
[0, 0, 0]])
1001
>>> a = ma.masked_equal(a, 1)
1002
>>> a
1003
masked_array(
1004
data=[[0, 0, 0],
1005
[0, --, 0],
1006
[0, 0, 0]],
1007
mask=[[False, False, False],
1008
[False, True, False],
1009
[False, False, False]],
1010
fill_value=1)
1011
>>> ma.mask_cols(a)
1012
masked_array(
1013
data=[[0, --, 0],
1014
[0, --, 0],
1015
[0, --, 0]],
1016
mask=[[False, True, False],
1017
[False, True, False],
1018
[False, True, False]],
1019
fill_value=1)
1020
1021
"""
1022
if axis is not np._NoValue:
1023
# remove the axis argument when this deprecation expires
1024
# NumPy 1.18.0, 2019-11-28
1025
warnings.warn(
1026
"The axis argument has always been ignored, in future passing it "
1027
"will raise TypeError", DeprecationWarning, stacklevel=2)
1028
return mask_rowcols(a, 1)
1029
1030
1031
#####--------------------------------------------------------------------------
1032
#---- --- arraysetops ---
1033
#####--------------------------------------------------------------------------
1034
1035
def ediff1d(arr, to_end=None, to_begin=None):
1036
"""
1037
Compute the differences between consecutive elements of an array.
1038
1039
This function is the equivalent of `numpy.ediff1d` that takes masked
1040
values into account, see `numpy.ediff1d` for details.
1041
1042
See Also
1043
--------
1044
numpy.ediff1d : Equivalent function for ndarrays.
1045
1046
"""
1047
arr = ma.asanyarray(arr).flat
1048
ed = arr[1:] - arr[:-1]
1049
arrays = [ed]
1050
#
1051
if to_begin is not None:
1052
arrays.insert(0, to_begin)
1053
if to_end is not None:
1054
arrays.append(to_end)
1055
#
1056
if len(arrays) != 1:
1057
# We'll save ourselves a copy of a potentially large array in the common
1058
# case where neither to_begin or to_end was given.
1059
ed = hstack(arrays)
1060
#
1061
return ed
1062
1063
1064
def unique(ar1, return_index=False, return_inverse=False):
1065
"""
1066
Finds the unique elements of an array.
1067
1068
Masked values are considered the same element (masked). The output array
1069
is always a masked array. See `numpy.unique` for more details.
1070
1071
See Also
1072
--------
1073
numpy.unique : Equivalent function for ndarrays.
1074
1075
"""
1076
output = np.unique(ar1,
1077
return_index=return_index,
1078
return_inverse=return_inverse)
1079
if isinstance(output, tuple):
1080
output = list(output)
1081
output[0] = output[0].view(MaskedArray)
1082
output = tuple(output)
1083
else:
1084
output = output.view(MaskedArray)
1085
return output
1086
1087
1088
def intersect1d(ar1, ar2, assume_unique=False):
1089
"""
1090
Returns the unique elements common to both arrays.
1091
1092
Masked values are considered equal one to the other.
1093
The output is always a masked array.
1094
1095
See `numpy.intersect1d` for more details.
1096
1097
See Also
1098
--------
1099
numpy.intersect1d : Equivalent function for ndarrays.
1100
1101
Examples
1102
--------
1103
>>> x = np.ma.array([1, 3, 3, 3], mask=[0, 0, 0, 1])
1104
>>> y = np.ma.array([3, 1, 1, 1], mask=[0, 0, 0, 1])
1105
>>> np.ma.intersect1d(x, y)
1106
masked_array(data=[1, 3, --],
1107
mask=[False, False, True],
1108
fill_value=999999)
1109
1110
"""
1111
if assume_unique:
1112
aux = ma.concatenate((ar1, ar2))
1113
else:
1114
# Might be faster than unique( intersect1d( ar1, ar2 ) )?
1115
aux = ma.concatenate((unique(ar1), unique(ar2)))
1116
aux.sort()
1117
return aux[:-1][aux[1:] == aux[:-1]]
1118
1119
1120
def setxor1d(ar1, ar2, assume_unique=False):
1121
"""
1122
Set exclusive-or of 1-D arrays with unique elements.
1123
1124
The output is always a masked array. See `numpy.setxor1d` for more details.
1125
1126
See Also
1127
--------
1128
numpy.setxor1d : Equivalent function for ndarrays.
1129
1130
"""
1131
if not assume_unique:
1132
ar1 = unique(ar1)
1133
ar2 = unique(ar2)
1134
1135
aux = ma.concatenate((ar1, ar2))
1136
if aux.size == 0:
1137
return aux
1138
aux.sort()
1139
auxf = aux.filled()
1140
# flag = ediff1d( aux, to_end = 1, to_begin = 1 ) == 0
1141
flag = ma.concatenate(([True], (auxf[1:] != auxf[:-1]), [True]))
1142
# flag2 = ediff1d( flag ) == 0
1143
flag2 = (flag[1:] == flag[:-1])
1144
return aux[flag2]
1145
1146
1147
def in1d(ar1, ar2, assume_unique=False, invert=False):
1148
"""
1149
Test whether each element of an array is also present in a second
1150
array.
1151
1152
The output is always a masked array. See `numpy.in1d` for more details.
1153
1154
We recommend using :func:`isin` instead of `in1d` for new code.
1155
1156
See Also
1157
--------
1158
isin : Version of this function that preserves the shape of ar1.
1159
numpy.in1d : Equivalent function for ndarrays.
1160
1161
Notes
1162
-----
1163
.. versionadded:: 1.4.0
1164
1165
"""
1166
if not assume_unique:
1167
ar1, rev_idx = unique(ar1, return_inverse=True)
1168
ar2 = unique(ar2)
1169
1170
ar = ma.concatenate((ar1, ar2))
1171
# We need this to be a stable sort, so always use 'mergesort'
1172
# here. The values from the first array should always come before
1173
# the values from the second array.
1174
order = ar.argsort(kind='mergesort')
1175
sar = ar[order]
1176
if invert:
1177
bool_ar = (sar[1:] != sar[:-1])
1178
else:
1179
bool_ar = (sar[1:] == sar[:-1])
1180
flag = ma.concatenate((bool_ar, [invert]))
1181
indx = order.argsort(kind='mergesort')[:len(ar1)]
1182
1183
if assume_unique:
1184
return flag[indx]
1185
else:
1186
return flag[indx][rev_idx]
1187
1188
1189
def isin(element, test_elements, assume_unique=False, invert=False):
1190
"""
1191
Calculates `element in test_elements`, broadcasting over
1192
`element` only.
1193
1194
The output is always a masked array of the same shape as `element`.
1195
See `numpy.isin` for more details.
1196
1197
See Also
1198
--------
1199
in1d : Flattened version of this function.
1200
numpy.isin : Equivalent function for ndarrays.
1201
1202
Notes
1203
-----
1204
.. versionadded:: 1.13.0
1205
1206
"""
1207
element = ma.asarray(element)
1208
return in1d(element, test_elements, assume_unique=assume_unique,
1209
invert=invert).reshape(element.shape)
1210
1211
1212
def union1d(ar1, ar2):
1213
"""
1214
Union of two arrays.
1215
1216
The output is always a masked array. See `numpy.union1d` for more details.
1217
1218
See Also
1219
--------
1220
numpy.union1d : Equivalent function for ndarrays.
1221
1222
"""
1223
return unique(ma.concatenate((ar1, ar2), axis=None))
1224
1225
1226
def setdiff1d(ar1, ar2, assume_unique=False):
1227
"""
1228
Set difference of 1D arrays with unique elements.
1229
1230
The output is always a masked array. See `numpy.setdiff1d` for more
1231
details.
1232
1233
See Also
1234
--------
1235
numpy.setdiff1d : Equivalent function for ndarrays.
1236
1237
Examples
1238
--------
1239
>>> x = np.ma.array([1, 2, 3, 4], mask=[0, 1, 0, 1])
1240
>>> np.ma.setdiff1d(x, [1, 2])
1241
masked_array(data=[3, --],
1242
mask=[False, True],
1243
fill_value=999999)
1244
1245
"""
1246
if assume_unique:
1247
ar1 = ma.asarray(ar1).ravel()
1248
else:
1249
ar1 = unique(ar1)
1250
ar2 = unique(ar2)
1251
return ar1[in1d(ar1, ar2, assume_unique=True, invert=True)]
1252
1253
1254
###############################################################################
1255
# Covariance #
1256
###############################################################################
1257
1258
1259
def _covhelper(x, y=None, rowvar=True, allow_masked=True):
1260
"""
1261
Private function for the computation of covariance and correlation
1262
coefficients.
1263
1264
"""
1265
x = ma.array(x, ndmin=2, copy=True, dtype=float)
1266
xmask = ma.getmaskarray(x)
1267
# Quick exit if we can't process masked data
1268
if not allow_masked and xmask.any():
1269
raise ValueError("Cannot process masked data.")
1270
#
1271
if x.shape[0] == 1:
1272
rowvar = True
1273
# Make sure that rowvar is either 0 or 1
1274
rowvar = int(bool(rowvar))
1275
axis = 1 - rowvar
1276
if rowvar:
1277
tup = (slice(None), None)
1278
else:
1279
tup = (None, slice(None))
1280
#
1281
if y is None:
1282
xnotmask = np.logical_not(xmask).astype(int)
1283
else:
1284
y = array(y, copy=False, ndmin=2, dtype=float)
1285
ymask = ma.getmaskarray(y)
1286
if not allow_masked and ymask.any():
1287
raise ValueError("Cannot process masked data.")
1288
if xmask.any() or ymask.any():
1289
if y.shape == x.shape:
1290
# Define some common mask
1291
common_mask = np.logical_or(xmask, ymask)
1292
if common_mask is not nomask:
1293
xmask = x._mask = y._mask = ymask = common_mask
1294
x._sharedmask = False
1295
y._sharedmask = False
1296
x = ma.concatenate((x, y), axis)
1297
xnotmask = np.logical_not(np.concatenate((xmask, ymask), axis)).astype(int)
1298
x -= x.mean(axis=rowvar)[tup]
1299
return (x, xnotmask, rowvar)
1300
1301
1302
def cov(x, y=None, rowvar=True, bias=False, allow_masked=True, ddof=None):
1303
"""
1304
Estimate the covariance matrix.
1305
1306
Except for the handling of missing data this function does the same as
1307
`numpy.cov`. For more details and examples, see `numpy.cov`.
1308
1309
By default, masked values are recognized as such. If `x` and `y` have the
1310
same shape, a common mask is allocated: if ``x[i,j]`` is masked, then
1311
``y[i,j]`` will also be masked.
1312
Setting `allow_masked` to False will raise an exception if values are
1313
missing in either of the input arrays.
1314
1315
Parameters
1316
----------
1317
x : array_like
1318
A 1-D or 2-D array containing multiple variables and observations.
1319
Each row of `x` represents a variable, and each column a single
1320
observation of all those variables. Also see `rowvar` below.
1321
y : array_like, optional
1322
An additional set of variables and observations. `y` has the same
1323
shape as `x`.
1324
rowvar : bool, optional
1325
If `rowvar` is True (default), then each row represents a
1326
variable, with observations in the columns. Otherwise, the relationship
1327
is transposed: each column represents a variable, while the rows
1328
contain observations.
1329
bias : bool, optional
1330
Default normalization (False) is by ``(N-1)``, where ``N`` is the
1331
number of observations given (unbiased estimate). If `bias` is True,
1332
then normalization is by ``N``. This keyword can be overridden by
1333
the keyword ``ddof`` in numpy versions >= 1.5.
1334
allow_masked : bool, optional
1335
If True, masked values are propagated pair-wise: if a value is masked
1336
in `x`, the corresponding value is masked in `y`.
1337
If False, raises a `ValueError` exception when some values are missing.
1338
ddof : {None, int}, optional
1339
If not ``None`` normalization is by ``(N - ddof)``, where ``N`` is
1340
the number of observations; this overrides the value implied by
1341
``bias``. The default value is ``None``.
1342
1343
.. versionadded:: 1.5
1344
1345
Raises
1346
------
1347
ValueError
1348
Raised if some values are missing and `allow_masked` is False.
1349
1350
See Also
1351
--------
1352
numpy.cov
1353
1354
"""
1355
# Check inputs
1356
if ddof is not None and ddof != int(ddof):
1357
raise ValueError("ddof must be an integer")
1358
# Set up ddof
1359
if ddof is None:
1360
if bias:
1361
ddof = 0
1362
else:
1363
ddof = 1
1364
1365
(x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked)
1366
if not rowvar:
1367
fact = np.dot(xnotmask.T, xnotmask) * 1. - ddof
1368
result = (dot(x.T, x.conj(), strict=False) / fact).squeeze()
1369
else:
1370
fact = np.dot(xnotmask, xnotmask.T) * 1. - ddof
1371
result = (dot(x, x.T.conj(), strict=False) / fact).squeeze()
1372
return result
1373
1374
1375
def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, allow_masked=True,
1376
ddof=np._NoValue):
1377
"""
1378
Return Pearson product-moment correlation coefficients.
1379
1380
Except for the handling of missing data this function does the same as
1381
`numpy.corrcoef`. For more details and examples, see `numpy.corrcoef`.
1382
1383
Parameters
1384
----------
1385
x : array_like
1386
A 1-D or 2-D array containing multiple variables and observations.
1387
Each row of `x` represents a variable, and each column a single
1388
observation of all those variables. Also see `rowvar` below.
1389
y : array_like, optional
1390
An additional set of variables and observations. `y` has the same
1391
shape as `x`.
1392
rowvar : bool, optional
1393
If `rowvar` is True (default), then each row represents a
1394
variable, with observations in the columns. Otherwise, the relationship
1395
is transposed: each column represents a variable, while the rows
1396
contain observations.
1397
bias : _NoValue, optional
1398
Has no effect, do not use.
1399
1400
.. deprecated:: 1.10.0
1401
allow_masked : bool, optional
1402
If True, masked values are propagated pair-wise: if a value is masked
1403
in `x`, the corresponding value is masked in `y`.
1404
If False, raises an exception. Because `bias` is deprecated, this
1405
argument needs to be treated as keyword only to avoid a warning.
1406
ddof : _NoValue, optional
1407
Has no effect, do not use.
1408
1409
.. deprecated:: 1.10.0
1410
1411
See Also
1412
--------
1413
numpy.corrcoef : Equivalent function in top-level NumPy module.
1414
cov : Estimate the covariance matrix.
1415
1416
Notes
1417
-----
1418
This function accepts but discards arguments `bias` and `ddof`. This is
1419
for backwards compatibility with previous versions of this function. These
1420
arguments had no effect on the return values of the function and can be
1421
safely ignored in this and previous versions of numpy.
1422
"""
1423
msg = 'bias and ddof have no effect and are deprecated'
1424
if bias is not np._NoValue or ddof is not np._NoValue:
1425
# 2015-03-15, 1.10
1426
warnings.warn(msg, DeprecationWarning, stacklevel=2)
1427
# Get the data
1428
(x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked)
1429
# Compute the covariance matrix
1430
if not rowvar:
1431
fact = np.dot(xnotmask.T, xnotmask) * 1.
1432
c = (dot(x.T, x.conj(), strict=False) / fact).squeeze()
1433
else:
1434
fact = np.dot(xnotmask, xnotmask.T) * 1.
1435
c = (dot(x, x.T.conj(), strict=False) / fact).squeeze()
1436
# Check whether we have a scalar
1437
try:
1438
diag = ma.diagonal(c)
1439
except ValueError:
1440
return 1
1441
#
1442
if xnotmask.all():
1443
_denom = ma.sqrt(ma.multiply.outer(diag, diag))
1444
else:
1445
_denom = diagflat(diag)
1446
_denom._sharedmask = False # We know return is always a copy
1447
n = x.shape[1 - rowvar]
1448
if rowvar:
1449
for i in range(n - 1):
1450
for j in range(i + 1, n):
1451
_x = mask_cols(vstack((x[i], x[j]))).var(axis=1)
1452
_denom[i, j] = _denom[j, i] = ma.sqrt(ma.multiply.reduce(_x))
1453
else:
1454
for i in range(n - 1):
1455
for j in range(i + 1, n):
1456
_x = mask_cols(
1457
vstack((x[:, i], x[:, j]))).var(axis=1)
1458
_denom[i, j] = _denom[j, i] = ma.sqrt(ma.multiply.reduce(_x))
1459
return c / _denom
1460
1461
#####--------------------------------------------------------------------------
1462
#---- --- Concatenation helpers ---
1463
#####--------------------------------------------------------------------------
1464
1465
class MAxisConcatenator(AxisConcatenator):
1466
"""
1467
Translate slice objects to concatenation along an axis.
1468
1469
For documentation on usage, see `mr_class`.
1470
1471
See Also
1472
--------
1473
mr_class
1474
1475
"""
1476
concatenate = staticmethod(concatenate)
1477
1478
@classmethod
1479
def makemat(cls, arr):
1480
# There used to be a view as np.matrix here, but we may eventually
1481
# deprecate that class. In preparation, we use the unmasked version
1482
# to construct the matrix (with copy=False for backwards compatibility
1483
# with the .view)
1484
data = super().makemat(arr.data, copy=False)
1485
return array(data, mask=arr.mask)
1486
1487
def __getitem__(self, key):
1488
# matrix builder syntax, like 'a, b; c, d'
1489
if isinstance(key, str):
1490
raise MAError("Unavailable for masked array.")
1491
1492
return super().__getitem__(key)
1493
1494
1495
class mr_class(MAxisConcatenator):
1496
"""
1497
Translate slice objects to concatenation along the first axis.
1498
1499
This is the masked array version of `lib.index_tricks.RClass`.
1500
1501
See Also
1502
--------
1503
lib.index_tricks.RClass
1504
1505
Examples
1506
--------
1507
>>> np.ma.mr_[np.ma.array([1,2,3]), 0, 0, np.ma.array([4,5,6])]
1508
masked_array(data=[1, 2, 3, ..., 4, 5, 6],
1509
mask=False,
1510
fill_value=999999)
1511
1512
"""
1513
def __init__(self):
1514
MAxisConcatenator.__init__(self, 0)
1515
1516
mr_ = mr_class()
1517
1518
#####--------------------------------------------------------------------------
1519
#---- Find unmasked data ---
1520
#####--------------------------------------------------------------------------
1521
1522
def flatnotmasked_edges(a):
1523
"""
1524
Find the indices of the first and last unmasked values.
1525
1526
Expects a 1-D `MaskedArray`, returns None if all values are masked.
1527
1528
Parameters
1529
----------
1530
a : array_like
1531
Input 1-D `MaskedArray`
1532
1533
Returns
1534
-------
1535
edges : ndarray or None
1536
The indices of first and last non-masked value in the array.
1537
Returns None if all values are masked.
1538
1539
See Also
1540
--------
1541
flatnotmasked_contiguous, notmasked_contiguous, notmasked_edges
1542
clump_masked, clump_unmasked
1543
1544
Notes
1545
-----
1546
Only accepts 1-D arrays.
1547
1548
Examples
1549
--------
1550
>>> a = np.ma.arange(10)
1551
>>> np.ma.flatnotmasked_edges(a)
1552
array([0, 9])
1553
1554
>>> mask = (a < 3) | (a > 8) | (a == 5)
1555
>>> a[mask] = np.ma.masked
1556
>>> np.array(a[~a.mask])
1557
array([3, 4, 6, 7, 8])
1558
1559
>>> np.ma.flatnotmasked_edges(a)
1560
array([3, 8])
1561
1562
>>> a[:] = np.ma.masked
1563
>>> print(np.ma.flatnotmasked_edges(a))
1564
None
1565
1566
"""
1567
m = getmask(a)
1568
if m is nomask or not np.any(m):
1569
return np.array([0, a.size - 1])
1570
unmasked = np.flatnonzero(~m)
1571
if len(unmasked) > 0:
1572
return unmasked[[0, -1]]
1573
else:
1574
return None
1575
1576
1577
def notmasked_edges(a, axis=None):
1578
"""
1579
Find the indices of the first and last unmasked values along an axis.
1580
1581
If all values are masked, return None. Otherwise, return a list
1582
of two tuples, corresponding to the indices of the first and last
1583
unmasked values respectively.
1584
1585
Parameters
1586
----------
1587
a : array_like
1588
The input array.
1589
axis : int, optional
1590
Axis along which to perform the operation.
1591
If None (default), applies to a flattened version of the array.
1592
1593
Returns
1594
-------
1595
edges : ndarray or list
1596
An array of start and end indexes if there are any masked data in
1597
the array. If there are no masked data in the array, `edges` is a
1598
list of the first and last index.
1599
1600
See Also
1601
--------
1602
flatnotmasked_contiguous, flatnotmasked_edges, notmasked_contiguous
1603
clump_masked, clump_unmasked
1604
1605
Examples
1606
--------
1607
>>> a = np.arange(9).reshape((3, 3))
1608
>>> m = np.zeros_like(a)
1609
>>> m[1:, 1:] = 1
1610
1611
>>> am = np.ma.array(a, mask=m)
1612
>>> np.array(am[~am.mask])
1613
array([0, 1, 2, 3, 6])
1614
1615
>>> np.ma.notmasked_edges(am)
1616
array([0, 6])
1617
1618
"""
1619
a = asarray(a)
1620
if axis is None or a.ndim == 1:
1621
return flatnotmasked_edges(a)
1622
m = getmaskarray(a)
1623
idx = array(np.indices(a.shape), mask=np.asarray([m] * a.ndim))
1624
return [tuple([idx[i].min(axis).compressed() for i in range(a.ndim)]),
1625
tuple([idx[i].max(axis).compressed() for i in range(a.ndim)]), ]
1626
1627
1628
def flatnotmasked_contiguous(a):
1629
"""
1630
Find contiguous unmasked data in a masked array along the given axis.
1631
1632
Parameters
1633
----------
1634
a : narray
1635
The input array.
1636
1637
Returns
1638
-------
1639
slice_list : list
1640
A sorted sequence of `slice` objects (start index, end index).
1641
1642
.. versionchanged:: 1.15.0
1643
Now returns an empty list instead of None for a fully masked array
1644
1645
See Also
1646
--------
1647
flatnotmasked_edges, notmasked_contiguous, notmasked_edges
1648
clump_masked, clump_unmasked
1649
1650
Notes
1651
-----
1652
Only accepts 2-D arrays at most.
1653
1654
Examples
1655
--------
1656
>>> a = np.ma.arange(10)
1657
>>> np.ma.flatnotmasked_contiguous(a)
1658
[slice(0, 10, None)]
1659
1660
>>> mask = (a < 3) | (a > 8) | (a == 5)
1661
>>> a[mask] = np.ma.masked
1662
>>> np.array(a[~a.mask])
1663
array([3, 4, 6, 7, 8])
1664
1665
>>> np.ma.flatnotmasked_contiguous(a)
1666
[slice(3, 5, None), slice(6, 9, None)]
1667
>>> a[:] = np.ma.masked
1668
>>> np.ma.flatnotmasked_contiguous(a)
1669
[]
1670
1671
"""
1672
m = getmask(a)
1673
if m is nomask:
1674
return [slice(0, a.size)]
1675
i = 0
1676
result = []
1677
for (k, g) in itertools.groupby(m.ravel()):
1678
n = len(list(g))
1679
if not k:
1680
result.append(slice(i, i + n))
1681
i += n
1682
return result
1683
1684
def notmasked_contiguous(a, axis=None):
1685
"""
1686
Find contiguous unmasked data in a masked array along the given axis.
1687
1688
Parameters
1689
----------
1690
a : array_like
1691
The input array.
1692
axis : int, optional
1693
Axis along which to perform the operation.
1694
If None (default), applies to a flattened version of the array, and this
1695
is the same as `flatnotmasked_contiguous`.
1696
1697
Returns
1698
-------
1699
endpoints : list
1700
A list of slices (start and end indexes) of unmasked indexes
1701
in the array.
1702
1703
If the input is 2d and axis is specified, the result is a list of lists.
1704
1705
See Also
1706
--------
1707
flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
1708
clump_masked, clump_unmasked
1709
1710
Notes
1711
-----
1712
Only accepts 2-D arrays at most.
1713
1714
Examples
1715
--------
1716
>>> a = np.arange(12).reshape((3, 4))
1717
>>> mask = np.zeros_like(a)
1718
>>> mask[1:, :-1] = 1; mask[0, 1] = 1; mask[-1, 0] = 0
1719
>>> ma = np.ma.array(a, mask=mask)
1720
>>> ma
1721
masked_array(
1722
data=[[0, --, 2, 3],
1723
[--, --, --, 7],
1724
[8, --, --, 11]],
1725
mask=[[False, True, False, False],
1726
[ True, True, True, False],
1727
[False, True, True, False]],
1728
fill_value=999999)
1729
>>> np.array(ma[~ma.mask])
1730
array([ 0, 2, 3, 7, 8, 11])
1731
1732
>>> np.ma.notmasked_contiguous(ma)
1733
[slice(0, 1, None), slice(2, 4, None), slice(7, 9, None), slice(11, 12, None)]
1734
1735
>>> np.ma.notmasked_contiguous(ma, axis=0)
1736
[[slice(0, 1, None), slice(2, 3, None)], [], [slice(0, 1, None)], [slice(0, 3, None)]]
1737
1738
>>> np.ma.notmasked_contiguous(ma, axis=1)
1739
[[slice(0, 1, None), slice(2, 4, None)], [slice(3, 4, None)], [slice(0, 1, None), slice(3, 4, None)]]
1740
1741
"""
1742
a = asarray(a)
1743
nd = a.ndim
1744
if nd > 2:
1745
raise NotImplementedError("Currently limited to atmost 2D array.")
1746
if axis is None or nd == 1:
1747
return flatnotmasked_contiguous(a)
1748
#
1749
result = []
1750
#
1751
other = (axis + 1) % 2
1752
idx = [0, 0]
1753
idx[axis] = slice(None, None)
1754
#
1755
for i in range(a.shape[other]):
1756
idx[other] = i
1757
result.append(flatnotmasked_contiguous(a[tuple(idx)]))
1758
return result
1759
1760
1761
def _ezclump(mask):
1762
"""
1763
Finds the clumps (groups of data with the same values) for a 1D bool array.
1764
1765
Returns a series of slices.
1766
"""
1767
if mask.ndim > 1:
1768
mask = mask.ravel()
1769
idx = (mask[1:] ^ mask[:-1]).nonzero()
1770
idx = idx[0] + 1
1771
1772
if mask[0]:
1773
if len(idx) == 0:
1774
return [slice(0, mask.size)]
1775
1776
r = [slice(0, idx[0])]
1777
r.extend((slice(left, right)
1778
for left, right in zip(idx[1:-1:2], idx[2::2])))
1779
else:
1780
if len(idx) == 0:
1781
return []
1782
1783
r = [slice(left, right) for left, right in zip(idx[:-1:2], idx[1::2])]
1784
1785
if mask[-1]:
1786
r.append(slice(idx[-1], mask.size))
1787
return r
1788
1789
1790
def clump_unmasked(a):
1791
"""
1792
Return list of slices corresponding to the unmasked clumps of a 1-D array.
1793
(A "clump" is defined as a contiguous region of the array).
1794
1795
Parameters
1796
----------
1797
a : ndarray
1798
A one-dimensional masked array.
1799
1800
Returns
1801
-------
1802
slices : list of slice
1803
The list of slices, one for each continuous region of unmasked
1804
elements in `a`.
1805
1806
Notes
1807
-----
1808
.. versionadded:: 1.4.0
1809
1810
See Also
1811
--------
1812
flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
1813
notmasked_contiguous, clump_masked
1814
1815
Examples
1816
--------
1817
>>> a = np.ma.masked_array(np.arange(10))
1818
>>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked
1819
>>> np.ma.clump_unmasked(a)
1820
[slice(3, 6, None), slice(7, 8, None)]
1821
1822
"""
1823
mask = getattr(a, '_mask', nomask)
1824
if mask is nomask:
1825
return [slice(0, a.size)]
1826
return _ezclump(~mask)
1827
1828
1829
def clump_masked(a):
1830
"""
1831
Returns a list of slices corresponding to the masked clumps of a 1-D array.
1832
(A "clump" is defined as a contiguous region of the array).
1833
1834
Parameters
1835
----------
1836
a : ndarray
1837
A one-dimensional masked array.
1838
1839
Returns
1840
-------
1841
slices : list of slice
1842
The list of slices, one for each continuous region of masked elements
1843
in `a`.
1844
1845
Notes
1846
-----
1847
.. versionadded:: 1.4.0
1848
1849
See Also
1850
--------
1851
flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
1852
notmasked_contiguous, clump_unmasked
1853
1854
Examples
1855
--------
1856
>>> a = np.ma.masked_array(np.arange(10))
1857
>>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked
1858
>>> np.ma.clump_masked(a)
1859
[slice(0, 3, None), slice(6, 7, None), slice(8, 10, None)]
1860
1861
"""
1862
mask = ma.getmask(a)
1863
if mask is nomask:
1864
return []
1865
return _ezclump(mask)
1866
1867
1868
###############################################################################
1869
# Polynomial fit #
1870
###############################################################################
1871
1872
1873
def vander(x, n=None):
1874
"""
1875
Masked values in the input array result in rows of zeros.
1876
1877
"""
1878
_vander = np.vander(x, n)
1879
m = getmask(x)
1880
if m is not nomask:
1881
_vander[m] = 0
1882
return _vander
1883
1884
vander.__doc__ = ma.doc_note(np.vander.__doc__, vander.__doc__)
1885
1886
1887
def polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False):
1888
"""
1889
Any masked values in x is propagated in y, and vice-versa.
1890
1891
"""
1892
x = asarray(x)
1893
y = asarray(y)
1894
1895
m = getmask(x)
1896
if y.ndim == 1:
1897
m = mask_or(m, getmask(y))
1898
elif y.ndim == 2:
1899
my = getmask(mask_rows(y))
1900
if my is not nomask:
1901
m = mask_or(m, my[:, 0])
1902
else:
1903
raise TypeError("Expected a 1D or 2D array for y!")
1904
1905
if w is not None:
1906
w = asarray(w)
1907
if w.ndim != 1:
1908
raise TypeError("expected a 1-d array for weights")
1909
if w.shape[0] != y.shape[0]:
1910
raise TypeError("expected w and y to have the same length")
1911
m = mask_or(m, getmask(w))
1912
1913
if m is not nomask:
1914
not_m = ~m
1915
if w is not None:
1916
w = w[not_m]
1917
return np.polyfit(x[not_m], y[not_m], deg, rcond, full, w, cov)
1918
else:
1919
return np.polyfit(x, y, deg, rcond, full, w, cov)
1920
1921
polyfit.__doc__ = ma.doc_note(np.polyfit.__doc__, polyfit.__doc__)
1922
1923