NumPy: Compare two arrays element-wise

Modified: | Tags: Python, NumPy

In NumPy, to compare two arrays (ndarray) element-wise, use comparison operators such as > or ==, which return a Boolean ndarray. You can also compare an array to a scalar value.

Additionally, NumPy offers functions like np.array_equal() and np.array_equiv() to check if two arrays are equal, and np.isclose() and np.allclose() to check if each or all elements are close.

The NumPy version used in this article is as follows. Note that functionality may vary between versions.

import numpy as np

print(np.__version__)
# 1.26.1

Compare two NumPy arrays element-wise with comparison operators

A Boolean ndarray is returned

Consider the following two NumPy arrays (ndarray) as examples.

a = np.arange(12).reshape(3, 4)
print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

b = np.arange(12).reshape(4, 3).T
print(b)
# [[ 0  3  6  9]
#  [ 1  4  7 10]
#  [ 2  5  8 11]]

Using comparison operators like <, >, <=, >=, ==, !=, each element is compared and a Boolean ndarray is returned.

a_compare = a < b
print(a_compare)
# [[False  True  True  True]
#  [False False  True  True]
#  [False False False False]]

print(type(a_compare))
# <class 'numpy.ndarray'>

print(a_compare.dtype)
# bool

Since comparisons are based on values, differing data types (dtype) are not a problem.

b_float = b.astype(float)
print(b_float)
# [[ 0.  3.  6.  9.]
#  [ 1.  4.  7. 10.]
#  [ 2.  5.  8. 11.]]

print(b_float.dtype)
# float64

print(a == b_float)
# [[ True False False False]
#  [False False False False]
#  [False False False  True]]

When comparing floating point numbers (float) with ==, be careful of inaccuracies. To allow for some tolerance, use np.isclose() described below.

In NumPy, the shapes are aligned as much as possible by so-called broadcasting, even when comparing arrays with different shapes.

b_1d = np.arange(4, 8)
print(b_1d)
# [4 5 6 7]

print(a < b_1d)
# [[ True  True  True  True]
#  [False False False False]
#  [False False False False]]

When comparing with a scalar value, each element is compared with that value.

print(a < 6)
# [[ True  True  True  True]
#  [ True  True False False]
#  [False False False False]]

It is also possible to compare the result of an operation. For example, to check if elements are even, you could use the following approach:

print(a % 2)
# [[0 1 0 1]
#  [0 1 0 1]
#  [0 1 0 1]]

print(a % 2 == 0)
# [[ True False  True False]
#  [ True False  True False]
#  [ True False  True False]]

With np.count_nonzero(), np.all(), np.any()

np.count_nonzero() counts the True values in a Boolean ndarray, indicating how many elements meet a condition.

a = np.arange(12).reshape(3, 4)
print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

print(a < 6)
# [[ True  True  True  True]
#  [ True  True False False]
#  [False False False False]]

print(np.count_nonzero(a < 6))
# 6

Use np.all() to check if all elements are True, and np.any() to check if any element is True. Both functions allow row-wise or column-wise checks with the axis argument.

print(np.all(a < 6))
# False

print(np.all(a < 6, axis=1))
# [ True False False]

print(np.any(a < 6))
# True

print(np.any(a < 6, axis=1))
# [ True  True False]

For more details on combining comparison operators with np.count_nonzero(), np.all(), and np.any(), see the following article.

Compare with NaN: np.isnan()

For example, NaN can occur when reading a CSV file with missing data.

Since comparing NaN with NaN always returns False, you need to use np.isnan() to check for NaN values.

a_nan = np.array([0, 1, np.nan])
print(a_nan)
# [ 0.  1. nan]

print(a_nan == np.nan)
# [False False False]

print(np.isnan(a_nan))
# [False False  True]

Note that comparison to NaN using < or > also returns False.

print(a_nan > 0)
# [False  True False]

Use np.array_equal() or np.isclose(), as mentioned later, if you want True when NaN values are at the same position.

For multiple conditions: &, |

Python allows chaining conditions as follows:

x = 6

print(4 < x < 8)
# True

This syntax does not apply to ndarray. To specify multiple conditions, write each condition separately and combine them using & (AND) or | (OR).

a = np.arange(12).reshape(3, 4)
print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

# print(4 < a < 8)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

print((a > 4) & (a < 8))
# [[False False False False]
#  [False  True  True  True]
#  [False False False False]]

Note that using and or or, or omitting parentheses, raises an error.

# print((a > 4) and (a < 8))
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

# print(a > 4 & a < 8)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

For more details on this error, see the following article.

The same applies when comparing three or more arrays. It is possible in Python syntax to compare them together.

x = 6
y = 6
z = 6

print(x == y == z)
# True

This is also not allowed for ndarray. Combine conditions using & or |.

b = np.arange(12).reshape(4, 3).T
print(b)
# [[ 0  3  6  9]
#  [ 1  4  7 10]
#  [ 2  5  8 11]]

c = np.zeros((3, 4), int)
print(c)
# [[0 0 0 0]
#  [0 0 0 0]
#  [0 0 0 0]]

# print(a == b == c)
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

print((a == b) & (b == c))
# [[ True False False False]
#  [False False False False]
#  [False False False False]]

