【发布时间】:2012-07-16 16:53:26
【问题描述】:
假设我有一个数组
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.1s。可疑的 xor1d 以 2.6s 排名第二,其次是 masking 和 Pandas Series.duplicated 在 3.1s,bincount 在 5.6s,in1d 和 senderle 的 setdiff1d 均在 7.3s。 Steven 的Counter 只是慢了一点,10.5s;紧随其后的是 Burhan 在 110 秒时的 Counter.most_common 和 DSM 在 360 秒时的 Counter 减法。
我将使用排序来提高性能,但我接受 Steven 的回答,因为性能是可以接受的,而且它感觉更清晰、更 Pythonic。
编辑:发现 Pandas 解决方案。如果 Pandas 可用,它就很清晰并且性能良好。
【问题讨论】:
-
您能解释一下为什么排序解决方案有效吗?我试过了,但由于某种原因,我真的不明白。
-
@Markus 如果对数组进行排序,则任何重复值都是相邻的。然后,您使用布尔掩码仅获取与前一项相同的项。
-
不应该是
s[:-1][ s[1:] == s[:-1] ]吗?我得到一个IndexError否则,布尔掩码比s-array 短一个元素.... -
@snake_charmer 我认为早期版本的 numpy 在这方面更加宽容。我会解决的,谢谢。
-
pandas 似乎提升了一些底层方法的性能。在我的机器上,pandas 只比排序方法慢 29%。 Mad Physicist 提出的方法比排序慢 17%。
标签: python numpy duplicates unique