Достичь уникальных бинарных списков с помощью numpy [duplicate]

, когда объект производного класса присваивается объекту базового класса, дополнительные атрибуты объекта производного класса вырезаются (отбрасываются) из объекта базового класса.

class Base { 
int x;
 };

class Derived : public Base { 
 int z; 
 };

 int main() 
{
Derived d;
Base b = d; // Object Slicing,  z of d is sliced off
}
151
задан Saullo G. P. Castro 12 August 2013 в 23:14
поделиться

20 ответов

Начиная с NumPy 1.13, можно просто выбрать ось для выбора уникальных значений в любом N-мерном массиве. Чтобы получить уникальные строки, можно сделать:

unique_rows = np.unique(original_array, axis=0)

52
ответ дан aiwabdn 21 August 2018 в 15:35
поделиться
  • 1
    is NumPy 1.13 out?. Я только что обновил python до 3.6.2, и моя версия numpy по-прежнему показывает 1.12 – sunny 24 October 2017 в 02:06
  • 2
    Осторожно с этой функцией. np.unique(list_cor, axis=0) получает массив с удаленными удаленными строками ; он не фильтрует массив на элементы, которые являются уникальными в исходном массиве . См. здесь , например .. – Brad Solomon 29 November 2017 в 23:08

Основываясь на ответе на этой странице, я написал функцию, которая реплицирует функцию функции unique(input,'rows') MATLAB, а дополнительная функция принимает допуски для проверки уникальности. Он также возвращает индексы такие, что c = data[ia,:] и data = c[ic,:]. Сообщите, если вы видите какие-либо расхождения или ошибки.

def unique_rows(data, prec=5):
    import numpy as np
    d_r = np.fix(data * 10 ** prec) / 10 ** prec + 0.0
    b = np.ascontiguousarray(d_r).view(np.dtype((np.void, d_r.dtype.itemsize * d_r.shape[1])))
    _, ia = np.unique(b, return_index=True)
    _, ic = np.unique(b, return_inverse=True)
    return np.unique(b).view(d_r.dtype).reshape(-1, d_r.shape[1]), ia, ic
1
ответ дан Arash_D_B 21 August 2018 в 15:35
поделиться

Помимо отличного ответа @Jaime, другой способ свернуть строку - использовать a.strides[0] (предполагая, что a C-смежный), который равен a.dtype.itemsize*a.shape[0]. Кроме того, void(n) является ярлыком для dtype((void,n)). мы приходим к этой кратчайшей версии:

a[unique(a.view(void(a.strides[0])),1)[1]]

Для

[[0 1 1 1 0 0]
 [1 1 1 0 0 0]
 [1 1 1 1 1 0]]
1
ответ дан B. M. 21 August 2018 в 15:35
поделиться

np.unique работает с списком кортежей:

>>> np.unique([(1, 1), (2, 2), (3, 3), (4, 4), (2, 2)])
Out[9]: 
array([[1, 1],
       [2, 2],
       [3, 3],
       [4, 4]])

Со списком списков он вызывает TypeError: unhashable type: 'list'

1
ответ дан codeape 21 August 2018 в 15:35
поделиться
  • 1
    похоже, не работает на моем. Каждый набор состоит из двух строк вместо двух чисел с плавающей запятой – mjp 13 February 2017 в 23:49
  • 2
    не работает, он возвращает список элементов, а не кортежей – Mohanad Kaleia 10 July 2017 в 15:39

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

Источник: https://stackoverflow.com/a/38461043/5402386

Вы можете использовать .count () и .index () list

coor = np.array([[10, 10], [12, 9], [10, 5], [12, 9]])
coor_tuple = [tuple(x) for x in coor]
unique_coor = sorted(set(coor_tuple), key=lambda x: coor_tuple.index(x))
unique_count = [coor_tuple.count(x) for x in unique_coor]
unique_index = [coor_tuple.index(x) for x in unique_coor]
6
ответ дан Community 21 August 2018 в 15:35
поделиться
  • 1
    Лучший ответ. Благодарю. Это самый (математически) обобщенный ответ, написанный до сих пор. Он рассматривает матрицу как набор точек данных или выборок в N-мерном пространстве и находит коллекцию одинаковых или похожих точек (сходство определяется либо евклидовым расстоянием, либо любыми другими способами). Эти точки могут быть перекрывающимися точками данных или очень близкими окрестностями. В конце набор одинаковых или похожих точек заменяется любой точкой (в вышеприведенном ответе первой точкой), принадлежащей к тому же множеству. Это помогает уменьшить избыточность из облака точек. – Sanchit 2 August 2016 в 10:01
  • 2
    @Sanchit aha, это хороший момент, вместо того, чтобы выбрать «первую» точку (на самом деле это может быть эффективно случайным, так как это зависит от того, как Python хранит точки в set) как представителя каждого thresh -раздела , функция может позволить пользователю указать, как выбрать эту точку, например, использовать «медианную» или точку, ближайшую к центроиду, и т. д. – Ahmed Fasih 2 August 2016 в 14:35
  • 3
    Конечно. Без сомнений. Я только что упомянул первый пункт, так как это то, что делает ваша программа, что совершенно нормально. – Sanchit 2 August 2016 в 15:17
  • 4
    Просто исправление - я неправильно сказал выше, что строка, которая будет выбрана для каждого thresh -кластера, была бы случайной из-за неупорядоченного характера set. Конечно, это мой мозг, set хранит кортежи индексов, которые находятся в thresh -окрестности, поэтому этот findRows действительно фактически возвращает, для каждого thresh - кластер, первая строка в нем. – Ahmed Fasih 2 August 2016 в 16:50

Самое простое решение - сделать строки одним элементом, сделав их строками. Каждая строка затем может быть сравнена в целом по своей уникальности с использованием numpy. Это решение является обобщающим, вам просто нужно изменить форму и перенести свой массив для других комбинаций. Вот решение для предоставленной проблемы.

import numpy as np

original = np.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]])

uniques, index = np.unique([str(i) for i in original], return_index=True)
cleaned = original[index]
print(cleaned)    

Дает:

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

Отправить мою нобелевскую премию по почте

-1
ответ дан Dave Pena 21 August 2018 в 15:35
поделиться
  • 1
    Очень неэффективно и подвержено ошибкам, например. с различными параметрами печати. Другие варианты явно предпочтительнее. – Michael 28 November 2016 в 19:18

Вот еще одна вариация для ответа @Greg pythonic

np.vstack(set(map(tuple, a)))
8
ответ дан divenex 21 August 2018 в 15:35
поделиться

Пакет numpy_indexed (отказ от ответственности: я его автор) завершает решение, опубликованное Jaime в приятном и проверенном интерфейсе, а также множество других функций:

import numpy_indexed as npi
new_a = npi.unique(a)  # unique elements over axis=0 (rows) by default
3
ответ дан Eelco Hoogendoorn 21 August 2018 в 15:35
поделиться

Еще одно возможное решение

np.vstack({tuple(row) for row in a})
126
ответ дан Greg von Winckel 21 August 2018 в 15:35
поделиться
  • 1
    +1 Это ясно, коротко и питонично. Если скорость не является реальной проблемой, эти типы решений должны отдавать предпочтение сложным, более высоким голосовым ответам на этот вопрос ИМО. – Bill Cheatham 30 April 2014 в 14:36
  • 2
    – Tian He 4 May 2016 в 15:51
  • 3
    @Greg von Winckel Можете ли вы предложить что-то, что не является чем-то, что не меняет порядок. – Laschet Jain 12 February 2017 в 23:30
  • 4
    Да, но не в одной команде: x = []; [x.append (tuple (r)) для r в a, если набор (r) не в x]; a_unique = array (x); – Greg von Winckel 12 May 2017 в 15:18

Другим вариантом использования структурированных массивов является использование вида void, который объединяет всю строку в один элемент:

a = np.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]])

b = np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
_, idx = np.unique(b, return_index=True)

unique_a = a[idx]

