简体   繁体   中英

Conditional indexing with Numpy ndarray

I have a Numpy ndarray matrix of float values and I need to select spesific rows where certain columns have values satisfying certain criteria. For example lets say I have the following numpy matrix:

matrix = np.ndarray([4, 5])
matrix[0,:] = range(1,6)
matrix[1,:] = range(6,11)
matrix[2,:] = range(11,16)
matrix[3,:] = range(16,21)

Lets say I want to select rows from the matrix where the first column's value is between 1 and 6 and the value of second column is between 2-7.

How can I get the row-indexes of the matrix where these conditions are satisfied? What about if I want to delete the rows that satisfy the conditional criterion?

For a numpy based solution, you can use numpy.where and then get the row indexes from it and then use it for indexing you matrix. Example -

matrix[np.where((1 <= matrix[:,0]) & (matrix[:,0] <= 6)
       & (2 <= matrix[:,1]) & (matrix[:,1] <= 7))]

Demo -

In [169]: matrix
Out[169]:
array([[  1.,   2.,   3.,   4.,   5.],
       [  6.,   7.,   8.,   9.,  10.],
       [ 11.,  12.,  13.,  14.,  15.],
       [ 16.,  17.,  18.,  19.,  20.]])

In [170]: matrix[np.where((1 <= matrix[:,0]) & (matrix[:,0] <= 6)
   .....:        & (2 <= matrix[:,1]) & (matrix[:,1] <= 7))]
Out[170]:
array([[  1.,   2.,   3.,   4.,   5.],
       [  6.,   7.,   8.,   9.,  10.]])

Another method , as indicated in the comments would be to use boolean masks, Example -

mask = ((1 <= matrix[:,0]) & (matrix[:,0] <= 6)
           & (2 <= matrix[:,1]) & (matrix[:,1] <= 7))

matrix[mask,:]

Demo -

In [41]: matrix
Out[41]:
array([[  1.,   2.,   3.,   4.,   5.],
       [  6.,   7.,   8.,   9.,  10.],
       [ 11.,  12.,  13.,  14.,  15.],
       [ 16.,  17.,  18.,  19.,  20.]])

In [42]: mask = ((1 <= matrix[:,0]) & (matrix[:,0] <= 6)
   ....:            & (2 <= matrix[:,1]) & (matrix[:,1] <= 7))

In [43]:

In [43]: matrix[mask,:]
Out[43]:
array([[  1.,   2.,   3.,   4.,   5.],
       [  6.,   7.,   8.,   9.,  10.]])

You can get the indices with :

rows = np.logical_and(0 < matrix[:, 0], < matrix[:, 0] < 6 ) *  np.logical_and(1 < matrix[:, 1], matrix[:, 1] < 7)

Then newMatrix = np.delete(matrix, rows, axis = 0)

You mentioned MATLAB. Here's the equivalent to the accepted answer using Octave

octave:17> ma=reshape(1:20,5,4)
ma =
    1    6   11   16
    2    7   12   17
    3    8   13   18
    4    9   14   19
    5   10   15   20

octave:18> mask=(1<=ma(1,:))&(ma(1,:)<=6)&(2<=ma(2,:))&(ma(2,:)<=7)
mask =
   1   1   0   0

octave:19> ma(:,mask)
ans =
    1    6
    2    7
    3    8
    4    9
    5   10

The accepted answer without where is:

In [592]: mask=(1 <= matrix[:,0]) & (matrix[:,0] <= 6) &(2 <= matrix[:,1]) & (matrix[:,1] <= 7)

In [593]: matrix[mask,:]
Out[593]: 
array([[  1.,   2.,   3.,   4.,   5.],
       [  6.,   7.,   8.,   9.,  10.]])

I switched rows and columns in the Octave version because that is its natural way of generating the same numbers (MATLAB/Octave use the equivalent of numpy s 'F' order - see below).

The other changes are 0 v 1 start index, and () v []. Otherwise the two notations are similar.

A simpler way to generate the matrix in numpy:

In [594]: np.arange(1,21).reshape(4,5)
Out[594]: 
array([[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10],
       [11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20]])

Or with the MATLAB layout:

In [595]: np.arange(1,21).reshape(5,4,order='F')
Out[595]: 
array([[ 1,  6, 11, 16],
       [ 2,  7, 12, 17],
       [ 3,  8, 13, 18],
       [ 4,  9, 14, 19],
       [ 5, 10, 15, 20]])

Get row indices:

row_indices = [x for x in range(4) if matrix[x][0] in range(1,7) and matrix[x][1] in range(2,8)]

Delete rows:

indices = [x for x in range(4) if not( matrix[x][0] in range(1,7) and matrix[x][1] in range(2,8))]

new_matrix = matrix[indices]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM