Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make a numpy array monotonic without a Python loop

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:

example

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]
like image 601
Lev Levitsky Avatar asked Feb 17 '15 14:02

Lev Levitsky


People also ask

Why NumPy array operations are faster than looping?

NumPy Arrays are faster than Python Lists because of the following reasons: An array is a collection of homogeneous data-types that are stored in contiguous memory locations. On the other hand, a list in Python is a collection of heterogeneous data types stored in non-contiguous memory locations.

Is NumPy always faster than python?

Because the Numpy array is densely packed in memory due to its homogeneous type, it also frees the memory faster. So overall a task executed in Numpy is around 5 to 100 times faster than the standard python list, which is a significant leap in terms of speed.

Does NumPy use for loops?

Numpy for loop is used for iterating through numpy arrays of different dimensions, which is created using the python numpy library and using the for loop, multiple operations can be done going through each element in the array by one.

What is monotonic array in python?

An array is monotonic if it is either monotone increasing or monotone decreasing. An array A is monotone increasing if for all i <= j, A[i] <= A[j]. An array A is monotone decreasing if for all i <= j, A[i] >= A[j]. Return “True” if the given array A is monotonic else return “False” (without quotes).


1 Answers

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.

like image 141
Alex Riley Avatar answered Sep 20 '22 01:09

Alex Riley