>>> unique_a
array([[0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

EDIT Добавлен np.ascontiguousarray в соответствии с рекомендацией @ seberg , Это замедлит метод вниз, если массив еще не смежен.

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

unique_a = np.unique(b).view(a.dtype).reshape(-1, a.shape[1])

Кроме того, по крайней мере, в моей системе, производительность по сравнению с методом lexsort по сравнению с методом lexsort:

a = np.random.randint(2, size=(10000, 6))

%timeit np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, a.shape[1])
100 loops, best of 3: 3.17 ms per loop

%timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]
100 loops, best of 3: 5.93 ms per loop

a = np.random.randint(2, size=(10000, 100))

%timeit np.unique(a.view(np.dtype((np.void, a.dtype.itemsize*a.shape[1])))).view(a.dtype).reshape(-1, a.shape[1])
10 loops, best of 3: 29.9 ms per loop

%timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]
10 loops, best of 3: 116 ms per loop
108
ответ дан Jaime 21 August 2018 в 15:35
поделиться
  • 1
    Большое спасибо. Это ответ, который я искал, вы можете объяснить, что происходит на этом шаге: b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))? – Akavall 7 June 2013 в 01:28
  • 2
    @Akavall Создает представление ваших данных с типом данных np.void размером в число байтов в полной строке. Это похоже на то, что вы получаете, если у вас есть массив из np.uint8 s и просматривать его как np.uint16 s, который объединяет все два столбца в один, но более гибкий. – Jaime 7 June 2013 в 03:34
  • 3
    @Jaime, можете ли вы добавить np.ascontiguousarray или подобное, чтобы быть в целом безопасным (я знаю, что это немного более ограничительный, чем необходимо, но ...). Строки должны быть смежными, чтобы представление работало так, как ожидалось. – seberg 7 June 2013 в 11:04
  • 4
    @ConstantineEvans Это недавнее дополнение: в numpy 1.6 попытка запустить np.unique в массиве np.void возвращает ошибку, связанную с тем, что mergesort не выполняется для этого типа. Однако он отлично работает в 1.7. – Jaime 7 June 2013 в 21:01
  • 5
    Стоит отметить, что если этот метод используется для чисел с плавающей запятой, существует catch, который -0. не будет сравниваться как +0., тогда как сравнение по элементам будет иметь -0.==+0. (как указано в float ieee стандарт). См. stackoverflow.com/questions/26782038/… – tom10 7 November 2014 в 00:52

Если вы хотите избежать затрат памяти на преобразование в ряд кортежей или другую подобную структуру данных, вы можете использовать структурные массивы numpy.

Фокус в том, чтобы просмотреть исходный массив как структурированный массив где каждый элемент соответствует строке исходного массива. Это не делает копию и довольно эффективно.

В качестве быстрого примера:

import numpy as np

data = np.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]])

ncols = data.shape[1]
dtype = data.dtype.descr * ncols
struct = data.view(dtype)

uniq = np.unique(struct)
uniq = uniq.view(data.dtype).reshape(-1, ncols)
print uniq

Чтобы понять, что происходит, взгляните на посредника Результаты.

. Когда мы рассматриваем вещи как структурированный массив, каждый элемент в массиве представляет собой строку в исходном массиве. (В принципе, это аналогичная структура данных для списка кортежей.)

In [71]: struct
Out[71]:
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)]],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

In [72]: struct[0]
Out[72]:
array([(1, 1, 1, 0, 0, 0)],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

Как только мы запустим numpy.unique, мы получим структурированный массив назад:

In [73]: np.unique(struct)
Out[73]:
array([(0, 1, 1, 1, 0, 0), (1, 1, 1, 0, 0, 0), (1, 1, 1, 1, 1, 0)],
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])

Затем нам нужно посмотреть как «нормальный» массив (_ хранит результат последнего вычисления в ipython, поэтому вы видите _.view...):

In [74]: _.view(data.dtype)
Out[74]: array([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0])

Затем переформатируйте обратно в 2D-массив (-1 является заполнителем, который говорит numpy, чтобы вычислить правильное количество строк, указать количество столбцов):

In [75]: _.reshape(-1, ncols)
Out[75]:
array([[0, 1, 1, 1, 0, 0],
       [1, 1, 1, 0, 0, 0],
       [1, 1, 1, 1, 1, 0]])

Очевидно, если вы хотели бы быть более кратким, вы могли бы написать его как:

import numpy as np

def unique_rows(data):
    uniq = np.unique(data.view(data.dtype.descr * data.shape[1]))
    return uniq.view(data.dtype).reshape(-1, data.shape[1])

data = np.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]])
print unique_rows(data)

В результате:

[[0 1 1 1 0 0]
 [1 1 1 0 0 0]
 [1 1 1 1 1 0]]
