'How to rank a list of numbers and print out the ranking?
I have a list of numbers that I'm trying to rank, starting from 1 (highest) then print that out. For numbers with ties, I'd just like to number them in order, whichever comes first.
lst = [[0.0] , [0.0] , [0.0] , [0.1] , [0.2]]
#expected output
rank_lst = [3,4,5,2,1]
I just want a simple function similar to what I've done:
rank_lst = [sorted(lst).index(values) for values in lst]
However this one starts at 0, ranks the lowest number as 0 and ranks tied values with the same number like below:
#output
rank_list = [0,0,0,1,2]
Solution 1:[1]
You can use numpy.argsort()
Since you want sorted from high to low, you can first make the values negative.
import numpy as np
lst = [[0.0] , [0.0] , [0.0] , [0.1] , [0.2]]
np_lst = np.array([v[0] for v in lst])
rank_lst = list(np.argsort(np.argsort(-np_lst)) + 1)
Edit: and a second np.argsort() to get what you want.
Solution 2:[2]
You could do it like this
lst = [[0.0], [0.0], [0.0], [0.1], [0.2]]
# wanted: rank_lst == [3, 4, 5, 2, 1]
# add original position
data = list(enumerate(lst, start=1))
# -> [(1, [0.0]), (2, [0.0]), (3, [0.0]), (4, [0.1]), (5, [0.2])]
# sort by value
data = list(sorted(data, key=lambda x: x[1], reverse=True))
# -> [(5, [0.2]), (4, [0.1]), (1, [0.0]), (2, [0.0]), (3, [0.0])]
# add sorted position
data = list(enumerate(data, start=1))
# -> [(1, (5, [0.2])), (2, (4, [0.1])), (3, (1, [0.0])), (4, (2, [0.0])), (5, (3, [0.0]))]
# resort to original order
data = list(sorted(data, key=lambda x: x[1][0]))
# -> [(3, (1, [0.0])), (4, (2, [0.0])), (5, (3, [0.0])), (2, (4, [0.1])), (1, (5, [0.2]))]
# extract sorted order number
rank_lst = [x[0] for x in data]
# -> [3, 4, 5, 2, 1]
Of course you can throw out of all those calls to list. I only used those to create the output.
Solution 3:[3]
You can try using a collections.defaultdict to collect the indices of the list in reverse then just pop the indices off the left one at time with collections.deque.
from collections import defaultdict
from collections import deque
lst = [0, 1, 0, 2, 0]
d = defaultdict(deque)
for i, x in enumerate(sorted(lst, reverse=True), start=1):
d[x].append(i)
result = [d[x].popleft() for x in lst]
print(result)
# [3, 2, 4, 1, 5]
Or with nested lists like in the question:
from collections import defaultdict
from collections import deque
from operator import itemgetter
lst = [[0.0], [0.0], [0.0], [0.1], [0.2]]
single = list(map(itemgetter(0), lst))
d = defaultdict(deque)
for i, x in enumerate(sorted(single, reverse=True), start=1):
d[x].append(i)
result = [d[x].popleft() for x in single]
print(result)
# [3, 4, 5, 2, 1]
Solution 4:[4]
>>> lst = [[0.0] , [0.0] , [0.0] , [0.1] , [0.2]]
>>> lst1 = [i[0] for i in lst] # you only need numbers, not lists for each value
>>> xx = list(enumerate(lst1)) # add an "index" to each value
>>> xx.sort(key=lambda i: -i[1]) # sort on values
>>> xxx = [(i[0], i[1], j+1) for j, i in enumerate(xx)] # add the rank of each value
>>> xxx.sort(key=lambda i : i[0]) # put them back in the original order using the index
>>> res = [i[2] for i in xxx] # get just the ranks
>>> res
[3, 4, 5, 2, 1]
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | |
| Solution 4 | cammil |
