Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an efficient way to get the position of the max element except for a specific column in a NumPy matrix?

For example, There is a 2d Numpy matrix M:

[[1,10,3],
 [4,15,6]]

The max element except for those in M[:][1] is 6, and its position is (1,2). So the answer is (1,2).

Thank you very much for any help!

like image 252
sunshk1227 Avatar asked Oct 27 '25 10:10

sunshk1227


2 Answers

One way:

col = 1
skip_col = np.delete(x, col, axis=1)
row, column = np.unravel_index(skip_col.argmax(), skip_col.shape)
if column >= col:
    column += 1 

Translated:

  1. Remove the column
  2. find the maximum argument (argmax gives a flattened result, unravel_index gives back the placement in the 2d array)
  3. If the column is greater or equal to the skipped one, add one

Following Dunes comment, I like the suggestion. It's nearly identical in amount of lines, but does not require a copy (as in np.delete). So if you are memory bound (as in really big data):

col = 1
row, column = np.unravel_index(x[:, :col].argmax(), x[:, :col].shape)  # left max, saving a line assuming it's the global max, but less readable
right_max = np.unravel_index(x[:, col+1:].argmax(), x[:, col+1:].shape)
if x[right_max] > x[row, column]:
    row, column = right_max
    column += col
like image 174
kabanus Avatar answered Oct 30 '25 01:10

kabanus


Here's a solution taking advantage of the set of nan functions:

In [180]: arr = np.array([[1,10,3],[4,15,6]])                                   
In [181]: arr1 = arr.astype(float)                                              
In [182]: arr1[:,1]=np.nan                                                      
In [183]: arr1                                                                  
Out[183]: 
array([[ 1., nan,  3.],
       [ 4., nan,  6.]])
In [184]: np.nanargmax(arr1)                                                    
Out[184]: 5
In [185]: np.unravel_index(np.nanargmax(arr1),arr.shape)                        
Out[185]: (1, 2)

It might not be optimal timewise, but is probably easier to debug that alternatives.

Looking at the np.nanargmax I see that it just replaces the np.nan with -np.inf. So we do something similar by just replacing the exclude column values with a small enough integer so they won't be the max.

In [188]: arr1=arr.copy()                                                       
In [189]: arr1[:,1] = np.min(arr1)-1                                            
In [190]: arr1                                                                  
Out[190]: 
array([[1, 0, 3],
       [4, 0, 6]])
In [191]: np.argmax(arr1)                                                       
Out[191]: 5
In [192]: np.unravel_index(np.argmax(arr1),arr.shape)                           
Out[192]: (1, 2)

I can also imagine a solution using np.ma.masked_array, but that tends to be more of a convenience than speed tool.

like image 37
hpaulj Avatar answered Oct 29 '25 23:10

hpaulj



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!