Подтвердить что ты не робот

Построение набора python из матрицы numpy

Я пытаюсь выполнить следующие

>> from numpy import *
>> x = array([[3,2,3],[4,4,4]])
>> y = set(x)
TypeError: unhashable type: 'numpy.ndarray'

Как я могу легко и эффективно создавать набор из массива numpy?

4b9b3361

Ответ 1

Если вам нужен набор элементов, вот еще один, возможно, более быстрый способ:

y = set(x.flatten())

PS: после выполнения сравнений между x.flat, x.flatten() и x.ravel() в массиве 10x100 я обнаружил, что все они работают примерно с той же скоростью. Для массива 3x3 самая быстрая версия - это версия итератора:

y = set(x.flat)

который я бы рекомендовал, потому что это менее дорогостоящая версия с памятью (она хорошо масштабируется с размером массива).

PS: есть также функция NumPy, которая делает что-то подобное:

y = numpy.unique(x)

Это создает массив NumPy с тем же элементом, что и set(x.flat), но как массив NumPy. Это очень быстро (почти в 10 раз быстрее), но если вам нужен set, то выполнение set(numpy.unique(x)) немного медленнее, чем другие процедуры (создание набора происходит с большими накладными расходами).

Ответ 2

Непременным эквивалентом массива является кортеж, поэтому попробуйте преобразовать массив массивов в массив кортежей:

>> from numpy import *
>> x = array([[3,2,3],[4,4,4]])

>> x_hashable = map(tuple, x)

>> y = set(x_hashable)
set([(3, 2, 3), (4, 4, 4)])

Ответ 3

Вышеупомянутые ответы работают, если вы хотите создать набор из элементов, содержащихся в ndarray, но если вы хотите создать набор объектов ndarray или использовать объекты ndarray как ключи в словаре - тогда вам придется предоставить хэшируемую оболочку для них. См. Приведенный ниже код для простого примера:

from hashlib import sha1

from numpy import all, array, uint8


class hashable(object):
    r'''Hashable wrapper for ndarray objects.

        Instances of ndarray are not hashable, meaning they cannot be added to
        sets, nor used as keys in dictionaries. This is by design - ndarray
        objects are mutable, and therefore cannot reliably implement the
        __hash__() method.

        The hashable class allows a way around this limitation. It implements
        the required methods for hashable objects in terms of an encapsulated
        ndarray object. This can be either a copied instance (which is safer)
        or the original object (which requires the user to be careful enough
        not to modify it).
    '''
    def __init__(self, wrapped, tight=False):
        r'''Creates a new hashable object encapsulating an ndarray.

            wrapped
                The wrapped ndarray.

            tight
                Optional. If True, a copy of the input ndaray is created.
                Defaults to False.
        '''
        self.__tight = tight
        self.__wrapped = array(wrapped) if tight else wrapped
        self.__hash = int(sha1(wrapped.view(uint8)).hexdigest(), 16)

    def __eq__(self, other):
        return all(self.__wrapped == other.__wrapped)

    def __hash__(self):
        return self.__hash

    def unwrap(self):
        r'''Returns the encapsulated ndarray.

            If the wrapper is "tight", a copy of the encapsulated ndarray is
            returned. Otherwise, the encapsulated ndarray itself is returned.
        '''
        if self.__tight:
            return array(self.__wrapped)

        return self.__wrapped

Использование класса обертки достаточно просто:

>>> from numpy import arange

>>> a = arange(0, 1024)
>>> d = {}
>>> d[a] = 'foo'
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: unhashable type: 'numpy.ndarray'
>>> b = hashable(a)
>>> d[b] = 'bar'
>>> d[b]
'bar'

Ответ 4

Если вам нужен набор элементов:

>> y = set(e for r in x
             for e in r)
set([2, 3, 4])

Для набора строк:

>> y = set(tuple(r) for r in x)
set([(3, 2, 3), (4, 4, 4)])