summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorahaldane <ealloc@gmail.com>2016-10-20 18:07:17 -0400
committerGitHub <noreply@github.com>2016-10-20 18:07:17 -0400
commit8a9b04cbe7d7d45989500b6aad51e636523e305e (patch)
tree2a6ef534f04ad64aa9daa78da075ddd9b0f95419
parent88a66d8d0464caf57f40cf85a24156042e7ff0d7 (diff)
parent4c2ad8a4a23524f422f476c1596c973c4308e5da (diff)
downloadpython-numpy-8a9b04cbe7d7d45989500b6aad51e636523e305e.tar.gz
python-numpy-8a9b04cbe7d7d45989500b6aad51e636523e305e.tar.bz2
python-numpy-8a9b04cbe7d7d45989500b6aad51e636523e305e.zip
Merge pull request #7922 from eric-wieser/np-ma-convolve
ENH: Add ma.convolve and ma.correlate for #6458
-rw-r--r--doc/release/1.12.0-notes.rst7
-rw-r--r--numpy/ma/core.py83
-rw-r--r--numpy/ma/tests/test_core.py19
3 files changed, 105 insertions, 4 deletions
diff --git a/doc/release/1.12.0-notes.rst b/doc/release/1.12.0-notes.rst
index 05ad4c152..0baa33049 100644
--- a/doc/release/1.12.0-notes.rst
+++ b/doc/release/1.12.0-notes.rst
@@ -254,6 +254,13 @@ context manager will work as expected. Additionally, it is possible
to use the context manager as a decorator which can be useful when
multiple tests give need to hide the same warning.
+New masked array functions ``ma.convolve`` and ``ma.correlate`` added
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+These functions wrapped the non-masked versions, but propagate through masked
+values. There are two different propagation modes. The default causes masked
+values to contaminate the result with masks, but the other mode only outputs
+masks if there is no alternative.
+
Improvements
============
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index c4a54acb4..4466dc0af 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -56,10 +56,10 @@ __all__ = [
'argmax', 'argmin', 'argsort', 'around', 'array', 'asanyarray',
'asarray', 'bitwise_and', 'bitwise_or', 'bitwise_xor', 'bool_', 'ceil',
'choose', 'clip', 'common_fill_value', 'compress', 'compressed',
- 'concatenate', 'conjugate', 'copy', 'cos', 'cosh', 'count', 'cumprod',
- 'cumsum', 'default_fill_value', 'diag', 'diagonal', 'diff', 'divide',
- 'dump', 'dumps', 'empty', 'empty_like', 'equal', 'exp', 'expand_dims',
- 'fabs', 'filled', 'fix_invalid', 'flatten_mask',
+ 'concatenate', 'conjugate', 'convolve', 'copy', 'correlate', 'cos', 'cosh',
+ 'count', 'cumprod', 'cumsum', 'default_fill_value', 'diag', 'diagonal',
+ 'diff', 'divide', 'dump', 'dumps', 'empty', 'empty_like', 'equal', 'exp',
+ 'expand_dims', 'fabs', 'filled', 'fix_invalid', 'flatten_mask',
'flatten_structured_array', 'floor', 'floor_divide', 'fmod',
'frombuffer', 'fromflex', 'fromfunction', 'getdata', 'getmask',
'getmaskarray', 'greater', 'greater_equal', 'harden_mask', 'hypot',
@@ -7366,6 +7366,81 @@ outer.__doc__ = doc_note(np.outer.__doc__,
outerproduct = outer
+def _convolve_or_correlate(f, a, v, mode, propagate_mask):
+ """
+ Helper function for ma.correlate and ma.convolve
+ """
+ if propagate_mask:
+ # results which are contributed to by either item in any pair being invalid
+ mask = (
+ f(getmaskarray(a), np.ones(np.shape(v), dtype=np.bool), mode=mode)
+ | f(np.ones(np.shape(a), dtype=np.bool), getmaskarray(v), mode=mode)
+ )
+ data = f(getdata(a), getdata(v), mode=mode)
+ else:
+ # results which are not contributed to by any pair of valid elements
+ mask = ~f(~getmaskarray(a), ~getmaskarray(v))
+ data = f(filled(a, 0), filled(v, 0), mode=mode)
+
+ return masked_array(data, mask=mask)
+
+
+def correlate(a, v, mode='valid', propagate_mask=True):
+ """
+ Cross-correlation of two 1-dimensional sequences.
+
+ Parameters
+ ----------
+ a, v : array_like
+ Input sequences.
+ mode : {'valid', 'same', 'full'}, optional
+ Refer to the `np.convolve` docstring. Note that the default
+ is 'valid', unlike `convolve`, which uses 'full'.
+ propagate_mask : bool
+ If True, then a result element is masked if any masked element contributes towards it.
+ If False, then a result element is only masked if no non-masked element
+ contribute towards it
+
+ Returns
+ -------
+ out : MaskedArray
+ Discrete cross-correlation of `a` and `v`.
+
+ See Also
+ --------
+ numpy.correlate : Equivalent function in the top-level NumPy module.
+ """
+ return _convolve_or_correlate(np.correlate, a, v, mode, propagate_mask)
+
+
+def convolve(a, v, mode='full', propagate_mask=True):
+ """
+ Returns the discrete, linear convolution of two one-dimensional sequences.
+
+ Parameters
+ ----------
+ a, v : array_like
+ Input sequences.
+ mode : {'valid', 'same', 'full'}, optional
+ Refer to the `np.convolve` docstring.
+ propagate_mask : bool
+ If True, then if any masked element is included in the sum for a result
+ element, then the result is masked.
+ If False, then the result element is only masked if no non-masked cells
+ contribute towards it
+
+ Returns
+ -------
+ out : MaskedArray
+ Discrete, linear convolution of `a` and `v`.
+
+ See Also
+ --------
+ numpy.convolve : Equivalent function in the top-level NumPy module.
+ """
+ return _convolve_or_correlate(np.convolve, a, v, mode, propagate_mask)
+
+
def allequal(a, b, fill_value=True):
"""
Return True if all entries of a and b are equal, using
diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py
index a4887aaf0..9b65643ed 100644
--- a/numpy/ma/tests/test_core.py
+++ b/numpy/ma/tests/test_core.py
@@ -4086,6 +4086,25 @@ class TestMaskedArrayFunctions(TestCase):
test = np.ma.compressed(M(shape=(0,1,2)))
assert_equal(test, 42)
+ def test_convolve(self):
+ a = masked_equal(np.arange(5), 2)
+ b = np.array([1, 1])
+ test = np.ma.convolve(a, b)
+ assert_equal(test, masked_equal([0, 1, -1, -1, 7, 4], -1))
+
+ test = np.ma.convolve(a, b, propagate_mask=False)
+ assert_equal(test, masked_equal([0, 1, 1, 3, 7, 4], -1))
+
+ test = np.ma.convolve([1, 1], [1, 1, 1])
+ assert_equal(test, masked_equal([1, 2, 2, 1], -1))
+
+ a = [1, 1]
+ b = masked_equal([1, -1, -1, 1], -1)
+ test = np.ma.convolve(a, b, propagate_mask=False)
+ assert_equal(test, masked_equal([1, 1, -1, 1, 1], -1))
+ test = np.ma.convolve(a, b, propagate_mask=True)
+ assert_equal(test, masked_equal([-1, -1, -1, -1, -1], -1))
+
class TestMaskedFields(TestCase):