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