Python 确定数组中的重复值

Python 确定数组中的重复值,python,numpy,duplicates,unique,Python,Numpy,Duplicates,Unique,假设我有一个数组 a = np.array([1, 2, 1, 3, 3, 3, 0]) 我如何(有效地,Pythonically)找到a的哪些元素是重复的(即非唯一值)?在这种情况下,结果将是array([1,3,3])或者如果有效,可能是array([1,3]) 我想出了一些似乎有效的方法: 掩蔽 集合运算 这个很可爱,但可能是非法的(因为a实际上不是唯一的): 直方图 分类 熊猫 有什么我错过的吗?我不一定要寻找一个只使用numpy的解决方案,但它必须与numpy数据类型一起工作,并且在

假设我有一个数组

a = np.array([1, 2, 1, 3, 3, 3, 0])
我如何(有效地,Pythonically)找到
a
的哪些元素是重复的(即非唯一值)?在这种情况下,结果将是
array([1,3,3])
或者如果有效,可能是
array([1,3])

我想出了一些似乎有效的方法:

掩蔽 集合运算 这个很可爱,但可能是非法的(因为
a
实际上不是唯一的):

直方图 分类 熊猫 有什么我错过的吗?我不一定要寻找一个只使用numpy的解决方案,但它必须与numpy数据类型一起工作,并且在中等大小的数据集(最大1000万个)上是高效的


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

最快的是排序,速度为1.1秒。可疑的
xor1d
在2.6秒时排名第二,其次是掩蔽和熊猫
系列。在3.1秒时重复
,在5.6秒时重复
bincount
,在7.3秒时重复
in1d
和senderle的
setdiff1d
。史蒂文的
计数器只慢了一点,10.5秒;紧随其后的是Burhan的
计数器。最常见的是110秒时的
,DSM的
计数器是360秒时的减法

我将使用排序来衡量性能,但我接受Steven的答案,因为性能是可以接受的,而且它感觉更清晰、更具python风格

编辑:发现了熊猫解决方案。如果可以使用Pandas,那么它将非常清晰并且性能良好。

对于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]

我认为这在
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).items() if count > 1]
[1, 3]

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

这里有另一种使用集合运算的方法,我认为这比您提供的方法简单一些:

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

我想你要求的是只使用
numpy
的解决方案,因为如果不是这样,那么仅仅使用
计数器
是非常困难的。但是我认为您应该明确这个要求。

如果
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
不是由小整数组成,我会使用这种方法。

人们已经建议使用
计数器
变体,但这里有一种方法不使用listcomp:

>>> from collections import Counter
>>> a = [1, 2, 1, 3, 3, 3, 0]
>>> (Counter(a) - Counter(set(a))).keys()
[1, 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]

如果数组是已排序的numpy数组,则只需执行以下操作:

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

从numpy版本1.9.0开始,有一个参数
return\u counts
,它大大简化了您的任务:

u, c = np.unique(a, return_counts=True)
dup = u[c > 1]
这与使用类似,只是得到一对数组而不是映射。我很想看看他们之间的相对表现


可能值得一提的是,尽管
np.unique
由于其数量众多而在实践中速度相当快,但它的算法复杂性比
计数器
解决方案差
np.unique
是基于排序的,因此在
O(n logn)
时间内渐近运行<代码>计数器
是基于散列的,因此具有
O(n)
复杂性。这对于最大的数据集来说无关紧要。

我认为这种方法的一个缺点是,
3
重复,而
1
不重复。不管怎样,拥有它都是件好事。(这与其说是对你的答案的批评,不如说是对OP最初的方法的批评。)@StevenRumbalski,是的,我明白你的意思。我的感觉是,如果真正需要的是一个面具而不是一个项目列表,那么重复的
3
是有意义的;如果需要的是一个项目列表,那么我同意没有重复的项目更好。我不反对使用
计数器
,但我担心效率和兼容性。你能解释一下为什么排序解决方案有效吗?我试过了,但由于某种原因我没有真正理解它。@Markus如果对数组排序,任何重复的值都是相邻的。然后使用布尔掩码只获取与上一个项相等的项。它不应该是
s[:-1][s[1::==s[:-1]]
?我得到一个
索引器
,否则,布尔掩码比
s
-数组短一个元素…@snake\u charmer我认为早期版本的numpy在这方面更宽容。我会解决的,谢谢。熊猫似乎已经改善了一些底层方法的性能。在我的机器上,熊猫只比排序方法慢29%。Mad Physician提出的方法比排序慢17%。注意:在python 3中必须使用计数器(a).items(),x[0]>1不是x[1]>1吗?后一个x表示频率。
a[1:][np.diff(a)==0]
,三年后仍然没有,您也可以使用
return\u counts
参数来
unique
。见我的答案。不重新计算集合更有效:
c=计数器(a);结果=(c-计数器(c.keys()).keys()
>>> 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
>>> indices = np.setdiff1d(np.arange(len(a)), np.unique(a, return_index=True)[1])
>>> a[indices]
array([1, 3, 3])
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])
>>> from collections import Counter
>>> a = [1, 2, 1, 3, 3, 3, 0]
>>> (Counter(a) - Counter(set(a))).keys()
[1, 3]
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]
a = np.array([1, 2, 2, 3, 4, 5, 5, 6])
rep_el = a[np.diff(a) == 0]
u, c = np.unique(a, return_counts=True)
dup = u[c > 1]
>>> 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] ]