我正在寻找一个向量化函数,如果之前已经见过数组中的值,则返回值为 True 的掩码,否则返回 False。
我正在寻找尽可能最快的解决方案,因为速度非常重要。
例如,这就是我想看到的:
array = [1, 2, 1, 2, 3]
mask = [False, False, True, True, False]
所以
is_duplicate = array[mask]
应该返回 [1, 2]
。
有没有一种快速、矢量化的方法来做到这一点?谢谢!
方法#1:排序
def mask_firstocc(a):
sidx = a.argsort(kind='stable')
b = a[sidx]
out = np.r_[False,b[:-1] == b[1:]][sidx.argsort()]
return out
我们可以使用
array-assignment
来提高性能。进一步-
def mask_firstocc_v2(a):
sidx = a.argsort(kind='stable')
b = a[sidx]
mask = np.r_[False,b[:-1] == b[1:]]
out = np.empty(len(a), dtype=bool)
out[sidx] = mask
return out
样品运行 -
In [166]: a
Out[166]: array([2, 1, 1, 0, 0, 4, 0, 3])
In [167]: mask_firstocc(a)
Out[167]: array([False, False, True, False, True, False, True, False])
方法#2: 使用
np.unique(..., return_index)
我们可以利用
np.unique
及其 return_index
,它似乎返回每个唯一元素的第一次出现,因此一个简单的数组赋值然后索引就可以了 -
def mask_firstocc_with_unique(a):
mask = np.ones(len(a), dtype=bool)
mask[np.unique(a, return_index=True)[1]] = False
return mask
使用
np.unique
a = np.array([1, 2, 1, 2, 3])
_, ix = np.unique(a, return_index=True)
b = np.full(a.shape, True)
b[ix] = False
In [45]: b
Out[45]: array([False, False, True, True, False])
您可以使用
enumerate
方法来实现这一点 - 该方法允许您使用 index + value
进行循环:
array = [1, 2, 1, 2, 3]
mask = []
for i,v in enumerate(array):
if array.index(v) == i:
mask.append(False)
else:
mask.append(True)
print(mask)
输出:
[False, False, True, True, False]
虽然 np.unique 可能比排序方法慢,但这里有一个单行代码,为一维数组(或列表)提供灵活性和可读性:
mask = ~np.isin(np.arange(len(array)), np.unique(array, return_index=True)[1])
mask
array([False, False, True, True, False])
几乎根据定义,这不能矢量化。 任何
index
的掩码值取决于 0 到 array
之间每个值的 index
值。 可能有一些算法可以将 array
扩展为 NxN 矩阵并进行奇特的测试,但您仍然会拥有 O(n^2) 算法。 简单的集合算法是 O(n log n)。