Поиск уникальных столбцов и столбцов

Я прошел через эти потоки:

и все они обсуждают несколько методов вычисления матрицы с уникальными строками и столбцами.

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

np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, 
a.shape[1])

В любом случае вышеупомянутое решение возвращает матрицу уникальных строк. То, что я ищу, - это что-то вроде первоначальной функциональности np.unique

u, indices = np.unique(a, return_inverse=True)

который возвращает не только список уникальных записей, но также членство каждого элемента в каждой найденной уникальной записи, но как это сделать для столбцов?

Вот пример того, что я ищу:

array([[0, 2, 0, 2, 2, 0, 2, 1, 1, 2],
       [0, 1, 0, 1, 1, 1, 2, 2, 2, 2]])

Мы имели бы:

u       = array([0,1,2,3,4])
indices = array([0,1,0,1,1,3,4,4,3])

Если разные значения в u представляют собой набор уникальных столбцов в исходном массиве:

0 -> [0,0]
1 -> [2,1]
2 -> [0,1]
3 -> [2,2]
4 -> [1,2]

Ответ 1

По существу, вы хотите, чтобы np.unique возвращал индексы уникальных столбцов и индексы того, где они используются? Это достаточно легко сделать, перенеся матрицу, а затем используя код из другого вопроса, с добавлением return_inverse=True.

at = a.T
b = np.ascontiguousarray(at).view(np.dtype((np.void, at.dtype.itemsize * at.shape[1])))
_, u, indices = np.unique(b, return_index=True, return_inverse=True)

С помощью a это дает:

In [35]: u
Out[35]: array([0, 5, 7, 1, 6])

In [36]: indices
Out[36]: array([0, 3, 0, 3, 3, 1, 4, 2, 2, 4])

Мне не совсем ясно, что вы хотите u быть. Если вы хотите, чтобы это были уникальные столбцы, вы могли бы использовать следующее:

at = a.T
b = np.ascontiguousarray(at).view(np.dtype((np.void, at.dtype.itemsize * at.shape[1])))
_, idx, indices = np.unique(b, return_index=True, return_inverse=True)
u = a[:,idx]

Это даст

In [41]: u
Out[41]:
array([[0, 0, 1, 2, 2],
       [0, 1, 2, 1, 2]])

In [42]: indices
Out[42]: array([0, 3, 0, 3, 3, 1, 4, 2, 2, 4])

Ответ 2

Сначала давайте получим уникальные индексы, для этого нам нужно начать с переноса массива:

>>> a=a.T

Используя модифицированную версию выше, чтобы получить уникальные индексы.

>>> ua, uind = np.unique(np.ascontiguousarray(a).view(np.dtype((np.void,a.dtype.itemsize * a.shape[1]))),return_inverse=True)

>>> uind
array([0, 3, 0, 3, 3, 1, 4, 2, 2, 4])

#Thanks to @Jamie
>>> ua = ua.view(a.dtype).reshape(ua.shape + (-1,))
>>> ua
array([[0, 0],
       [0, 1],
       [1, 2],
       [2, 1],
       [2, 2]])

Для здравого смысла:

>>> np.all(a==ua[uind])
True

Воспроизведение диаграммы:

>>> for x in range(ua.shape[0]):
...     print x,'->',ua[x]
...
0 -> [0 0]
1 -> [0 1]
2 -> [1 2]
3 -> [2 1]
4 -> [2 2]

Выполнять именно то, что вы просите, но будет немного медленнее, если ему нужно преобразовать массив:

>>> b=np.asfortranarray(a).view(np.dtype((np.void,a.dtype.itemsize * a.shape[0])))
>>> ua,uind=np.unique(b,return_inverse=True)
>>> uind
array([0, 3, 0, 3, 3, 1, 4, 2, 2, 4])
>>> ua.view(a.dtype).reshape(ua.shape+(-1,),order='F')
array([[0, 0, 1, 2, 2],
       [0, 1, 2, 1, 2]])

#To return this in the previous order.
>>> ua.view(a.dtype).reshape(ua.shape + (-1,))

Ответ 3

Не совсем уверен, что вы после, но посмотрите на numpy_indexed пакет (отказ от ответственности: я его автор); он уверен, что проблемы такого рода будут проще:

import numpy_indexed as npi
unique_columns = npi.unique(A, axis=1)
# or perhaps this is what you want?
unique_columns, indices = npi.group_by(A.T, np.arange(A.shape[1])))