5

I have a numpy array in Python which is n-by-n (in the example is 3-by-3)and contains zero values in all the diagonal positions. e.g

array([[ 0.   , -0.65  ,  1.3 ,   0.56],
       [ 0.45 ,  0.    ,  0.54,   43   ],
       [ 0.5  ,  0.12  ,  0.  ,   7    ]
       [ 0.2  ,  0.3  ,  0.4  ,   0    ]])

Is it possible to sort the array without modifying the diagonal positions so as to look like the one below? Because all of the sorting functions will take into account the "zeros" that exist in the diagonal positions and will change their relative position.

array([[ 0.   , 1.3    ,  0.56  ,   -0.65],
       [ 43   ,  0.    ,  0.54  ,   0.45   ],
       [ 7    ,  0.5   ,  0.    ,   0.12    ]
       [ 0.4  ,  0.3  ,  0.2    ,   0    ]])

If the above operation cannot be done, then the N maximum values and their corresponding indexes in each row could suffice.

Till now i have tried sort and argsort but with no result.

2
  • I think there's a typo in the last row. You're missing a 0. Commented Mar 2, 2015 at 14:17
  • The array is now 3x4... Commented Mar 2, 2015 at 14:20

2 Answers 2

2

I'm a little late to this question, but if you're looking for a NumPy-only solution, you could substitute inf for your diagonal, sort in your chosen order, and then shuffle the inf column back to the diagonal:

In [189]: a = np.array([[ 0.   , -0.65  ,  1.3 ,   0.56],
   .....:        [ 0.45 ,  0.    ,  0.54,   43   ],
   .....:        [ 0.5  ,  0.12  ,  0.  ,   7    ],
   .....:        [ 0.2  ,  0.3  ,  0.4  ,   0    ]])

In [190]: np.fill_diagonal(a,np.inf)

In [191]: a.sort()

In [192]: a = a[:,::-1]

In [193]: for i in range(1,len(a)):
   .....:         a[i,:i+1] = np.roll(a[i,:i+1], i)
   .....:     

In [194]: np.fill_diagonal(a, 0)

In [195]: a
Out[195]: 
array([[  0.  ,   1.3 ,   0.56,  -0.65],
   [ 43.  ,   0.  ,   0.54,   0.45],
   [  7.  ,   0.5 ,   0.  ,   0.12],
   [  0.4 ,   0.3 ,   0.2 ,   0.  ]])
Sign up to request clarification or add additional context in comments.

2 Comments

This doesn't work, just swapping values destroys the sort. A implementation with np.triu_indices would probably work.
Thanks, @Ophion -- you're absolutely right. I think I've fixed it now, using np.roll on appropriate slices.
1

The easiest approach is to remove the zeroes, sort, then add the zeroes back along the diagonal:

>>> a = [[0,1,2],[3,0,0],[5,6,0]]
>>> no_zeroes = [r[:i] + r[i+1:] for i, r in enumerate(a)]
>>> no_zeroes
[[1, 2], [3, 0], [5, 6]]
>>> sorted_no_zeroes = [sorted(r, reverse=True) for r in no_zeroes]
>>> sorted_no_zeroes
[[2, 1], [3, 0], [6, 5]]
>>> sorted_with_zeroes = [r[:i] + [0] + r[i:] for i, r in enumerate(sorted_no_zeroes)]
>>> sorted_with_zeroes
[[0, 2, 1], [3, 0, 0], [6, 5, 0]]

Wrapped into a function:

>>> def sort_ignoring_zeroes(a):
...  s = [sorted(r[:i] + r[i+1:], reverse=True) for i, r in enumerate(a)]
...  return [r[:i] + [0] + r[i:] for i, r in enumerate(s)]
...
>>> sort_ignoring_zeroes(
          [[ 0.   , 1.3    ,  0.56  ,   -0.65],
...        [ 43   ,  0.    ,  0.54  ,   0.45],
...        [ 7    ,  0.5   ,  0.    ,   0.12]])
[[0, 1.3, 0.56, -0.65],
 [43, 0, 0.54, 0.45],
 [7, 0.5, 0, 0.12]]
>>>

1 Comment

I was thinking maybe of a simpler operation and just return the indexes of the n largest values of each row. I am trying this: idx = (-arr).argsort()[:n] but the problem is that it works only if n equals the size of the N-by-N array

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.