你的方法:
def dedup_reference(a, b):
for el in b:
idx = (el == a).argmax()
if a[idx] == el:
a = np.delete(a, idx)
return a
扫描方法需要对输入进行排序:
def dedup_scan(arr, sel):
arr.sort()
sel.sort()
mask = np.ones_like(arr, dtype=np.bool)
sel_idx = 0
for i, x in enumerate(arr):
if sel_idx == sel.size:
break
if x == sel[sel_idx]:
mask[i] = False
sel_idx += 1
return arr[mask]
np.unique计数方法:
def dedup_unique(arr, sel):
d_arr = dict(zip(*np.unique(arr, return_counts=True)))
d_sel = dict(zip(*np.unique(sel, return_counts=True)))
d = {k: v - d_sel.get(k, 0) for k, v in d_arr.items()}
res = np.empty(sum(d.values()), dtype=arr.dtype)
idx = 0
for k, count in d.items():
res[idx:idx+count] = k
idx += count
return res
您也许可以通过巧妙地使用 numpy 集合函数(例如 np.in1d)来完成与上述相同的操作,但我认为这并不比仅使用字典快。
这是一个懒惰的基准测试尝试(更新为包括@Divakar 的diff_v2 和diff_v3 方法):
>>> def timeit_ab(f, n=10):
... cmd = f"{f}(a.copy(), b.copy())"
... t = timeit(cmd, globals=globals(), number=n) / n
... print("{:.4f} {}".format(t, f))
>>> array_copy = lambda x, y: None
>>> funcs = [
... 'array_copy',
... 'dedup_reference',
... 'dedup_scan',
... 'dedup_unique',
... 'diff_v2',
... 'diff_v3',
... ]
>>> def run_test(maxval, an, bn):
... global a, b
... a = np.random.randint(maxval, size=an)
... b = np.random.choice(a, size=bn, replace=False)
... for f in funcs:
... timeit_ab(f)
>>> run_test(10**1, 10000, 5000)
0.0000 array_copy
0.0617 dedup_reference
0.0035 dedup_scan
0.0004 dedup_unique (*)
0.0020 diff_v2
0.0009 diff_v3
>>> run_test(10**2, 10000, 5000)
0.0000 array_copy
0.0643 dedup_reference
0.0037 dedup_scan
0.0007 dedup_unique (*)
0.0023 diff_v2
0.0013 diff_v3
>>> run_test(10**3, 10000, 5000)
0.0000 array_copy
0.0641 dedup_reference
0.0041 dedup_scan
0.0022 dedup_unique
0.0027 diff_v2
0.0016 diff_v3 (*)
>>> run_test(10**4, 10000, 5000)
0.0000 array_copy
0.0635 dedup_reference
0.0041 dedup_scan
0.0082 dedup_unique
0.0029 diff_v2
0.0015 diff_v3 (*)
>>> run_test(10**5, 10000, 5000)
0.0000 array_copy
0.0635 dedup_reference
0.0041 dedup_scan
0.0118 dedup_unique
0.0031 diff_v2
0.0016 diff_v3 (*)
>>> run_test(10**6, 10000, 5000)
0.0000 array_copy
0.0627 dedup_reference
0.0043 dedup_scan
0.0126 dedup_unique
0.0032 diff_v2
0.0016 diff_v3 (*)
要点:
-
dedup_reference 会随着重复次数的增加而显着减慢。
-
如果值的范围很小,
dedup_unique 最快。 diff_v3 非常快,并且不依赖于值的范围。
- 数组复制时间可以忽略不计。
- 字典很酷。
性能特征在很大程度上取决于数据量(未测试)以及数据的统计分布。我建议使用您自己的数据测试这些方法并选择最快的方法。请注意,各种解决方案会产生不同的输出,并对输入做出不同的假设。