从两个numpy数组中删除重复的元素

时间:2016-03-26 06:20:33

标签: python arrays numpy duplicates

我有两个numpy数组ab,有两千万个元素(浮点数)。如果这两个数组的组合元素相同,那么我们称之为重复,应该从两个数组中删除。例如,

a = numpy.array([1,3,6,3,7,8,3,2,9,10,14,6])
b = numpy.array([2,4,15,4,7,9,2,2,0,11,4,15])

从这两个数组中,我们a[2]&b[2]a[11]&b[11]相同,然后我们将其称为重复元素,应将其删除。与a[1]&b[1] vs a[3]&b[3]相同虽然每个数组本身都有重复元素,但它们不会被视为重复元素。所以我希望返回的数组是:

a = numpy.array([1,3,6,7,8,3,2,9,10,14])
b = numpy.array([2,4,15,7,9,2,2,0,11,4])

任何人都有最聪明的方法来实现这种减少吗?

2 个答案:

答案 0 :(得分:3)

首先,您必须打包ab以识别重复项。 如果值是正整数(参见其他情况下的编辑),则可以通过以下方式实现:

base=a.max()+1
c=a+base*b

然后只需在c中找到唯一值:

val,ind=np.unique(c,return_index=True)

并检索ab中的相关值。

ind.sort()
print(a[ind])
print(b[ind])

重复的删除。 (这里有两个):

[ 1  3  6  7  8  3  2  9 10 14]
[ 2  4 15  7  9  2  2  0 11  4]

修改

无论数据类型如何,c数组都可以如下所示,将数据打包为字节:

ab=ascontiguousarray(vstack((a,b)).T) 
dtype = 'S'+str(2*a.itemsize)
c=ab.view(dtype=dtype)

答案 1 :(得分:2)

这是在一次通过中完成的,并且不需要任何额外的内存用于生成的数组。

将每个索引处的元素配对并迭代它们。跟踪到目前为止已经看到哪些对以及数组索引的计数器。如果以前没有看到新的对,则索引将增加1,有效地将它们写回原始位置。但是,对于重复对,您不会增加索引,有效地将每个新对转移到左侧一个位置。最后,保留第一个index个元素以缩短数组。

import itertools as it

def delete_duplicate_pairs(*arrays):
    unique = set()
    arrays = list(arrays)
    n = range(len(arrays))
    index = 0
    for pair in it.izip(*arrays):
        if pair not in unique:
            unique.add(pair)
            for i in n:
                arrays[i][index] = pair[i]
            index += 1
    return [a[:index] for a in arrays]

如果您使用的是Python 2,zip()会预先创建对列表。如果阵列中有很多元素,那么使用itertools.izip()会更有效率,这会在您请求时创建对。但是,默认情况下,Python 3中的zip()的行为与此类似。

对于您的情况,

>>> import numpy as np
>>> a = np.array([1,3,6,3,7,8,3,2,9,10,14,6])
>>> b = np.array([2,4,15,4,7,9,2,2,0,11,4,15])
>>> a, b = delete_duplicate_pairs(a, b)
>>> a
array([ 1,  3,  6,  7,  8,  3,  2,  9, 10, 14])
>>> b
array([ 2,  4, 15,  7,  9,  2,  2,  0, 11,  4])

现在,这一切都归结为数组所拥有的值。如果您只有0-9的值,则只有100个唯一对,大多数元素将是重复的,这样可以节省您的时间。对于ab的2000万个元素并且仅包含0-9之间的值,该过程在6秒内完成。对于0-999之间的值,需要12秒。