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

Определение повторяющихся значений в массиве

Предположим, что у меня есть массив

a = np.array([1, 2, 1, 3, 3, 3, 0])

Как я могу (эффективно, на Pythonically) находить, какие элементы a дублируются (т.е. не уникальные значения)? В этом случае результат будет array([1, 3, 3]) или, возможно, array([1, 3]), если он эффективен.

Я придумал несколько методов, которые работают:

Маскировка

m = np.zeros_like(a, dtype=bool)
m[np.unique(a, return_index=True)[1]] = True
a[~m]

Задайте операции

a[~np.in1d(np.arange(len(a)), np.unique(a, return_index=True)[1], assume_unique=True)]

Этот симпатичный, но, вероятно, незаконный (поскольку a на самом деле не уникален):

np.setxor1d(a, np.unique(a), assume_unique=True)

Гистограмма

u, i = np.unique(a, return_inverse=True)
u[np.bincount(i) > 1]

Сортировка

s = np.sort(a, axis=None)
s[:-1][s[1:] == s[:-1]]

Pandas

s = pd.Series(a)
s[s.duplicated()]

Есть ли что-то, что я пропустил? Я не обязательно ищу решение только для numpy, но оно должно работать с типами данных numpy и быть эффективным на средних наборах данных (до 10 миллионов в размере).


Выводы

Тестирование с набором данных размером 10 миллионов (на Xeon 2.8 ГГц):

a = np.random.randint(10**7, size=10**7)

Самая быстрая сортировка - в 1.1s. Сомнительный xor1d занимает второе место в 2.6 с, затем маскируется и Pandas Series.duplicated в 3.1s, bincount на 5.6s и in1d и senderle setdiff1d как на 7.3s. Стивен Counter только немного медленнее, при 10,5 с; отставание отстает от Burhan Counter.most_common при 110s и DSM Counter вычитания при 360s.

Я собираюсь использовать сортировку для производительности, но я принимаю решение Стивена, потому что производительность приемлема, и она кажется более ясной и более Pythonic.

Изменить: обнаружено решение Pandas. Если доступно Pandas, оно очищается и работает хорошо.

4b9b3361

Ответ 1

Я думаю, что это наиболее ясно сделано за пределами numpy. Вам придется время от времени использовать ваши решения numpy, если вы заинтересованы в скорости.

>>> import numpy as np
>>> from collections import Counter
>>> a = np.array([1, 2, 1, 3, 3, 3, 0])
>>> [item for item, count in Counter(a).iteritems() if count > 1]
[1, 3]

note: Это похоже на ответ Бурхана Халида, но использование iteritems без подписи в состоянии должно быть быстрее.

Ответ 2

Люди уже предложили варианты Counter, но здесь тот, который не использует listcomp:

>>> from collections import Counter
>>> a = [1, 2, 1, 3, 3, 3, 0]
>>> (Counter(a) - Counter(set(a))).keys()
[1, 3]

[Отправлено не потому, что это эффективно - это не так, но потому что я думаю, что это мило, что вы можете вычесть экземпляры Counter.]

Ответ 3

Для Python 2.7 +

>>> import numpy
>>> from collections import Counter
>>> n = numpy.array([1,1,2,3,3,3,0])
>>> [x[1] for x in Counter(n).most_common() if x[0] > 1]
[3, 1]

Ответ 4

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

>>> indices = np.setdiff1d(np.arange(len(a)), np.unique(a, return_index=True)[1])
>>> a[indices]
array([1, 3, 3])

Я предполагаю, что вы просите numpy -онные решения, так как если это не так, очень сложно спорить только с помощью Counter. Я думаю, вы должны сделать это требование явным, хотя.

Ответ 5

Если a состоит из небольших целых чисел, вы можете напрямую использовать numpy.bincount:

import numpy as np

a = np.array([3, 2, 2, 0, 4, 3])
counts = np.bincount(a)
print np.where(counts > 1)[0]
# array([2, 3])

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

Ответ 6

Если массив является отсортированным массивом numpy, просто выполните:

a = np.array([1, 2, 2, 3, 4, 5, 5, 6])
rep_el = a[np.diff(a) == 0]

Ответ 7

Я добавляю свое решение в кучу для этого 3-летнего вопроса, потому что ни одно из решений не соответствует тому, что я хотел или не использовал libs, кроме numpy. Этот метод находит как индексы дубликатов, так и значения для разных наборов дубликатов.

import numpy as np

A = np.array([1,2,3,4,4,4,5,6,6,7,8])

# Record the indices where each unique element occurs.
list_of_dup_inds = [np.where(a == A)[0] for a in np.unique(A)]

# Filter out non-duplicates.
list_of_dup_inds = filter(lambda inds: len(inds) > 1, list_of_dup_inds)

for inds in list_of_dup_inds: print inds, A[inds]
# >> [3 4 5] [4 4 4]
# >> [7 8] [6 6]