diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/ma/extras.py | 262 | ||||
-rw-r--r-- | numpy/ma/tests/test_extras.py | 264 |
2 files changed, 424 insertions, 102 deletions
diff --git a/numpy/ma/extras.py b/numpy/ma/extras.py index 006292cd5..b2f06ea6c 100644 --- a/numpy/ma/extras.py +++ b/numpy/ma/extras.py @@ -19,11 +19,14 @@ __all__ = ['apply_along_axis', 'atleast_1d', 'atleast_2d', 'atleast_3d', 'ediff1d', 'flatnotmasked_contiguous', 'flatnotmasked_edges', 'hsplit', 'hstack', + 'intersect1d', 'intersect1d_nu', 'mask_cols', 'mask_rowcols', 'mask_rows', 'masked_all', 'masked_all_like', 'median', 'mr_', 'notmasked_contiguous', 'notmasked_edges', 'polyfit', 'row_stack', + 'setdiff1d', 'setmember1d', 'setxor1d', + 'unique1d', 'union1d', 'vander', 'vstack', ] @@ -133,9 +136,12 @@ class _fromnxfunction: res.append(masked_array(_d, mask=_m)) return res -atleast_1d = _fromnxfunction('atleast_1d') -atleast_2d = _fromnxfunction('atleast_2d') -atleast_3d = _fromnxfunction('atleast_3d') +#atleast_1d = _fromnxfunction('atleast_1d') +#atleast_2d = _fromnxfunction('atleast_2d') +#atleast_3d = _fromnxfunction('atleast_3d') +atleast_1d = np.atleast_1d +atleast_2d = np.atleast_2d +atleast_3d = np.atleast_3d vstack = row_stack = _fromnxfunction('vstack') hstack = _fromnxfunction('hstack') @@ -587,73 +593,211 @@ def dot(a,b, strict=False): m = ~np.dot(am, bm) return masked_array(d, mask=m) -#............................................................................... -def ediff1d(array, to_end=None, to_begin=None): +#####-------------------------------------------------------------------------- +#---- --- arraysetops --- +#####-------------------------------------------------------------------------- + +def ediff1d(arr, to_end=None, to_begin=None): """ - Return the differences between consecutive elements of an - array, possibly with prefixed and/or appended values. + Computes the differences between consecutive elements of an array. - Parameters - ---------- - array : {array} - Input array, will be flattened before the difference is taken. - to_end : {number}, optional - If provided, this number will be tacked onto the end of the returned - differences. - to_begin : {number}, optional - If provided, this number will be taked onto the beginning of the - returned differences. + This function is the equivalent of `numpy.ediff1d` that takes masked + values into account. + + See Also + -------- + numpy.eddif1d : equivalent function for ndarrays. Returns ------- - ed : {array} - The differences. Loosely, this will be (ary[1:] - ary[:-1]). - + output : MaskedArray + """ - a = masked_array(array, copy=True) - if a.ndim > 1: - a.reshape((a.size,)) - (d, m, n) = (a._data, a._mask, a.size-1) - dd = d[1:]-d[:-1] - if m is nomask: - dm = nomask - else: - dm = m[1:]-m[:-1] + arr = ma.asanyarray(arr).flat + ed = arr[1:] - arr[:-1] + arrays = [ed] # + if to_begin is not None: + arrays.insert(0, to_begin) if to_end is not None: - to_end = asarray(to_end) - nend = to_end.size - if to_begin is not None: - to_begin = asarray(to_begin) - nbegin = to_begin.size - r_data = np.empty((n+nend+nbegin,), dtype=a.dtype) - r_mask = np.zeros((n+nend+nbegin,), dtype=bool) - r_data[:nbegin] = to_begin._data - r_mask[:nbegin] = to_begin._mask - r_data[nbegin:-nend] = dd - r_mask[nbegin:-nend] = dm - else: - r_data = np.empty((n+nend,), dtype=a.dtype) - r_mask = np.zeros((n+nend,), dtype=bool) - r_data[:-nend] = dd - r_mask[:-nend] = dm - r_data[-nend:] = to_end._data - r_mask[-nend:] = to_end._mask + arrays.append(to_end) + # + if len(arrays) != 1: + # We'll save ourselves a copy of a potentially large array in the common + # case where neither to_begin or to_end was given. + ed = hstack(arrays) + # + return ed + + +def unique1d(ar1, return_index=False, return_inverse=False): + """ + Finds the unique elements of an array. + + Masked values are considered the same element (masked). + + The output array is always a MaskedArray. + + See Also + -------- + np.unique1d : equivalent function for ndarrays. + """ + output = np.unique1d(ar1, + return_index=return_index, + return_inverse=return_inverse) + if isinstance(output, tuple): + output = list(output) + output[0] = output[0].view(MaskedArray) + output = tuple(output) + else: + output = output.view(MaskedArray) + return output + + +def intersect1d(ar1, ar2): + """ + Returns the repeated or unique elements belonging to the two arrays. + + Masked values are assumed equals one to the other. + The output is always a masked array + + See Also + -------- + numpy.intersect1d : equivalent function for ndarrays. + + Examples + -------- + >>> x = array([1, 3, 3, 3], mask=[0, 0, 0, 1]) + >>> y = array([3, 1, 1, 1], mask=[0, 0, 0, 1]) + >>> intersect1d(x, y) + masked_array(data = [1 1 3 3 --], + mask = [False False False False True], + fill_value = 999999) + """ + aux = ma.concatenate((ar1,ar2)) + aux.sort() + return aux[aux[1:] == aux[:-1]] + + + +def intersect1d_nu(ar1, ar2): + """ + Returns the unique elements common to both arrays. + + Masked values are considered equal one to the other. + The output is always a masked array. + + See Also + -------- + intersect1d : Returns repeated or unique common elements. + numpy.intersect1d_nu : equivalent function for ndarrays. + + Examples + -------- + >>> x = array([1, 3, 3, 3], mask=[0, 0, 0, 1]) + >>> y = array([3, 1, 1, 1], mask=[0, 0, 0, 1]) + >>> intersect1d_nu(x, y) + masked_array(data = [1 3 --], + mask = [False False True], + fill_value = 999999) + + """ + # Might be faster than unique1d( intersect1d( ar1, ar2 ) )? + aux = ma.concatenate((unique1d(ar1), unique1d(ar2))) + aux.sort() + return aux[aux[1:] == aux[:-1]] + + + +def setxor1d(ar1, ar2): + """ + Set exclusive-or of 1D arrays with unique elements. + + See Also + -------- + numpy.setxor1d : equivalent function for ndarrays + + """ + aux = ma.concatenate((ar1, ar2)) + if aux.size == 0: + return aux + aux.sort() + auxf = aux.filled() +# flag = ediff1d( aux, to_end = 1, to_begin = 1 ) == 0 + flag = ma.concatenate(([True], (auxf[1:] != auxf[:-1]), [True])) +# flag2 = ediff1d( flag ) == 0 + flag2 = (flag[1:] == flag[:-1]) + return aux[flag2] + + +def setmember1d(ar1, ar2): + """ + Return a boolean array set True where first element is in second array. + + See Also + -------- + numpy.setmember1d : equivalent function for ndarrays. + + """ + ar1 = ma.asanyarray(ar1) + ar2 = ma.asanyarray( ar2 ) + ar = ma.concatenate((ar1, ar2 )) + b1 = ma.zeros(ar1.shape, dtype = np.int8) + b2 = ma.ones(ar2.shape, dtype = np.int8) + tt = ma.concatenate((b1, b2)) + + # We need this to be a stable sort, so always use 'mergesort' here. The + # values from the first array should always come before the values from the + # second array. + perm = ar.argsort(kind='mergesort') + aux = ar[perm] + aux2 = tt[perm] +# flag = ediff1d( aux, 1 ) == 0 + flag = ma.concatenate((aux[1:] == aux[:-1], [False])) + ii = ma.where( flag * aux2 )[0] + aux = perm[ii+1] + perm[ii+1] = perm[ii] + perm[ii] = aux # - elif to_begin is not None: - to_begin = asarray(to_begin) - nbegin = to_begin.size - r_data = np.empty((n+nbegin,), dtype=a.dtype) - r_mask = np.zeros((n+nbegin,), dtype=bool) - r_data[:nbegin] = to_begin._data - r_mask[:nbegin] = to_begin._mask - r_data[nbegin:] = dd - r_mask[nbegin:] = dm + indx = perm.argsort(kind='mergesort')[:len( ar1 )] # + return flag[indx] + + +def union1d(ar1, ar2): + """ + Union of 1D arrays with unique elements. + + See also + -------- + numpy.union1d : equivalent function for ndarrays. + + """ + return unique1d(ma.concatenate((ar1, ar2))) + + +def setdiff1d(ar1, ar2): + """ + Set difference of 1D arrays with unique elements. + + See Also + -------- + numpy.setdiff1d : equivalent function for ndarrays + + """ + aux = setmember1d(ar1,ar2) + if aux.size == 0: + return aux else: - r_data = dd - r_mask = dm - return masked_array(r_data, mask=r_mask) + return ma.asarray(ar1)[aux == 0] + + + +#####-------------------------------------------------------------------------- +#---- --- Covariance --- +#####-------------------------------------------------------------------------- + + def _covhelper(x, y=None, rowvar=True, allow_masked=True): diff --git a/numpy/ma/tests/test_extras.py b/numpy/ma/tests/test_extras.py index 7c051377a..5ae7bd72c 100644 --- a/numpy/ma/tests/test_extras.py +++ b/numpy/ma/tests/test_extras.py @@ -338,39 +338,7 @@ class Test2DFunctions(TestCase): c = dot(b,a,False) assert_equal(c, np.dot(b.filled(0),a.filled(0))) - def test_ediff1d(self): - "Tests mediff1d" - x = masked_array(np.arange(5), mask=[1,0,0,0,1]) - difx_d = (x._data[1:]-x._data[:-1]) - difx_m = (x._mask[1:]-x._mask[:-1]) - dx = ediff1d(x) - assert_equal(dx._data, difx_d) - assert_equal(dx._mask, difx_m) - # - dx = ediff1d(x, to_begin=masked) - assert_equal(dx._data, np.r_[0,difx_d]) - assert_equal(dx._mask, np.r_[1,difx_m]) - dx = ediff1d(x, to_begin=[1,2,3]) - assert_equal(dx._data, np.r_[[1,2,3],difx_d]) - assert_equal(dx._mask, np.r_[[0,0,0],difx_m]) - # - dx = ediff1d(x, to_end=masked) - assert_equal(dx._data, np.r_[difx_d,0]) - assert_equal(dx._mask, np.r_[difx_m,1]) - dx = ediff1d(x, to_end=[1,2,3]) - assert_equal(dx._data, np.r_[difx_d,[1,2,3]]) - assert_equal(dx._mask, np.r_[difx_m,[0,0,0]]) - # - dx = ediff1d(x, to_end=masked, to_begin=masked) - assert_equal(dx._data, np.r_[0,difx_d,0]) - assert_equal(dx._mask, np.r_[1,difx_m,1]) - dx = ediff1d(x, to_end=[1,2,3], to_begin=masked) - assert_equal(dx._data, np.r_[0,difx_d,[1,2,3]]) - assert_equal(dx._mask, np.r_[1,difx_m,[0,0,0]]) - # - dx = ediff1d(x._data, to_end=masked, to_begin=masked) - assert_equal(dx._data, np.r_[0,difx_d,0]) - assert_equal(dx._mask, np.r_[1,0,0,0,0,1]) + class TestApplyAlongAxis(TestCase): # @@ -383,6 +351,7 @@ class TestApplyAlongAxis(TestCase): assert_equal(xa,[[1,4],[7,10]]) + class TestMedian(TestCase): # def test_2d(self): @@ -422,11 +391,12 @@ class TestMedian(TestCase): assert_equal(median(x,0), [[12,10],[8,9],[16,17]]) + class TestCov(TestCase): - # + def setUp(self): self.data = array(np.random.rand(12)) - # + def test_1d_wo_missing(self): "Test cov on 1D variable w/o missing values" x = self.data @@ -434,7 +404,7 @@ class TestCov(TestCase): assert_almost_equal(np.cov(x, rowvar=False), cov(x, rowvar=False)) assert_almost_equal(np.cov(x, rowvar=False, bias=True), cov(x, rowvar=False, bias=True)) - # + def test_2d_wo_missing(self): "Test cov on 1 2D variable w/o missing values" x = self.data.reshape(3,4) @@ -442,7 +412,7 @@ class TestCov(TestCase): assert_almost_equal(np.cov(x, rowvar=False), cov(x, rowvar=False)) assert_almost_equal(np.cov(x, rowvar=False, bias=True), cov(x, rowvar=False, bias=True)) - # + def test_1d_w_missing(self): "Test cov 1 1D variable w/missing values" x = self.data @@ -466,7 +436,7 @@ class TestCov(TestCase): cov(x, x[::-1], rowvar=False)) assert_almost_equal(np.cov(nx, nx[::-1], rowvar=False, bias=True), cov(x, x[::-1], rowvar=False, bias=True)) - # + def test_2d_w_missing(self): "Test cov on 2D variable w/ missing value" x = self.data @@ -486,11 +456,12 @@ class TestCov(TestCase): np.cov(xf, rowvar=False, bias=True) * x.shape[0]/frac) + class TestCorrcoef(TestCase): - # + def setUp(self): self.data = array(np.random.rand(12)) - # + def test_1d_wo_missing(self): "Test cov on 1D variable w/o missing values" x = self.data @@ -499,7 +470,7 @@ class TestCorrcoef(TestCase): corrcoef(x, rowvar=False)) assert_almost_equal(np.corrcoef(x, rowvar=False, bias=True), corrcoef(x, rowvar=False, bias=True)) - # + def test_2d_wo_missing(self): "Test corrcoef on 1 2D variable w/o missing values" x = self.data.reshape(3,4) @@ -508,7 +479,7 @@ class TestCorrcoef(TestCase): corrcoef(x, rowvar=False)) assert_almost_equal(np.corrcoef(x, rowvar=False, bias=True), corrcoef(x, rowvar=False, bias=True)) - # + def test_1d_w_missing(self): "Test corrcoef 1 1D variable w/missing values" x = self.data @@ -532,7 +503,7 @@ class TestCorrcoef(TestCase): corrcoef(x, x[::-1], rowvar=False)) assert_almost_equal(np.corrcoef(nx, nx[::-1], rowvar=False, bias=True), corrcoef(x, x[::-1], rowvar=False, bias=True)) - # + def test_2d_w_missing(self): "Test corrcoef on 2D variable w/ missing value" x = self.data @@ -575,6 +546,213 @@ class TestPolynomial(TestCase): assert_almost_equal(a, a_) + +class TestArraySetOps(TestCase): + # + def test_unique1d_onlist(self): + "Test unique1d on list" + data = [1, 1, 1, 2, 2, 3] + test = unique1d(data, return_index=True, return_inverse=True) + self.failUnless(isinstance(test[0], MaskedArray)) + assert_equal(test[0], masked_array([1, 2, 3], mask=[0, 0, 0])) + assert_equal(test[1], [0, 3, 5]) + assert_equal(test[2], [0, 0, 0, 1, 1, 2]) + + def test_unique1d_onmaskedarray(self): + "Test unique1d on masked data w/use_mask=True" + data = masked_array([1, 1, 1, 2, 2, 3], mask=[0, 0, 1, 0, 1, 0]) + test = unique1d(data, return_index=True, return_inverse=True) + assert_equal(test[0], masked_array([1, 2, 3, -1], mask=[0, 0, 0, 1])) + assert_equal(test[1], [0, 3, 5, 2]) + assert_equal(test[2], [0, 0, 3, 1, 3, 2]) + # + data.fill_value = 3 + data = masked_array([1, 1, 1, 2, 2, 3], + mask=[0, 0, 1, 0, 1, 0], fill_value=3) + test = unique1d(data, return_index=True, return_inverse=True) + assert_equal(test[0], masked_array([1, 2, 3, -1], mask=[0, 0, 0, 1])) + assert_equal(test[1], [0, 3, 5, 2]) + assert_equal(test[2], [0, 0, 3, 1, 3, 2]) + + def test_unique1d_allmasked(self): + "Test all masked" + data = masked_array([1, 1, 1], mask=True) + test = unique1d(data, return_index=True, return_inverse=True) + assert_equal(test[0], masked_array([1,], mask=[True])) + assert_equal(test[1], [0]) + assert_equal(test[2], [0, 0, 0]) + # + "Test masked" + data = masked + test = unique1d(data, return_index=True, return_inverse=True) + assert_equal(test[0], masked_array(masked)) + assert_equal(test[1], [0]) + assert_equal(test[2], [0]) + + def test_ediff1d(self): + "Tests mediff1d" + x = masked_array(np.arange(5), mask=[1,0,0,0,1]) + control = array([1, 1, 1, 4], mask=[1, 0, 0, 1]) + test = ediff1d(x) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + # + def test_ediff1d_tobegin(self): + "Test ediff1d w/ to_begin" + x = masked_array(np.arange(5), mask=[1,0,0,0,1]) + test = ediff1d(x, to_begin=masked) + control = array([0, 1, 1, 1, 4], mask=[1, 1, 0, 0, 1]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + # + test = ediff1d(x, to_begin=[1,2,3]) + control = array([1, 2, 3, 1, 1, 1, 4], mask=[0, 0, 0, 1, 0, 0, 1]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + # + def test_ediff1d_toend(self): + "Test ediff1d w/ to_end" + x = masked_array(np.arange(5), mask=[1,0,0,0,1]) + test = ediff1d(x, to_end=masked) + control = array([1, 1, 1, 4, 0], mask=[1, 0, 0, 1, 1]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + # + test = ediff1d(x, to_end=[1,2,3]) + control = array([1, 1, 1, 4, 1, 2, 3], mask=[1, 0, 0, 1, 0, 0, 0]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + # + def test_ediff1d_tobegin_toend(self): + "Test ediff1d w/ to_begin and to_end" + x = masked_array(np.arange(5), mask=[1,0,0,0,1]) + test = ediff1d(x, to_end=masked, to_begin=masked) + control = array([0, 1, 1, 1, 4, 0], mask=[1, 1, 0, 0, 1, 1]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + # + test = ediff1d(x, to_end=[1,2,3], to_begin=masked) + control = array([0, 1, 1, 1, 4, 1, 2, 3], mask=[1, 1, 0, 0, 1, 0, 0, 0]) + assert_equal(test, control) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + # + def test_ediff1d_ndarray(self): + "Test ediff1d w/ a ndarray" + x = np.arange(5) + test = ediff1d(x) + control = array([1, 1, 1, 1], mask=[0, 0, 0, 0]) + assert_equal(test, control) + self.failUnless(isinstance(test, MaskedArray)) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + # + test = ediff1d(x, to_end=masked, to_begin=masked) + control = array([0, 1, 1, 1, 1, 0], mask=[1, 0, 0, 0, 0, 1]) + self.failUnless(isinstance(test, MaskedArray)) + assert_equal(test.data, control.data) + assert_equal(test.mask, control.mask) + + + def test_intersect1d(self): + "Test intersect1d" + x = array([1, 3, 3, 3], mask=[0, 0, 0, 1]) + y = array([3, 1, 1, 1], mask=[0, 0, 0, 1]) + test = intersect1d(x, y) + control = array([1, 1, 3, 3, -1], mask=[0, 0, 0, 0, 1]) + assert_equal(test, control) + + + def test_intersect1d_nu(self): + "Test intersect1d_nu" + x = array([1, 3, 3, 3], mask=[0, 0, 0, 1]) + y = array([3, 1, 1, 1], mask=[0, 0, 0, 1]) + test = intersect1d_nu(x, y) + control = array([1, 3, -1], mask=[0, 0, 1]) + assert_equal(test, control) + + + def test_setxor1d(self): + "Test setxor1d" + a = array([1, 2, 5, 7, -1], mask=[0, 0, 0, 0, 1]) + b = array([1, 2, 3, 4, 5, -1], mask=[0, 0, 0, 0, 0, -1]) + test = setxor1d(a, b) + assert_equal(test, array([3, 4, 7])) + # + a = array([1, 2, 5, 7, -1], mask=[0, 0, 0, 0, 1]) + b = [1, 2, 3, 4, 5] + test = setxor1d(a, b) + assert_equal(test, array([3, 4, 7, -1], mask=[0, 0, 0, 1])) + # + a = array( [1, 2, 3] ) + b = array( [6, 5, 4] ) + test = setxor1d(a, b) + assert(isinstance(test, MaskedArray)) + assert_equal(test, [1, 2, 3, 4, 5, 6]) + # + a = array([1, 8, 2, 3], mask=[0, 1, 0, 0]) + b = array([6, 5, 4, 8], mask=[0, 0, 0, 1]) + test = setxor1d(a, b) + assert(isinstance(test, MaskedArray)) + assert_equal(test, [1, 2, 3, 4, 5, 6]) + # + assert_array_equal([], setxor1d([],[])) + + + def test_setmember1d( self ): + "Test setmember1d" + a = array([1, 2, 5, 7, -1], mask=[0, 0, 0, 0, 1]) + b = array([1, 2, 3, 4, 5, -1], mask=[0, 0, 0, 0, 0, -1]) + test = setmember1d(a, b) + assert_equal(test, [True, True, True, False, True]) + # + assert_array_equal([], setmember1d([],[])) + + + def test_union1d( self ): + "Test union1d" + a = array([1, 2, 5, 7, -1], mask=[0, 0, 0, 0, 1]) + b = array([1, 2, 3, 4, 5, -1], mask=[0, 0, 0, 0, 0, -1]) + test = union1d(a, b) + control = array([1, 2, 3, 4, 5, 7, -1], mask=[0, 0, 0, 0, 0, 0, 1]) + assert_equal(test, control) + # + assert_array_equal([], setmember1d([],[])) + + + def test_setdiff1d( self ): + "Test setdiff1d" + a = array([6, 5, 4, 7, 1, 2, 1], mask=[0, 0, 0, 0, 0, 0, 1]) + b = array([2, 4, 3, 3, 2, 1, 5]) + test = setdiff1d(a, b) + assert_equal(test, array([6, 7, -1], mask=[0, 0, 1])) + # + a = arange(10) + b = arange(8) + assert_equal(setdiff1d(a, b), array([8, 9])) + + + def test_setdiff1d_char_array(self): + "Test setdiff1d_charray" + a = np.array(['a','b','c']) + b = np.array(['a','b','s']) + assert_array_equal(setdiff1d(a,b), np.array(['c'])) + + + + +class TestShapeBase(TestCase): + # + def test_atleast1d(self): + pass + + ############################################################################### #------------------------------------------------------------------------------ if __name__ == "__main__": |