After fiddling around for a while, I figured things out, and am posting them here hoping it will help others.
Intuitively, np.where is like asking "tell me where in this array, entries satisfy a given condition".
>>> a = np.arange(5,10)
>>> np.where(a < 8) # tell me where in a, entries are < 8
(array([0, 1, 2]),) # answer: entries indexed by 0, 1, 2
It can also be used to get entries in array that satisfy the condition:
>>> a[np.where(a < 8)]
array([5, 6, 7]) # selects from a entries 0, 1, 2
When a is a 2d array, np.where() returns an array of row idx's, and an array of col idx's:
>>> a = np.arange(4,10).reshape(2,3)
array([[4, 5, 6],
[7, 8, 9]])
>>> np.where(a > 8)
(array(1), array(2))
As in the 1d case, we can use np.where() to get entries in the 2d array that satisfy the condition:
>>> a[np.where(a > 8)] # selects from a entries 0, 1, 2
array([9])
Note, when a is 1d, np.where() still returns an array of row idx's and an array of col idx's, but columns are of length 1, so latter is empty array.
You can use np.in1d:
np.where(np.in1d(letters, ['A', 'C']))[0]
Out[]: array([0, 2, 3, 5, 6, 8], dtype=int64)
If you've got multiple more complex conditions, you can use functools.reduce
from functools import reduce
conditions = [letters == 'A', letters == 'C']
np.where(reduce(np.logical_or, conditions))[0]
Out[]: array([0, 2, 3, 5, 6, 8], dtype=int64)
numpy.any will return True/False, so that won't be suitable to use here.
You can stick to just numpy.where, but with a small tweak in the condition -- you introduce the bitwise OR operator into the condition like this:
np.where((letters == 'A') | (letters == 'C'))
In fact, numpy has this built in as well, as numpy.bitwise_or:
np.where(np.bitwise_or(letters == 'A', letters == 'C'))
Here's a short working example:
import numpy as np
A = 'A'
B = 'B'
C = 'C'
letters = np.array([A, B, C, A, B, C, A, B, C])
# Either this:
letter_indexes = np.where((letters == 'A') | (letters == 'C'))
# Or this:
letter_indexes = np.where(np.bitwise_or(letters == 'A', letters == 'C'))
print(letter_indexes[0])
# [0 2 3 5 6 8]
My understanding of np.where() was so far as sort of an arg container for .loc. However in the example below, .loc works, but not when np.where is used as arg. Why is that happening?
df=pd.DataFrame({'Name':['Tom', 'Mia', 'Sam'], 'Age':[15, 26, 32]}, index=['A','B','C'])
print(df.loc[(df['Age']>28)&(df['Name'].str.startswith('S')])
k=np.where((df['Age']>28)&(df['Name'].str.startswith('S'))
print(df.loc[k])