1

I'm attempting to sort a dictionaries keys according to its values. So I have used numpy's argsort to sort the values in ascending order. But when I attempt to sort the keys according to the values indices I get the error:

IndexError: too many indices for array

What am I doing wrong here?

import numpy as np

## Map occurences of colours in image
colour_map = {}
#...
colour_map['#fff'] = 15
colour_map['#ccc'] = 99
#...

## Sort colour map from most frequent to least 
colours         = np.array(colour_map.keys())   # dict_keys(['#fff', '#ccc'])
col_frequencies = np.array(colour_map.values()) # dict_values([15, 99])

indicies = col_frequencies.argsort()

# Error on below line "IndexError: too many indices for array"
colours = colours[indicies[::-1]]
sazr
  • 24,984
  • 66
  • 194
  • 362
  • 2
    When you call `.keys()` and `values()` numpy doesn't convert them to char or integer arrays but instead object arrays. `colours = np.array(list(colour_map.keys()))` followed by `col_frequencies = np.array(list(colour_map.values()))` should solve this. – ayhan Oct 11 '17 at 12:01
  • @ayhan Thanks that fixed it. If you make an answer I can accept it. – sazr Oct 11 '17 at 12:09
  • Your code works fine as-is on `Python 2.7.12` with `Numpy 1.13.0`. – carthurs Oct 11 '17 at 12:09
  • @carthurs doesn't work in Python 3.6 – sazr Oct 11 '17 at 12:16
  • @JakeM I still couldn't figure out why `colours[0]` raises an error. It's an array with a single item after all. Maybe someone can come up with an explanation. – ayhan Oct 11 '17 at 13:33
  • @JakeM It seems the return type of dict.keys() changed between Python 2 and 3 https://stackoverflow.com/questions/16819222/how-to-return-dictionary-keys-as-a-list-in-python – carthurs Oct 11 '17 at 15:40
  • @ayhan I investigated this, and it turns out it's not an array with a single item - see my answer below! – carthurs Oct 12 '17 at 15:08

1 Answers1

1

In Python 3, dir(np.array(colour_map.keys())) shows that this class not satisfy the array_like requirement which is specified as being necessary in the documentation for numpy.array https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.array.html

The definition of array_like was explored in more detail here numpy: formal definition of "array_like" objects?

It seems that np.array doesn't check whether array_like is satisfied, and will happily construct a Numpy array from an object which does not satisfy it.

Then when you try to index it, the indexing doesn't work.

Here's an example with my_object designed not to be array_like.

class my_object():
    def greet(self):
        print("hi!")

a = my_object()
a.greet()
print(dir(a))  # no __array__ attribute

b = np.array(a)

b[0]

results in

hi!
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'greet']
Traceback (most recent call last):
  File "C:/path/to/my/script.py", 
line 35, in <module>
    b[0]
IndexError: too many indices for array

Now let's try making it array-like (or at least sufficiently array-like for this to work):

class my_object():
    def greet(self):
        print("hi!")

    def __array__(self):
        return np.array([self])

a = my_object()

b = np.array(a)

b[0].greet()  # Now we can index b successfully

results in:

hi!
carthurs
  • 553
  • 1
  • 5
  • 18