Мне нужно найти уникальные строки в numpy.array
.
Например:
>>> a # I have
array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
>>> new_a # I want to get to
array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 0]])
Я знаю, что могу создать набор и цикл по массиву, но я ищу эффективный чистый numpy
решение. Я считаю, что есть способ установить тип данных void, и тогда я мог бы просто использовать numpy.unique
, но я не мог понять, как заставить это работать.
Ответы:
Начиная с NumPy 1.13, можно просто выбрать ось для выбора уникальных значений в любом массиве N-dim. Чтобы получить уникальные строки, можно сделать:
unique_rows = np.unique(original_array, axis=0)
источник
np.unique(list_cor, axis=0)
возвращает массив с удаленными дублирующимися строками ; он не фильтрует массив по элементам, которые являются уникальными в исходном массиве . Смотрите здесь , например ..original_array.sort(axis=1)
Еще одно возможное решение
источник
np.vstack(list({tuple(row) for row in AIPbiased[i, :, :]}))
FutureWarning: массивы в стек должны передаваться как тип «последовательности», такой как список или кортеж. Поддержка непоследовательных итераций, таких как генераторы, устарела с NumPy 1.16 и в будущем приведет к ошибке.Другой вариант использования структурированных массивов - это использование
void
типа, который объединяет всю строку в один элемент:РЕДАКТИРОВАТЬ Добавлено
np.ascontiguousarray
после рекомендации @ Seberg. Это замедлит метод, если массив еще не является смежным.РЕДАКТИРОВАТЬ Выше можно немного ускорить, возможно за счет ясности, выполнив:
Кроме того, по крайней мере, в моей системе производительность выше или ниже, чем у метода lexsort:
источник
b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
?np.void
типом данных размером в число байтов в полной строке. Это похоже на два, что вы получите, если у вас есть массивnp.uint8
s и вы видите его какnp.uint16
s, который объединяет каждые два столбца в один, но более гибкий.np.ascontiguousarray
или аналогичный, чтобы быть в целом безопасным (я знаю, что это немного более строгим, чем необходимо, но ...). Строки должны быть смежными, чтобы представление работало должным образом.np.unique
массиваnp.void
возвращается ошибка, связанная с сортировкой слиянием, не реализованной для этого типа. Он работает нормально в 1,7, хотя.-0.
которая не будет сравниваться как равная+0.
, тогда как сравнение по элементам будет иметь-0.==+0.
(как указано в стандарте ieee float). См stackoverflow.com/questions/26782038/...Если вы хотите избежать затрат памяти на преобразование в серию кортежей или другую подобную структуру данных, вы можете использовать структурированные массивы numpy.
Хитрость заключается в том, чтобы просмотреть исходный массив в виде структурированного массива, где каждый элемент соответствует строке исходного массива. Это не делает копию, и довольно эффективно.
В качестве быстрого примера:
Чтобы понять, что происходит, взгляните на промежуточные результаты.
Как только мы рассматриваем вещи как структурированный массив, каждый элемент в массиве является строкой в вашем исходном массиве. (По сути, это структура данных, аналогичная списку кортежей.)
После запуска
numpy.unique
мы вернем структурированный массив:Затем мы должны рассматривать его как «нормальный» массив (в котором
_
хранится результат последнего вычисленияipython
, поэтому вы видите это_.view...
):А затем преобразуйте обратно в 2D-массив (
-1
это заполнитель, который говорит numpy вычислить правильное количество строк, дать количество столбцов):Очевидно, что если вы хотите быть более кратким, вы можете написать это так:
Что приводит к:
источник
lexsort
. Я думал, что вы имели в виду использование списка кортежей. Да,lexsort
возможно, лучший вариант в этом случае. Я забыл об этом и вскочил на слишком сложное решение.np.unique
когда я запускаю его,np.random.random(100).reshape(10,10)
возвращаются все уникальные отдельные элементы, но вы хотите уникальные строки, поэтому сначала вам нужно поместить их в кортежи:Это единственный способ, которым я вижу, как вы меняете типы, чтобы делать то, что вы хотите, и я не уверен, что итерация списка, чтобы изменить на кортежи, в порядке с вашим "не цикл"
источник
< 100
строки на вызов. Это точно описывает, как выполняется выполнение уникальных над строками.uniques
содержит уникальные элементы. Потенциально я неправильно понимаю ожидаемую формуarray
- не могли бы вы быть более точным здесь?uniques
отсортирована (и, следовательно, отличается от строк вarray
).B = np.array([[1,2],[2,1]]); A = np.unique([tuple(row) for row in B]); print(A) = array([[1, 2],[1, 2]])
np.unique работает, сортируя плоский массив, а затем проверяет, равен ли каждый элемент предыдущему. Это можно сделать вручную без выравнивания:
Этот метод не использует кортежи и должен быть намного быстрее и проще, чем другие методы, приведенные здесь.
ПРИМЕЧАНИЕ: предыдущая версия этого не имела ind сразу после [, что означает, что были использованы неправильные индексы. Кроме того, Джо Кингтон отмечает, что это делает различные промежуточные копии. Следующий метод делает меньше, делая отсортированную копию и затем используя ее представления:
Это быстрее и использует меньше памяти.
Кроме того, если вы хотите найти уникальные строки в ndarray независимо от того, сколько измерений в массиве, будет работать следующее:
Интересная оставшаяся проблема будет, если вы захотите отсортировать / уникально вдоль произвольной оси массива произвольной размерности, что будет более трудным.
Редактировать:
Чтобы продемонстрировать разницу в скорости, я провел несколько тестов в ipython из трех разных методов, описанных в ответах. С вашим точным знаком a нет большой разницы, хотя эта версия немного быстрее:
Однако при увеличении a эта версия оказывается намного, намного быстрее:
источник
a[ind[1:]]
копия и т. д.) С другой стороны, ваше решение, как правило, в 2-3 раза быстрее, чем мое, до тех пор, пока у вас не закончится оперативная память.dtype
у тебя на времени? Я думаю, что вы ошиблись. В моей системе вызов,np.unique
как описано в моем ответе, немного быстрее, чем при использовании любого из двух вариантовnp.lexsort
. И это примерно в 5 раз быстрее, если массив для поиска уникальных объектов имеет форму(10000, 100)
. Даже если вы решите переопределить, чтоnp.unique
нужно для сокращения некоторого (незначительного) времени выполнения, свертывание каждой строки в один объект выполняет более быстрое сравнение, чем необходимость вызыватьnp.any
сравнение столбцов, особенно для большего числа столбцов.dtype
это простоa.dtype
, то есть тип данных просматриваемых данных, как это сделал Джо Кингтон в своем ответе. Если столбцов много, другой (несовершенный!) Способ сохранить скорость - использоватьlexsort
сортировку только по нескольким столбцам. Это зависит от данных, так как необходимо знать, какие столбцы обеспечивают достаточную дисперсию для идеальной сортировки. Напримерa.shape = (60000, 500)
- сортировка на первых 3 -х колонок:ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0]))
. Экономия времени довольно существенная, но опять же отказ от ответственности: он может не охватить все случаи - это зависит от данных.Вот еще один вариант @Greg pythonic ответа
источник
Я сравнил предложенную альтернативу для скорости и обнаружил, что, к удивлению, решение void view
unique
даже немного быстрее, чем родной numpyunique
сaxis
аргументом. Если вы ищете скорость, вы захотитеКод для воспроизведения сюжета:
источник
vstack_dict
никогда не использует диктовку, фигурные скобки - это комплексное понимание, и поэтому его поведение почти идентичноvstatck_set
. Посколькуvstack_dict
график производительности отсутствует для графика, похоже, он просто покрываетсяvstack_set
графиком производительности, поскольку они очень похожи!vstack
вариант.Мне не понравился ни один из этих ответов, потому что ни один из них не обрабатывает массивы с плавающей точкой в линейной алгебре или в смысле векторного пространства, где две строки, «равные», означают «в некотором 𝜀». В одном ответе, который имеет пороговое значение допуска, https://stackoverflow.com/a/26867764/500207 , был выбран порог как поэлементной, так и десятичной точности, который работает в некоторых случаях, но не так математически обобщен, как истинное векторное расстояние.
Вот моя версия:
Вышеуказанная функция общественного достояния используется
scipy.spatial.distance.pdist
для нахождения евклидова (настраиваемого) расстояния между каждой парой строк. Затем он сравнивает каждое расстояние соthresh
старым, чтобы найти строки, которые находятся внутриthresh
друг друга, и возвращает только одну строку из каждогоthresh
-кластера.Как указывалось, расстояние
metric
не обязательно должно быть евклидовым -pdist
может вычислять различные расстояния, включаяcityblock
(норма Манхэттена) иcosine
(угол между векторами).Если
thresh=0
(по умолчанию), то строки должны быть точными, чтобы считаться «уникальными». Другие хорошие значения дляthresh
использования масштабируются с машинной точностью, тthresh=np.spacing(1)*1e3
. Е.источник
set
) в качестве представителя каждойthresh
окрестности определенного размера, функция может позволить пользователь может указать, как выбрать эту точку, например, использовать «медиану» или точку, ближайшую к центроиду, и т. д.thresh
кластера, будет случайной из-за неупорядоченной природыset
. Конечно , это brainfart на моей части,set
хранит наборы индексов , которые находятся вthresh
-окрестности, так что этоfindRows
делает на самом деле возвращения, для каждого -thresh
кластера, первая строка в нем.Почему бы не использовать
drop_duplicates
от панд:источник
Пакет numpy_indexed (отказ от ответственности: я его автор) оборачивает решение, опубликованное Jaime, в приятный и проверенный интерфейс, а также многие другие функции:
источник
np.unique работает с учетом списка кортежей:
Со списком списков это поднимает
TypeError: unhashable type: 'list'
источник
Основываясь на ответе на этой странице, я написал функцию, которая копирует возможности функции MATLAB
unique(input,'rows')
, с дополнительной функцией для принятия допуска для проверки уникальности. Он также возвращает такие индексы, чтоc = data[ia,:]
иdata = c[ic,:]
. Пожалуйста, сообщите, если вы видите какие-либо расхождения или ошибки.источник
Помимо превосходного ответа @Jaime, другой способ свернуть строку - использовать
a.strides[0]
(при условии, что онa
является C-смежным), что равноa.dtype.itemsize*a.shape[0]
. Кроме тогоvoid(n)
, это ярлык дляdtype((void,n))
. мы наконец приходим к этой самой короткой версии:Для
источник
Для общих целей, таких как трехмерные или более крупные многомерные вложенные массивы, попробуйте следующее:
который удовлетворяет вашему 2D-набору данных:
дает:
Но также и 3D-массивы, такие как:
дает:
источник
unique
return_index
функции Jaime должно упростить эту последнююreturn
строку. Просто индексируйте оригиналar
на правой оси.Ни один из этих ответов не работал для меня. Я предполагаю, что мои уникальные строки содержали строки, а не числа. Однако этот ответ из другого потока работал:
Источник: https://stackoverflow.com/a/38461043/5402386
Вы можете использовать методы списка .count () и .index ()
источник
На самом деле мы можем превратить числовой массив mxn в числовой массив mx 1, попробуйте использовать следующую функцию, она предоставляет count , inverse_idx и т. Д., Как и numpy.unique:
Пример:
источник
Давайте возьмем всю матрицу в виде списка, затем удалим дубликаты из этого списка и, наконец, вернем наш уникальный список обратно в матрицу:
источник
Самое простое решение - сделать строки одним элементом, сделав их строками. Затем каждый ряд можно сравнить как единое целое по уникальности с помощью numpy. Это решение обобщенно, вам просто нужно изменить форму и транспонировать массив для других комбинаций. Вот решение для предоставленной проблемы.
Дам:
Отправить мой Нобелевский приз по почте
источник
источник