29
ответ дан Joe Kington 21 August 2018 в 15:35
поделиться
  • 1
    Это на самом деле кажется очень медленным, почти таким же медленным, как использование кортежей. По-видимому, сортировка такого структурированного массива медленная. – cge 6 June 2013 в 21:28
  • 2
    @cge - Попробуйте его с помощью массивов большего размера. Да, сортировка массива numpy выполняется медленнее сортировки списка. Однако скорость не является главным фактором в большинстве случаев, когда вы используете ndarrays. Это использование памяти. Список кортежей будет использовать значительно больше памяти, чем это решение. Даже если у вас достаточно памяти, с достаточно большим массивом, преобразование его в список кортежей имеет большие накладные расходы, чем преимущество скорости. – Joe Kington 6 June 2013 в 21:34
  • 3
    @cge - Ах, я не заметил, что вы использовали lexsort. Я думал, вы ссылаетесь на использование списка кортежей. Да, lexsort, вероятно, лучший вариант в этом случае. Я забыл об этом и перешел на слишком сложное решение. – Joe Kington 6 June 2013 в 21:37

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

ind = np.lexsort(a.T)
a[ind[np.concatenate(([True],np.any(a[ind[1:]]!=a[ind[:-1]],axis=1)))]]

Этот метод не использует кортежи и должен быть намного быстрее и проще, чем другие методы, приведенные здесь.

ПРИМЕЧАНИЕ. Предыдущая версия из этого не было ind ind сразу после [, что означает, что использовались неправильные индексы. Кроме того, Джо Кингтон хорошо говорит о том, что этот делает множество различных промежуточных копий. Следующий метод делает меньше, создавая отсортированную копию и затем используя ее виды:

b = a[np.lexsort(a.T)]
b[np.concatenate(([True], np.any(b[1:] != b[:-1],axis=1)))]

Это быстрее и использует меньше памяти.

Кроме того, если вы хотите найти уникальные строки в ndarray , независимо от того, сколько измерений в массиве, будут работать следующие:

b = a[lexsort(a.reshape((a.shape[0],-1)).T)];
b[np.concatenate(([True], np.any(b[1:]!=b[:-1],axis=tuple(range(1,a.ndim)))))]

Интересной оставшейся проблемой будет, если вы хотите сортировать / уникально

Edit:

Чтобы продемонстрировать разницу в скорости, я провел несколько тестов в ipython из трех различные методы, описанные в ответах. С ваш точный a, разница не слишком велика, хотя эта версия немного быстрее:

In [87]: %timeit unique(a.view(dtype)).view('<i8')
10000 loops, best of 3: 48.4 us per loop

In [88]: %timeit ind = np.lexsort(a.T); a[np.concatenate(([True], np.any(a[ind[1:]]!= a[ind[:-1]], axis=1)))]
10000 loops, best of 3: 37.6 us per loop

In [89]: %timeit b = [tuple(row) for row in a]; np.unique(b)
10000 loops, best of 3: 41.6 us per loop

При большей версии, однако, эта версия заканчивается намного быстрее:

In [96]: a = np.random.randint(0,2,size=(10000,6))

In [97]: %timeit unique(a.view(dtype)).view('<i8')
10 loops, best of 3: 24.4 ms per loop

In [98]: %timeit b = [tuple(row) for row in a]; np.unique(b)
10 loops, best of 3: 28.2 ms per loop

In [99]: %timeit ind = np.lexsort(a.T); a[np.concatenate(([True],np.any(a[ind[1:]]!= a[ind[:-1]],axis=1)))]
100 loops, best of 3: 3.25 ms per loop
16
ответ дан jojo 21 August 2018 в 15:35
поделиться
  • 1
    – Joe Kington 6 June 2013 в 21:55
  • 2
    Хорошая точка зрения. Как оказалось, моя попытка вытащить промежуточные копии, используя только индексы, заставила мой метод использовать больше памяти и в итоге медленнее, чем просто сделать отсортированную копию массива, так как a_sorted [1:] не является копией a_sorted , – cge 6 June 2013 в 22:16
  • 3
    Что dtype в ваших таймингах? Думаю, ты ошибался. В моей системе вызов np.unique, как описано в моем ответе, немного быстрее, чем использование одного из ваших двух вариантов np.lexsort. И это примерно в 5 раз быстрее, если массив, чтобы найти uniques имеет форму (10000, 100). Даже если вы решите переопределить то, что np.unique делает для обрезки некоторого (младшего) времени выполнения, свертывание каждой строки в один объект выполняется быстрее, чем при вызове np.any при сравнении столбцов, особенно для более высоких значений столбцов. – Jaime 7 June 2013 в 10:55
  • 4
    @cge: вы, вероятно, имели в виду «np.any» вместо стандартного «any», который не принимает аргумент ключевого слова. – Alfred M. 12 September 2013 в 11:59
  • 5
    @Jaime - я считаю, что dtype - это просто a.dtype, то есть тип данных просматриваемых данных, как это сделал Джо Кингтон в его ответе. Если есть много столбцов, другой (несовершенный!) Способ ускорить работу с помощью lexsort - это отсортировать только по нескольким столбцам. Это зависит от данных, поскольку нужно знать, какие столбцы обеспечивают достаточную дисперсию для сортировки. Например. a.shape = (60000, 500) - сортировка по первым трем столбцам: ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0])). Экономия времени довольно существенна, но отказ от ответственности снова: он может не поймать все случаи - это зависит от данных. – n1k31t4 21 March 2018 в 14:31

