Getting indices of an array in Python
Question:
I have a numpy array A
with True, False
elements. I want to print all indices which have False
element. But, I am getting an error. I present the expected output:
import numpy as np
A=np.array([[False],
[False],
[ True],
[False],
[False]])
for i in range(0,len(A)):
if (A[i]==['False']):
print(i)
The error is :
FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
if (A[i]==['False']):
The expected output is :
[0,1,3,4]
Answers:
Rather than iterating over the array, you can build an index array using np.arange
, and then slice the indices using the boolean array.
np.arange(len(A))[~A.ravel()]
# returns:
array([0, 1, 3, 4])
If you want it with the same dimensionality as A
, you can use np.argwhere
np.argwhere(~A.ravel())
# returns:
array([[0],
[1],
[3],
[4]], dtype=int64)
you are comparing list with boolean value i.e True/False with list with string value i.e ‘False’, hence you are getting the error.
Change the if condition as follows (i.e. without quotation marks for False):
if (A[i] == [False])
You can also use np.where:
A=np.array([[False],
[False],
[ True],
[False],
[False]])
print(np.where(np.squeeze(A)==False))
Note: np.squeeze
just removes the last dimension of your array.
The output is array([0, 1, 3, 4]
as expected.
.nonzero()
will give you those indices.
>>> A
array([[False],
[False],
[ True],
[False],
[False]])
>>> ~A
array([[ True],
[ True],
[False],
[ True],
[ True]])
>>>
>>> (~A).nonzero()[0]
array([0, 1, 3, 4])
>>>
>>>
>>> np.flatnonzero(~A)
array([0, 1, 3, 4])
You could get those indices in one shot using argwhere:
indices = np.argwhere(A==False)[:,0] # extract only row indexes from output
print(indices)
# [0 1 3 4]
Using np.where with unpacking could also work:
indices,_ = np.where(A==False)
print(indices)
# [0 1 3 4]
You can use list comprehension as well.
enumerate
is considered more pythonic than range(len(A))
[i for i,j in enumerate(A) if A[i]==[False]]
#[0, 1, 3, 4]
What’s wrong in you code?
In every iteration of your loop your arrays are of type bool
, and you are trying to compare with a list(str)
. For Numpy to make the comparison it must cast types. But Numpy will only perform the comparison if it can safely cast dtypes (see this answer). Although Python 3 can cast bool('anything')
to True
, Numpy don’t find it safe. Why? I don’t know, but see how this can be funny:
>>> bool('False') == True
True
And how to make element-wise comparison using two different dtype arrays? choose one type to cast
Note that you’ll get the same warning if you: np.array(['False']) == False
.
For element-wise comparison you can use np.equal(array1, array2, dtype=your_type)
:
>>> compare = np.array(len(A)*(('False',),))
>>> compare
array([['False'],
['False'],
['False'],
['False'],
['False']], dtype='<U5')
>>> np.equal(A, compare, dtype=bool)
UFuncTypeError: Cannot cast ufunc 'equal' input 1 from dtype('<U5') to dtype('bool') with casting rule 'same_kind'
With that it throws an error you can handle if it’d be the case.
Therefore the comparison can’t be performed since the types can’t be cast. Which can be checked using np.can_cast
:
>>> np.can_cast('<U5', bool)
False
How to fix your code?
There are already so many great answers, and you can simply choose any and you’ll probably be ok. But here is my contribution in case you want to maintain a similar syntax:
for idx, element in enumerate(A):
if not element:
print(idx)
Here, enumerate
concatenates every element of A
with an counting index, and the not element
will return True every time element
is False
.
But in case of best performance always prefer using Numpy’s functions:
>>> compare = np.array(len(A)*((False,),))
>>> np.where(np.equal(A, compare))[0]
array([0, 1, 3, 4])
I have a numpy array A
with True, False
elements. I want to print all indices which have False
element. But, I am getting an error. I present the expected output:
import numpy as np
A=np.array([[False],
[False],
[ True],
[False],
[False]])
for i in range(0,len(A)):
if (A[i]==['False']):
print(i)
The error is :
FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison
if (A[i]==['False']):
The expected output is :
[0,1,3,4]
Rather than iterating over the array, you can build an index array using np.arange
, and then slice the indices using the boolean array.
np.arange(len(A))[~A.ravel()]
# returns:
array([0, 1, 3, 4])
If you want it with the same dimensionality as A
, you can use np.argwhere
np.argwhere(~A.ravel())
# returns:
array([[0],
[1],
[3],
[4]], dtype=int64)
you are comparing list with boolean value i.e True/False with list with string value i.e ‘False’, hence you are getting the error.
Change the if condition as follows (i.e. without quotation marks for False):
if (A[i] == [False])
You can also use np.where:
A=np.array([[False],
[False],
[ True],
[False],
[False]])
print(np.where(np.squeeze(A)==False))
Note: np.squeeze
just removes the last dimension of your array.
The output is array([0, 1, 3, 4]
as expected.
.nonzero()
will give you those indices.
>>> A
array([[False],
[False],
[ True],
[False],
[False]])
>>> ~A
array([[ True],
[ True],
[False],
[ True],
[ True]])
>>>
>>> (~A).nonzero()[0]
array([0, 1, 3, 4])
>>>
>>>
>>> np.flatnonzero(~A)
array([0, 1, 3, 4])
You could get those indices in one shot using argwhere:
indices = np.argwhere(A==False)[:,0] # extract only row indexes from output
print(indices)
# [0 1 3 4]
Using np.where with unpacking could also work:
indices,_ = np.where(A==False)
print(indices)
# [0 1 3 4]
You can use list comprehension as well.
enumerate
is considered more pythonic than range(len(A))
[i for i,j in enumerate(A) if A[i]==[False]]
#[0, 1, 3, 4]
What’s wrong in you code?
In every iteration of your loop your arrays are of type bool
, and you are trying to compare with a list(str)
. For Numpy to make the comparison it must cast types. But Numpy will only perform the comparison if it can safely cast dtypes (see this answer). Although Python 3 can cast bool('anything')
to True
, Numpy don’t find it safe. Why? I don’t know, but see how this can be funny:
>>> bool('False') == True
True
And how to make element-wise comparison using two different dtype arrays? choose one type to cast
Note that you’ll get the same warning if you: np.array(['False']) == False
.
For element-wise comparison you can use np.equal(array1, array2, dtype=your_type)
:
>>> compare = np.array(len(A)*(('False',),))
>>> compare
array([['False'],
['False'],
['False'],
['False'],
['False']], dtype='<U5')
>>> np.equal(A, compare, dtype=bool)
UFuncTypeError: Cannot cast ufunc 'equal' input 1 from dtype('<U5') to dtype('bool') with casting rule 'same_kind'
With that it throws an error you can handle if it’d be the case.
Therefore the comparison can’t be performed since the types can’t be cast. Which can be checked using np.can_cast
:
>>> np.can_cast('<U5', bool)
False
How to fix your code?
There are already so many great answers, and you can simply choose any and you’ll probably be ok. But here is my contribution in case you want to maintain a similar syntax:
for idx, element in enumerate(A):
if not element:
print(idx)
Here, enumerate
concatenates every element of A
with an counting index, and the not element
will return True every time element
is False
.
But in case of best performance always prefer using Numpy’s functions:
>>> compare = np.array(len(A)*((False,),))
>>> np.where(np.equal(A, compare))[0]
array([0, 1, 3, 4])