test if one numpy array is between arrays a and b

Viewed 95

say I have three numpy arrays:

a = np.array([8,2,10,10])
b = np.array([5,6,7,8])
c = np.array([9,10,11,12])

I would like to do an element-wise test if a is between b and c. And if so, return something like:

["Pass","Fail","Pass","Pass"]
2 Answers

For a pure numpy solution, you can use np.where():

np.where((b < a) & (a < c), 'Pass', 'Fail')

# array(['Pass', 'Fail', 'Pass', 'Pass'], dtype='<U5')

As noted in comments, additional checking is needed if you want either b<a<c or c<a<b:

bac = (b < a) & (a < c)
cab = (c < a) & (a < b)
np.where(bac | cab, 'Pass', 'Fail')

If a, b, and c are not numpy arrays themselves but instead columns of lists:

a = np.array([[8,2,3], 2, 10, 10], dtype=object)
b = np.array([[5,4,5], 6, 7, 8], dtype=object)
c = np.array([[9,6,7], 10, 11, 12], dtype=object)
df = pd.DataFrame({'a': a, 'b': b, 'c': c})

#            a          b          c
# 0  [8, 2, 3]  [5, 4, 5]  [9, 6, 7]
# 1          2          6         10
# 2         10          7         11
# 3         10          8         12

Use applymap() to convert each cell to a numpy array and then apply() the betweenness test along axis=1:

def between(row):
    bac = (row.b < row.a) & (row.a < row.c)
    cab = (row.c < row.a) & (row.a < row.b)
    return np.where(bac | cab, 'Pass', 'Fail')

df = df.applymap(np.array)
df.apply(between, axis=1)

# 0    [Pass, Fail, Fail]
# 1                  Fail
# 2                  Pass
# 3                  Pass
# dtype: object

Via Pandas:

df=pd.DataFrame(data=[a,b,c]).T
df.columns=['a','b','c']

Finally:

result=df['a'].between(df['b'],df['c']).apply(lambda x:'Pass' if x else 'Fail').values

Now If you print result you will get your desired output:

array(['Pass', 'Fail', 'Pass', 'Pass'], dtype=object)

AS Noted in comment by @user2357112 supports Monica:

pandas.Series.between defaults to an inclusive "betweenness" check, so 2 is considered to be between 2 and 3. If you want an exclusive check, you can pass inclusive=False

i.e:

result=df['a'].between(df['b'],df['c'],inclusive=False).apply(lambda x:'Pass' if x else 'Fail').values

Note: It is not much efficient(speedwise) as compared to numpy's where() method for large/huge data but it will do the work

Related