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