Christian K.
Christian K.

Reputation: 2823

Get index of minimum value in a row combined with other constraints

I need to find the index of the minimum per row in a 2-dim array which at the same time satifies additional constraint on the column values. Having two arrays a and b

a = np.array([[1,0,1],[0,0,1],[0,0,0],[1,1,1]])

b = np.array([[1,-1,2],[4,-1,1],[1,-1,2],[1,2,-1]])

the objective is to find the indicies for which holds that a == 1, b is positive and b is the minimumim value of the row. Fulfilling the first two conditions is easy

idx = np.where(np.logical_and(a == 1, b > 0))

which yields the indices:

(array([0, 0, 1, 3, 3]), array([0, 2, 2, 0, 1]))

Now I need to filter the duplicate row entries (stick with minimum value only) but I cannot think of an elegant way to achieve that. In the above example the result should be

(array([0,1,3]), array([0,2,0]))

edit:

It should also work for a containing other values than just 0 and 1.

Upvotes: 3

Views: 273

Answers (2)

Scott Boston
Scott Boston

Reputation: 153460

Updated to trying to understand the problem better, try:

c = b*(b*a > 0)
np.where(c==np.min(c[np.nonzero(c)]))

Output:

(array([0, 1, 3], dtype=int64), array([0, 2, 0], dtype=int64))

Timings:

Method 1

a = np.array([[1,0,1],[0,0,1],[0,0,0],[1,1,1]])
b = np.array([[1,-1,2],[4,-1,1],[1,-1,2],[1,2,-1]])
b[b<0] = 100000
cond = [[True if i == b.argmin(axis=1)[k] else False for i in range(b.shape[1])] for k in range(b.shape[0])]
idx = np.where(np.logical_and(np.logical_and(a == 1, b > 0),cond))
idx

Method 2

c = b*(b*a > 0)
idx1 = np.where(c==np.min(c[np.nonzero(c)]))
idx1

Method 1 Timing:

28.3 µs ± 418 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Method 2 Timing:

12.2 µs ± 144 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Upvotes: 2

Christian K.
Christian K.

Reputation: 2823

I found a solution based on list comprehension. It is necessary to change the negative values of b to some high value though.

a = np.array([[1,0,1],[0,0,1],[0,0,0],[1,1,1]])
b = np.array([[1,-1,2],[4,-1,1],[1,-1,2],[1,2,-1]])
b[b<0] = 100000
cond = [[True if i == b.argmin(axis=1)[k] else False for i in range(b.shape[1])] for k in range(b.shape[0])]
idx = np.where(np.logical_and(np.logical_and(a == 1, b > 0),cond))
print(idx)

(array([0, 1, 3]), array([0, 2, 0]))

Please let me hear what you think.

edit: I just noticed that this solution is horribly slow.

Upvotes: 0

Related Questions