Efficiently check if numpy ndarray values are strictly increasing

Question:

I’m having a numpy ndarray where I would like to check if each row vector is monotonically increasing.

Example:

a = np.asarray([[1,2,3],[1,5,7],[4,3,6]])
monotonically_increasing(a)

Expected return:

[True, True, False]

I’m not entirely sure how to efficiently do this, since the matrices are expected to be quite large (~1000×1000), and was hoping for some help.

Asked By: Jimmy C

||

Answers:

You can make a function like this:

def monotonically_increasing(l):
    return all(x < y for x, y in zip(l, l[1:]))

and then check for it, sublist for sublist, so

[monotonically_increasing(sublist) for sublist in a]
Answered By: Mathias711
>>> import numpy as np
>>> a = np.asarray([[1,2,3],[1,5,7],[4,3,6]])

Find the difference between each element. np.diff has an argument that lets you specify the axis to perform the diff

>>> np.diff(a)
array([[ 1,  1],
       [ 4,  2],
       [-1,  3]])

Check to see if each difference is greater than 0.

>>> np.diff(a) > 0
array([[ True,  True],
       [ True,  True],
       [False,  True]], dtype=bool)

Check to see if all the differences are > 0

>>> np.all(np.diff(a) > 0)
False
>>> 

As suggested by @Jaime – check that each element is greater than the element to its left:

np.all(a[:, 1:] >= a[:, :-1], axis=1)

Which appears to be about twice as fast/efficient as my diff solution.

Answered By: wwii

To add to the answers provided @Jaime and all, to get the exact place where there are violations, in addition to just determining if they are strictly increasing or decreasing, I chained this as follows

a = np.array( [[1,2,3], [5,4,3], [4,5,6], [4,6,3]])
a[np.where 
   ( np.invert  
     (np.all(a[:, 1:] >= a[:, :-1], axis=1)) 
   ) 
 ]
 Result:
  array([[5, 4, 3],
   [4, 6, 3]])
Answered By: Srinivas

There was another question related to how to handle strictly decreasing from @igorkf. I combined that answer into a useful function.

def check_monotonicity (data: np.array, increasing: bool, axis: int) -> np.array :
  if increasing: # strictly increasing
    return data [np.where (
             np.invert (
                 (np.all(data[:, 1:] >= data[:, :-1], axis=axis))
             ) ) ]
  else: # strictly decreasing
    return data [np.where (
             np.invert (
                 (np.all(data[:, 0:-1] >= data[:, 1:], axis=axis))
             ) ) ]
Answered By: Srinivas
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.