26

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 (~1000x1000), and was hoping for some help.

Mathias711
  • 6,444
  • 4
  • 38
  • 54
Jimmy C
  • 8,392
  • 10
  • 39
  • 60

2 Answers2

52
>>> 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.

wwii
  • 21,286
  • 7
  • 34
  • 74
  • 17
    It's probably faster to compare each item to the adjacent one directly, rather than comparing if their difference is greater than zero: `np.all(a[:, 1:] >= a[:, :-1], axis=1)` – Jaime Jun 09 '15 at 15:51
  • Concur. Worst case yours makes one pass and mine makes one pass for the diff and a *shorter* pass for ```np.all```. – wwii Jun 09 '15 at 17:38
  • @Jaime this is indeed the case, for 10**6 elements, `np.all(x[:-1] > x[1:])` takes 600us, while `np.all(np.diff(x) < 0)` takes 2.03ms, about 3 times longer. – lumbric Oct 07 '19 at 07:53
  • 1
    What if for **strictly decreasing** ? – igorkf Jan 21 '21 at 13:52
  • 1
    @igorkf - [Python - How to check list monotonicity](https://stackoverflow.com/questions/4983258/python-how-to-check-list-monotonicity) - too bad I didn't search and find that when I answered. Others searching with variations of `python numpy strictly decreasing site:stackoverflow.com` - this one too [Make a numpy array monotonic without a Python loop](https://stackoverflow.com/questions/28563711/make-a-numpy-array-monotonic-without-a-python-loop) – wwii Jan 21 '21 at 14:47
1

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]
Mathias711
  • 6,444
  • 4
  • 38
  • 54
  • 4
    the question is about numpy arrays, which may be GBs in size; looping over them is extremely slow; this answer could be improved by benchmarking various approaches with various array sizes – user2561747 Feb 28 '19 at 21:07