user1234440
user1234440

Reputation: 23617

Python Ranking Dictionary Return Rank

I have a python dictionary:

x = {'a':10.1,'b':2,'c':5}

How do I go about ranking and returning the rank value? Like getting back:

res = {'a':1,c':2,'b':3}

Thanks

Edit:

I am not trying to sort as that can be done via sorted function in python. I was more thinking about getting the rank values from highest to smallest...so replacing the dictionary values by their position after sorting. 1 means highest and 3 means lowest.

Upvotes: 10

Views: 23459

Answers (8)

Mark Z.
Mark Z.

Reputation: 2447

Using pandas:

import pandas as pd

x = {'a':10.1,'b':2,'c':5}
res = dict(zip(x.keys(), pd.Series(x.values()).rank().tolist()))

Upvotes: 1

keithpjolley
keithpjolley

Reputation: 2273

Using scipy.stats.rankdata:

[ins] In [55]: from scipy.stats import rankdata                                                                                                                                                        

[ins] In [56]: x = {'a':10.1, 'b':2, 'c': 5, 'd': 5}                                                                                                                                                   

[ins] In [57]: dict(zip(x.keys(), rankdata([-i for i in x.values()], method='min')))                                                                                                                   
Out[57]: {'a': 1, 'b': 4, 'c': 2, 'd': 2}

[ins] In [58]: dict(zip(x.keys(), rankdata([-i for i in x.values()], method='max')))                                                                                                                   
Out[58]: {'a': 1, 'b': 4, 'c': 3, 'd': 3}

@beta, @DSM scipy.stats.rankdata has some other 'methods' for ties also that may be more appropriate to what you are wanting to do with ties.

Upvotes: 2

Makoto
Makoto

Reputation: 106528

Pretty simple sort-of simple but kind of complex one-liner.

{key[0]:1 + value for value, key in enumerate(
                       sorted(d.iteritems(),
                              key=lambda x: x[1],
                              reverse=True))}

Let me walk you through it.

  • We use enumerate to give us a natural ordering of elements, which is zero-based. Simply using enumerate(d.iteritems()) will generate a list of tuples that contain an integer, then the tuple which contains a key:value pair from the original dictionary.
  • We sort the list so that it appears in order from highest to lowest.
  • We want to treat the value as the enumerated value (that is, we want 0 to be a value for 'a' if there's only one occurrence (and I'll get to normalizing that in a bit), and so forth), and we want the key to be the actual key from the dictionary. So here, we swap the order in which we're binding the two values.
  • When it comes time to extract the actual key, it's still in tuple form - it appears as ('a', 0), so we want to only get the first element from that. key[0] accomplishes that.
  • When we want to get the actual value, we normalize the ranking of it so that it's 1-based instead of zero-based, so we add 1 to value.

Upvotes: 0

DSM
DSM

Reputation: 353604

If I understand correctly, you can simply use sorted to get the ordering, and then enumerate to number them:

>>> x = {'a':10.1, 'b':2, 'c':5}
>>> sorted(x, key=x.get, reverse=True)
['a', 'c', 'b']
>>> {key: rank for rank, key in enumerate(sorted(x, key=x.get, reverse=True), 1)}
{'b': 3, 'c': 2, 'a': 1}

Note that this assumes that the ranks are unambiguous. If you have ties, the rank order among the tied keys will be arbitrary. It's easy to handle that too using similar methods, for example if you wanted all the tied keys to have the same rank. We have

>>> x = {'a':10.1, 'b':2, 'c': 5, 'd': 5}
>>> {key: rank for rank, key in enumerate(sorted(x, key=x.get, reverse=True), 1)}
{'a': 1, 'b': 4, 'd': 3, 'c': 2}

but

>>> r = {key: rank for rank, key in enumerate(sorted(set(x.values()), reverse=True), 1)}
>>> {k: r[v] for k,v in x.items()}
{'a': 1, 'b': 3, 'd': 2, 'c': 2}

Upvotes: 19

Avinash Raj
Avinash Raj

Reputation: 174874

You could do like this,

>>> x = {'a':10.1,'b':2,'c':5}
>>> m = {}
>>> k = 0
>>> for i in dict(sorted(x.items(), key=lambda k: k[1], reverse=True)):
        k += 1
        m[i] = k


>>> m
{'a': 1, 'c': 2, 'b': 3}

Upvotes: 0

Ajay
Ajay

Reputation: 5347

In [23]: from collections import OrderedDict

In [24]: mydict=dict([(j,i) for i, j in enumerate(x.keys(),1)])

In [28]: sorted_dict = sorted(mydict.items(), key=itemgetter(1))

In [29]: sorted_dict
Out[29]: [('a', 1), ('c', 2), ('b', 3)]
In [35]: OrderedDict(sorted_dict)
Out[35]: OrderedDict([('a', 1), ('c', 2), ('b', 3)])

Upvotes: 0

Abd Azrad
Abd Azrad

Reputation: 311

One way would be to examine the dictionary for the largest value, then remove it, while building a new dictionary:

my_dict = x = {'a':10.1,'b':2,'c':5}
i = 1
new_dict ={}
while len(my_dict) > 0:
    my_biggest_key = max(my_dict, key=my_dict.get)
    new_dict[my_biggest_key] = i
    my_dict.pop(my_biggest_key)
    i += 1
print new_dict

Upvotes: 0

Rcynic
Rcynic

Reputation: 392

First sort by value in the dict, then assign ranks. Make sure you sort reversed, and then recreate the dict with the ranks.

from the previous answer :

import operator
x={'a':10.1,'b':2,'c':5}
sorted_x = sorted(x.items(), key=operator.itemgetter(1), reversed=True)
out_dict = {}
for idx, (key, _) in enumerate(sorted_x):
    out_dict[key] = idx + 1
print out_dict

Upvotes: 0

Related Questions