Ошибка типа: не хэшируемый тип: ‘numpy.ndarray’ при преобразовании кортежа в set

#python #numpy

#python #numpy

Вопрос:

 data_xy = tuple([x, y])
  

x и y — это массивы numpy с размерами:
x.shape = (56567, 128, 16) и
y.shape = (56567, 1)

Ошибка типа возникает в следующей строке:

     for data_class in sorted(set(data_xy[1])):
  

Ошибка типа: не хэшируемый тип: ‘numpy.ndarray’

Комментарии:

1. наборы не могут содержать изменяемые типы. См . learnpython.dev/02-введение в python/…

2. @balderman. Наборы могут содержать изменяемые типы просто отлично. Они не могут содержать нехешируемые типы.

Ответ №1:

Вы не можете хэшировать массив numpy, потому что он изменяемый. Наборы — это хэш-таблицы, которые требуют, чтобы все их элементы были хэшируемыми.

Поскольку вы не можете применить set к строкам массива, я предлагаю np.unique вместо этого использовать:

 s = np.unique(data_xy[1], axis=0)
s.sort()

for data_class in s:
  

В общем, выполнение for цикла над массивами numpy — это то, что вы должны стремиться обойти, поскольку это часто не нужно и замедляет работу.

Альтернативным решением было бы создать хешируемый тип оболочки для строк, чтобы вы могли использовать их в set . Это будет довольно медленно и не рекомендуется, но служит для иллюстрации концепции:

 class RowView:
    def __init__(self, row):
        self.hash = hash(tuple(row))
        self.data = row
    def __hash__(self):
        return self.hash
    def __lt__(self, other):
        return np.argmax(np.less(self.data, other.data)) < np.argmax(np.less(other.data, self.data))

for data_class in (x.data for x in sorted(set(RowView(r) for r in data_xy[1]))):
  

Немного более быстрое решение, которое лучше демонстрирует пользовательское хеширование, — это расширение np.ndarray с помощью пользовательского хэша. Затем вы можете использовать объекты просмотра напрямую, не копируя данные вперед и назад:

 class HashableArray(np.ndarray):
    def __hash__(self):
        return hash(tuple(self))
    def __lt__(self, other):
        return np.argmax(np.less(self, other)) < np.argmax(np.less(other, self))

for data_class in sorted(set(x.view(HashableArray) for x in data_xy[1]))):