Make a numpy array monotonic without a Python loop

2019-06-06 06:21发布

问题:

I have a 1D array of values which is supposed to be monotonic (let's say decreasing), but there are random regions where the value increases with index.

I need an array where each region is replaced with a value directly preceding it, so that the resulting array is sorted.

So if given array is:

a = np.array([10.0, 9.5, 8.0, 7.2, 7.8, 8.0, 7.0, 5.0, 3.0, 2.5, 3.0, 2.0])

I want the result to be

b = np.array([10.0, 9.5, 8.0, 7.2, 7.2, 7.2, 7.0, 5.0, 3.0, 2.5, 2.5, 2.0])

Here's a graphical representation:

I know how to achieve it with a Python loop, but is there a way to do this with NumPy machinery?

Python code for clarity:

b = np.array(a)
for i in range(1, b.size):
    if b[i] > b[i-1]:
        b[i] = b[i-1]

回答1:

You can use np.minimum.accumulate to collect the minimum values as you move through the array:

>>> np.minimum.accumulate(a)
array([ 10. ,   9.5,   8. ,   7.2,   7.2,   7.2,   7. ,   5. ,   3. ,
         2.5,   2.5,   2. ])

At each element in the array, this function returns the minimum value seen so far.

If you wanted an array to be monotonic increasing, you could use np.maximum.accumulate.

Many other universal functions in NumPy have an accumulate method to simulate looping through an array, applying the function to each element and collecting the returned values into an array of the same size.