1

I have a numpy array . I want rescale the elements in the array, so that the smallest number in array is represented by 1, and largest number in array is represented by the number of unique elements in array.

For example

A=[ [2,8,8],[3,4,5] ]  

would become

[ [1,5,5],[2,3,4] ]
show_stopper
  • 288
  • 5
  • 17
  • Almost duplicate of [python - Numpy Array Rank All Elements - Stack Overflow](https://stackoverflow.com/questions/36193225/numpy-array-rank-all-elements) (although that one want the maximum to have rank 1) – user202729 Jan 11 '21 at 11:00

2 Answers2

3

Use np.unique with its return_inverse param -

np.unique(A, return_inverse=1)[1].reshape(A.shape)+1

Sample run -

In [10]: A
Out[10]: 
array([[2, 8, 8],
       [3, 4, 5]])

In [11]: np.unique(A, return_inverse=1)[1].reshape(A.shape)+1
Out[11]: 
array([[1, 5, 5],
       [2, 3, 4]])
Divakar
  • 218,885
  • 19
  • 262
  • 358
  • Everything is clear to me! But, why does adding 1 at the end works? Isn't it more like an ad-hoc solution? could this be generalized? – kmario23 Jun 07 '18 at 19:56
  • 1
    @kmario23 Why add 1? Because OP wants the new *mapping* to start from 1 I think. That `1` could be called `start_val` and that could be the generic version? – Divakar Jun 07 '18 at 19:58
  • 1
    yes the 1 only offsets the start, if you use 10, the numbering starts from 10 to (number of unique+10). – show_stopper Jun 07 '18 at 20:04
1

If you're not opposed to using scipy, you could use rankdata, with method='dense' (judging by the tags on your question):

from scipy.stats import rankdata

rankdata(A, 'dense').reshape(A.shape)

array([[1, 5, 5],
       [2, 3, 4]])

Note that in your case, method='min' would achieve the same results, see linked documentation for more details

sacuL
  • 49,704
  • 8
  • 81
  • 106