Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Take N first values from every row in NumPy matrix that fulfill condition

I have a numpy vector, and a numpy array.

I need to take from every row in the matrix the first N (lets say 3) values that are smaller than (or equal to) the corresponding line in the vector.

so if this is my vector:

7,
9,
22,
38,
6,
15

and this is my matrix:

[[ 20.,   9.,   7.,   5.,   None,   None],
 [ 33.,  21.,  18.,   9.,   8.,   7.],
 [ 31.,  21.,  13.,  12.,   4.,   0.],
 [ 36.,  18.,  11.,   7.,   7.,   2.],
 [ 20.,  14.,  10.,   6.,   6.,   3.],
 [ 14.,  14.,  13.,  11.,   5.,   5.]]

the output should be:

[[7,5,None],
 [9,8,7],
 [21,13,12],
 [36,18,11],
 [6,6,3],
 14,14,13]]

Is there any efficient way to do that with masks or something, without an ugly for loop?

Any help will be appreciated!

like image 636
Binyamin Even Avatar asked Oct 16 '22 23:10

Binyamin Even


1 Answers

Approach #1

Here's one with broadcasting -

def takeN_le_per_row_broadcasting(a, b, N=3): # a, b : 1D, 2D arrays respectively
    # First col indices in each row of b with <= corresponding one in a
    idx = (b <= a[:,None]).argmax(1)

    # Get all N ranged column indices
    all_idx = idx[:,None] + np.arange(N)

    # Finally advanced-index with those indices into b for desired output
    return b[np.arange(len(all_idx))[:,None], all_idx]

Approach #2

Inspired by NumPy Fancy Indexing - Crop different ROIs from different channels's solution, we can leverage np.lib.stride_tricks.as_strided for efficient patch extraction, like so -

from skimage.util.shape import view_as_windows

def takeN_le_per_row_strides(a, b, N=3): # a, b : 1D, 2D arrays respectively
    # First col indices in each row of b with <= corresponding one in a
    idx = (b <= a[:,None]).argmax(1)

    # Get 1D sliding windows for each element off data
    w = view_as_windows(b, (1,N))[:,:,0]

    # Use fancy/advanced indexing to select the required ones
    return w[np.arange(len(idx)), idx]
like image 125
Divakar Avatar answered Oct 21 '22 03:10

Divakar