Check if two arrays are equal: np.array_equal(), np.array_equiv()

You can check if all elements of two arrays are equal using == and np.all().

a = np.array([0, 1, 2])
b = np.array([0, 1, 2])
c = np.array([3, 4, 5])

print(np.all(a == b))
# True

print(np.all(a == c))
# False

Alternatively, you can use the np.array_equal() and np.array_equiv() functions.

Specify array-like objects as the first and second arguments. If all elements are equal, these functions return True, otherwise False.

print(np.array_equal(a, b))
# True

print(np.array_equal(a, c))
# False

print(np.array_equiv(a, b))
# True

print(np.array_equiv(a, c))
# False

Like ==, different data types (dtype) are not a problem.

b_float = b.astype(float)

print(np.array_equal(a, b_float))
# True

print(np.array_equiv(a, b_float))
# True

np.array_equal() returns False if the shapes do not match, whereas np.array_equiv() allows comparisons with a scalar or a broadcastable array.

ones = np.array([1, 1, 1])

print(np.array_equal(ones, 1))
# False

print(np.array_equiv(ones, 1))
# True

a_1d = np.array([0, 1, 2])
a_2d = np.array([[0, 1, 2], [0, 1, 2], [0, 1, 2]])

print(np.array_equal(a_1d, a_2d))
# False

print(np.array_equiv(a_1d, a_2d))
# True

Comparisons between NaN values return False, even if they are in the same position.

a_nan = np.array([np.nan, 1, 2])
b_nan = np.array([np.nan, 1, 2])

print(np.array_equal(a_nan, b_nan))
# False

print(np.array_equiv(a_nan, b_nan))
# False

print(np.all(a_nan == b_nan))
# False

NumPy 1.19 introduced equal_nan as a third argument to np.array_equal(), allowing comparisons between NaN values to yield True when set to True. The default setting is False.

print(np.array_equal(a_nan, b_nan, True))
# True

Check if each element of two arrays is close: np.isclose()

Floating point numbers (float) are represented in binary internally, making it impossible to represent some decimal numbers exactly.

For example, 0.1 + 0.1 + 0.1 is not equal to 0.3.

print(0.1 + 0.1 + 0.1)
# 0.30000000000000004

a = np.array([0.3, 0.1 + 0.1 + 0.1])
print(a)
# [0.3 0.3]

b = np.array([0.3, 0.3])
print(b)
# [0.3 0.3]

print(a == b)
# [ True False]

Note that the output of print() is displayed as 0.3 in the above example because the default is to display up to 8 decimal places. You can change the setting with np.set_printoptions().

np.set_printoptions(precision=18)

print(a)
# [0.3                 0.30000000000000004]

np.isclose() checks if values are close element-wise within a tolerance. It is also possible to compare to a scalar or a broadcastable array.

print(np.isclose(a, b))
# [ True  True]

print(np.isclose(a, 0.3))
# [ True  True]

It can also compare scalar values, returning a scalar value.

print(np.isclose(0.1 + 0.1 + 0.1, 0.3))
# True

The allowable tolerance can be specified with the rtol and atol arguments. Defaults are rtol=1e-05 and atol=1e-08. The determination of closeness is based on the following formula.

absolute(a - b) <= (atol + rtol * absolute(b)) numpy.isclose — NumPy v1.26 Manual

The math module includes math.isclose(), which uses a different formula for comparison.

For example, to consider it True when the absolute difference is within 1, configure the settings as follows.

print(np.isclose(100, 101))
# False

print(np.isclose(100, 101, rtol=0, atol=1))
# True

The equal_nan argument, which defaults to False, can be set to True to treat comparisons between NaN values as True.

print(np.isclose(np.nan, np.nan))
# False

print(np.isclose(np.nan, np.nan, equal_nan=True))
# True

Note that comparisons of other values with NaN are False, even with equal_nan=True.

a_nan = np.array([np.nan, 1, 2])
b_nan = np.array([np.nan, 1, np.nan])

print(np.isclose(a_nan, b_nan))
# [False  True False]

print(np.isclose(a_nan, b_nan, equal_nan=True))
# [ True  True False]

Check if all elements of two arrays are close: np.allclose()

np.allclose() checks if two arrays are element-wise equal within a tolerance.

a = np.array([0.3, 0.1 + 0.1 + 0.1])
b = np.array([0.3, 0.3])
c = np.array([0.1, 0.3])

print(np.allclose(a, b))
# True

print(np.allclose(a, c))
# False

np.allclose() is implemented as np.all(np.isclose(...)) and accepts the same arguments as np.isclose().

The allowable tolerance is specified by the rtol and atol arguments, with the same formula used in np.isclose().

a = np.array([99, 100, 101])

print(np.allclose(a, 100))
# False

print(np.allclose(a, 100, rtol=0, atol=1))
# True

It is also possible to compare to a scalar or a broadcastable array.

The equal_nan argument, which defaults to False, can also be specified. The default is equal_nan=False.

a_nan = np.array([np.nan, 1, 2])
b_nan = np.array([np.nan, 1, 2])

print(np.allclose(a_nan, b_nan))
# False

print(np.allclose(a_nan, b_nan, equal_nan=True))
# True

Related Categories

Related Articles