Home > Back-end >  NumPy elementwise chaining comparison (a <= b <= c)
NumPy elementwise chaining comparison (a <= b <= c)

Time:07-09

Python support chaining comparison:

1<2<3<4

How to do that for NumPy?

If only 3 array, we can do this:

a = np.array([1,2,4,5,6])
b = np.array([2,6,1,5,6])
c = np.array([7,4,6,6,8])
np.logical_and((a <= b),(b <= c))

With 4 array, it becomes too burdensome since np.logical_and only accept 2 inputs.

a = np.array([1,2,4,5,6])
b = np.array([2,6,1,5,6])
c = np.array([7,4,6,6,8])
d = np.array([8,9,9,9,2])
np.logical_and((a <= b),(b <= c))  # work
np.logical_and((b <= c),(c <= d))  # work
np.logical_and((a <= b),(b <= c),(c <= d))  # not work

Edit: Slightly add complexity, on 2D:

a = np.array([[1,2,3],
              [4,5,6]])
b = np.array([[2,6,3],
              [1,5,6]])
c = np.array([[7,4,3],
              [6,6,8]])
d = np.array([[8,9,3],
              [9,9,2]])

CodePudding user response:

You can use the reduce method from functools.

import functools
import numpy as np

a = np.array([1,2,4,5,6])
b = np.array([2,6,1,5,6])
c = np.array([7,4,6,6,8])
d = np.array([8,9,9,9,2])

arr = [a <= b, b <= c, c <= d]
result = functools.reduce(np.logical_and, arr)

CodePudding user response:

Simply use &:

(a <= b) & (b <= c) & (c <= d)

As the doc says:

The & operator can be used as a shorthand for np.logical_and on boolean ndarrays.

CodePudding user response:

Benchmark:

Chaining (best: AndrejH)

%timeit functools.reduce(np.logical_and, [a <= b, b <= c, c <= d])  # AndrejH
6.27 µs ± 244 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit np.all([a<=b, b<=c, c<=d], axis=0)  # Quang Hoang
59.7 µs ± 8.37 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Chaining up to three array (best: OP)

%timeit np.logical_and((a <= b), (b <= c))  # OP
3.8 µs ± 339 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit functools.reduce(np.logical_and, [a <= b, b <= c])  # AndrejH
4.2 µs ± 75.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit np.all([a <= b, b <= c], axis=0)  # Quang Hoang
45.6 µs ± 6.13 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

CodePudding user response:

For this particular case, you can stack the arrays and check if each column is sorted.

np.apply_along_axis(lambda arr: all(arr[1:] >= arr[:-1]), 0, np.stack([a, b, c, d]))
# array([ True, False, False,  True, False])
  • Related