Почему бы не использовать drop_duplicates из панд:

>>> timeit pd.DataFrame(image.reshape(-1,3)).drop_duplicates().values
1 loops, best of 3: 3.08 s per loop

>>> timeit np.vstack({tuple(r) for r in image.reshape(-1,3)})
1 loops, best of 3: 51 s per loop
3
ответ дан kalu 21 August 2018 в 15:35
поделиться
  • 1
    Я действительно люблю этот ответ. Конечно, он не использует numpy напрямую, но для меня это легче всего понять, будучи быстрым. – noctilux 12 May 2017 в 02:58

Позволяет получить всю матрицу numpy в виде списка, затем удалить дубликаты из этого списка и, наконец, вернуть наш уникальный список обратно в матрицу numpy:

matrix_as_list=data.tolist() 
matrix_as_list:
[[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]]

uniq_list=list()
uniq_list.append(matrix_as_list[0])

[uniq_list.append(item) for item in matrix_as_list if item not in uniq_list]

unique_matrix=np.array(uniq_list)
unique_matrix:
array([[1, 1, 1, 0, 0, 0],
       [0, 1, 1, 1, 0, 0],
       [1, 1, 1, 1, 1, 0]])
0
ответ дан Mahdi Ghelichi 21 August 2018 в 15:35
поделиться

Я сравнил предложенную альтернативу скорости и обнаружил, что, на удивление, решение void view unique даже немного быстрее, чем native unique numpy с аргументом axis. Если вы ищете скорость, вам понадобится

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


Код для воспроизведения графика:

import numpy
import perfplot


def unique_void_view(a):
    return numpy.unique(
        a.view(numpy.dtype((numpy.void, a.dtype.itemsize*a.shape[1])))
        ).view(a.dtype).reshape(-1, a.shape[1])


def lexsort(a):
    ind = numpy.lexsort(a.T)
    return a[ind[
        numpy.concatenate((
            [True], numpy.any(a[ind[1:]] != a[ind[:-1]], axis=1)
            ))
        ]]


def vstack(a):
    return numpy.vstack({tuple(row) for row in a})


def unique_axis(a):
    return numpy.unique(a, axis=0)


perfplot.show(
    setup=lambda n: numpy.random.randint(2, size=(n, 20)),
    kernels=[unique_void_view, lexsort, vstack, unique_axis],
    n_range=[2**k for k in range(15)],
    logx=True,
    logy=True,
    xlabel='len(a)',
    equality_check=None
    )
4
ответ дан Nico Schlömer 21 August 2018 в 15:35
поделиться
  • 1
    Очень приятный ответ, одна второстепенная точка: vstack_dict, никогда не использует dict, фигурные скобки - это понимание множества, и поэтому его поведение почти идентично vstatck_set. Так как vstack_dict отсутствует строка производительности для графика fro, похоже, что это просто покрывается графиком производительности vstack_set, так как они настолько похожи! – Akavall 9 July 2017 в 16:56
  • 2
    Спасибо за ответ. Я улучшил график, включив только один вариант vstack. – Nico Schlömer 10 July 2017 в 07:46

np.unique, когда я запускаю его на np.random.random(100).reshape(10,10), возвращает все уникальные отдельные элементы, но вам нужны уникальные строки, поэтому сначала вам нужно поместить их в кортежи:

array = #your numpy array of lists
new_array = [tuple(row) for row in array]
uniques = np.unique(new_array)

Это единственный способ увидеть, как вы меняете типы, чтобы делать то, что вы хотите, и я не уверен, что итерация списка, чтобы изменить на кортежи, в порядке с вашим «не зацикливанием»

