确定数组中的重复值

时间:2012-07-17 17:52:00

标签: python numpy duplicates unique

假设我有一个数组

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

我如何(有效地,Python地)找到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]]

熊猫

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

有什么我错过的吗?我不一定会寻找一个只有numpy的解决方案,但它必须使用numpy数据类型,并且对中型数据集(高达1000万的大小)有效。


结论

使用1000万大小的数据集(在2.8GHz Xeon上)进行测试:

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

最快的是排序,为1.1秒。可疑的xor1d在2.6秒时排名第二,然后是3.1秒的掩蔽和熊猫Series.duplicated,在{5.6}的bincount,以及in1d和发送者的setdiff1d两者在7.3s。史蒂文的Counter只有一点点慢,只有10.5秒;落后于Burhan的Counter.most_common在110s和DSM的Counter减法在360s。

我将使用排序来提高性能,但我接受了Steven的回答,因为它的性能是可以接受的,并且感觉更清晰,更Pythonic。

编辑:发现了熊猫解决方案。如果Pandas可用,它很清楚并且表现良好。

9 个答案:

答案 0 :(得分:20)

我认为这在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]

注意:这与Burhan Khalid的答案相似,但在条件下使用iteritems而不使用下标应该更快。

答案 1 :(得分:16)

从numpy 1.9.0版开始,np.unique具有参数return_counts,可大大简化您的任务:

u, c = np.unique(a, return_counts=True)
dup = u[c > 1]

这与使用Counter相似,不同之处在于您获得了一对数组而不是映射。我很想知道它们之间的相对表现。

答案 2 :(得分:12)

人们已经建议Counter个变种,但这里有一个不使用listcomp的变种:

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

[发布不是因为它有效 - 它不是 - 但因为我觉得你可以减去Counter个实例很可爱。]

答案 3 :(得分:7)

对于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 :(得分:5)

这是使用set操作的另一种方法,我认为它比你提供的方法更直接:

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

我想你要求numpy - 只有解决方案,因为如果不是这样的话,那么仅仅使用Counter就很难争辩。我认为你应该明确提出这个要求。

答案 5 :(得分:4)

如果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 :(得分:3)

我正在为这个3岁的问题添加我的解决方案,因为除了numpy之外,没有任何解决方案符合我的要求或使用libs。此方法查找重复项的索引和不同重复项集的值。

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]

答案 7 :(得分:3)

如果数组是一个有序的numpy数组,那么只需执行:

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

答案 8 :(得分:0)

>>> import numpy as np

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

>>> uniques, uniq_idx, counts = np.unique(a,return_index=True,return_counts=True)
>>> duplicates = a[ uniq_idx[counts>=2] ]  # <--- Get duplicates

如果您还想得到孤儿:

>>> orphans = a[ uniq_idx[counts==1] ]