我有很多大型一维数组,我想获取唯一值。通常,可以执行以下操作:
x = np.random.randint(10000, size=100000000)
np.unique(x)
但是,这会执行不必要的数组排序。np.unique
的文档没有提到任何在不排序的情况下检索索引的方法。np.unique
的其他答案包括使用return_index
但据我了解,数组仍在排序中。因此,我尝试使用set
:
set(x)
但这比用np.unique
对数组进行排序要慢得多。有没有更快的方法来检索此数组的唯一值,避免排序并且比np.unique
更快?
如果您的值是相对较小范围内的正整数(例如 0 ...10000(,还有另一种使用掩码获取唯一值列表的方法: (见下文unique2()
(
import numpy as np
def unique1(x):
return np.unique(x)
def unique2(x):
maxVal = np.max(x)+1
values = np.arange(maxVal)
used = np.zeros(maxVal)
used[x] = 1
return values[used==1]
# optimized (with option to provide known value range)
def unique3(x,maxVal=None):
maxVal = maxVal or np.max(x)+1
used = np.zeros(maxVal,dtype=np.uint8)
used[x] = 1
return np.argwhere(used==1)[:,0]
在我的测试中,这种方法比 np.unique 快得多,并且不涉及排序:
from timeit import timeit
count = 3
x = np.random.randint(10000, size=100000000)
t = timeit(lambda:unique1(x),number=count)
print("unique1",t)
t = timeit(lambda:unique2(x),number=count)
print("unique2",t)
t = timeit(lambda:unique3(x),number=count)
print("unique3",t)
t = timeit(lambda:unique3(x,10000),number=count)
print("unique3",t, "with known value range")
# unique1 16.894681214000002
# unique2 0.8627655060000023
# unique3 0.8411087540000004
# unique3 0.5896318829999991 with known value range
以防万一你改变对依赖关系的看法,这里有一个简单的numba.njit
实现:
import numba
@numba.njit
def unique(arr):
return np.array(list(set(arr)))
%timeit unique(x) #using Alain T.'s benchmark array
2.64 s ± 799 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit np.unique(x)
5.45 s ± 233 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
没有上面那么快,但也不需要正整数输入。