关于python:获取唯一的一维NumPy数组值而不进行排序

Getting Unique 1D NumPy Array Values without Sorting

我有许多大型1D数组,我想获取唯一的值。通常,可以执行以下操作:

1
2
x = np.random.randint(10000, size=100000000)
np.unique(x)

但是,这会执行不必??要的数组排序。 np.unique的文档未提及不进行排序即可检索索引的任何方式。 np.unique的其他答案包括使用return_index,但是据我了解,该数组仍在排序。因此,我尝试使用set

1
set(x)

但是,这比用np.unique对数组进行排序要慢得多。是否有一种更快的方法来检索此数组的唯一值,从而避免排序并比np.unique更快?


如果您的值是相对较小范围内的正整数(例如0 ... 10000),则有另一种方法可以使用掩码获取唯一值列表:
(请参见下面的unique2())

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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快很多,并且不涉及排序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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实现:

1
2
3
4
5
6
7
8
9
10
11
12
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)

闪电般的速度不如上面,但也不需要正整数输入。