18
ответ дан Ryan Saxe 21 August 2018 в 15:35
поделиться
  • 1
    +1 Это ясно, коротко и питонично. Если скорость не является реальной проблемой, эти типы решений должны отдавать предпочтение сложным, более высоким голосовым ответам на этот вопрос ИМО. – Bill Cheatham 30 April 2014 в 14:36
  • 2
    Я предпочитаю это по принятому решению. Скорость не является проблемой для меня, потому что у меня есть только < 100 строк для каждого вызова. Это точно описывает, как выполняется выполнение уникальных над строками. – rayryeng 1 April 2015 в 17:04
  • 3
    Это действительно не работает для моих данных, uniques содержит уникальные элементы. Потенциально я неправильно понимаю ожидаемую форму array - не могли бы вы уточнить здесь? – FooBar 20 April 2015 в 13:34
  • 4
    @ ryan-saxe Мне нравится, что это pythonic, но это не очень хорошее решение, потому что строка, возвращаемая в 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]]) – jmlarson 23 March 2016 в 13:20

Для общего назначения, такого как 3D или более высокие многомерные вложенные массивы, попробуйте следующее:

import numpy as np

def unique_nested_arrays(ar):
    origin_shape = ar.shape
    origin_dtype = ar.dtype
    ar = ar.reshape(origin_shape[0], np.prod(origin_shape[1:]))
    ar = np.ascontiguousarray(ar)
    unique_ar = np.unique(ar.view([('', origin_dtype)]*np.prod(origin_shape[1:])))
    return unique_ar.view(origin_dtype).reshape((unique_ar.shape[0], ) + origin_shape[1:])

, который удовлетворяет вашему двумерному набору данных:

a = np.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]])
unique_nested_arrays(a)

дает:

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

Но также и 3D-массивы вроде:

b = np.array([[[1, 1, 1], [0, 1, 1]],
              [[0, 1, 1], [1, 1, 1]],
              [[1, 1, 1], [0, 1, 1]],
              [[1, 1, 1], [1, 1, 1]]])
unique_nested_arrays(b)

дают:

array([[[0, 1, 1], [1, 1, 1]],
   [[1, 1, 1], [0, 1, 1]],
   [[1, 1, 1], [1, 1, 1]]])
0
ответ дан Tara 21 August 2018 в 15:35
поделиться
  • 1
    Используя unique return_index, как это сделал Хайме, сделать эту последнюю return строку проще. Просто проиндексируйте оригинал ar на правой оси. – hpaulj 22 August 2016 в 22:24

На самом деле мы можем превратить массив numx numx mxn в массив строк mx 1 numpy, попробуйте использовать следующую функцию, он предоставляет count, inverse_idx и т. д., как numpy.unique:

import numpy as np

def uniqueRow(a):
    #This function turn m x n numpy array into m x 1 numpy array storing 
    #string, and so the np.unique can be used

    #Input: an m x n numpy array (a)
    #Output unique m' x n numpy array (unique), inverse_indx, and counts 

    s = np.chararray((a.shape[0],1))
    s[:] = '-'

    b = (a).astype(np.str)

    s2 = np.expand_dims(b[:,0],axis=1) + s + np.expand_dims(b[:,1],axis=1)

    n = a.shape[1] - 2    

    for i in range(0,n):
         s2 = s2 + s + np.expand_dims(b[:,i+2],axis=1)

    s3, idx, inv_, c = np.unique(s2,return_index = True,  return_inverse = True, return_counts = True)

    return a[idx], inv_, c

Пример :

A = np.array([[ 3.17   9.502  3.291],
  [ 9.984  2.773  6.852],
  [ 1.172  8.885  4.258],
  [ 9.73   7.518  3.227],
  [ 8.113  9.563  9.117],
  [ 9.984  2.773  6.852],
  [ 9.73   7.518  3.227]])

B, inv_, c = uniqueRow(A)

Results:

B:
[[ 1.172  8.885  4.258]
[ 3.17   9.502  3.291]
[ 8.113  9.563  9.117]
[ 9.73   7.518  3.227]
[ 9.984  2.773  6.852]]

inv_:
[3 4 1 0 2 4 0]

c:
[2 1 1 1 2]
0
ответ дан Ting On Chan 21 August 2018 в 15:35
поделиться
import numpy as np
original = np.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]])
# create a view that the subarray as tuple and return unique indeies.
_, unique_index = np.unique(original.view(original.dtype.descr * original.shape[1]),
                            return_index=True)
# get unique set
print(original[unique_index])
-2
ответ дан YoungLearnsToCoding 21 August 2018 в 15:35
поделиться
7
ответ дан Community 1 November 2018 в 09:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: