one*_*6oz 3 python performance numpy unique
运行np.unique()时,它首先展平数组,对数组进行排序,然后查找唯一值.当我的数组具有形状(10,3000,3000)时,需要大约一秒钟来查找唯一身份,但这很快就会增加,因为我需要多次调用np.unique().由于我只关心数组中唯一数字的总数,因此排序似乎是浪费时间.
是否有更快的方法来查找除np.unique()之外的大型数组中的唯一值总数?
War*_*ser 11
这是一个适用于dtype np.uint8快于的数组的方法np.unique.
首先,创建一个数组来使用:
In [128]: a = np.random.randint(1, 128, size=(10, 3000, 3000)).astype(np.uint8)
Run Code Online (Sandbox Code Playgroud)
为了以后的比较,使用np.unique以下方法查找唯一值:
In [129]: u = np.unique(a)
Run Code Online (Sandbox Code Playgroud)
这是更快的方法; v将包含结果:
In [130]: q = np.zeros(256, dtype=int)
In [131]: q[a.ravel()] = 1
In [132]: v = np.nonzero(q)[0]
Run Code Online (Sandbox Code Playgroud)
验证我们得到了相同的结果:
In [133]: np.array_equal(u, v)
Out[133]: True
Run Code Online (Sandbox Code Playgroud)
定时:
In [134]: %timeit u = np.unique(a)
2.86 s ± 9.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [135]: %timeit q = np.zeros(256, dtype=int); q[a.ravel()] = 1; v = np.nonzero(q)
300 ms ± 5.52 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Run Code Online (Sandbox Code Playgroud)
所以2.86秒np.unique(),替代方法0.3秒.
我们可以利用元素uint8通过分箱计数来限制范围的事实np.bincount,然后简单地计算其中非零的数量。由于np.bincount需要一个1D数组,因此我们将用 展平输入np.ravel(),然后将其提供给bincount。
因此,实施将是 -
(np.bincount(a.ravel())!=0).sum()
Run Code Online (Sandbox Code Playgroud)
运行时测试
用于创建具有各种数量的唯一数字的输入数组的辅助函数 -
def create_input(n_unique):
unq_nums = np.random.choice(np.arange(256), n_unique,replace=0)
return np.random.choice(unq_nums, (10,3000,3000)).astype(np.uint8)
Run Code Online (Sandbox Code Playgroud)
其他方法:
# @Warren Weckesser's soln
def assign_method(a):
q = np.zeros(256, dtype=int)
q[a.ravel()] = 1
return len(np.nonzero(q)[0])
Run Code Online (Sandbox Code Playgroud)
验证所提出的方法 -
In [141]: a = create_input(n_unique=120)
In [142]: len(np.unique(a))
Out[142]: 120
In [143]: (np.bincount(a.ravel())!=0).sum()
Out[143]: 120
Run Code Online (Sandbox Code Playgroud)
时间安排 -
In [124]: a = create_input(n_unique=128)
In [125]: %timeit len(np.unique(a)) # Original soln
...: %timeit assign_method(a) # @Warren Weckesser's soln
...: %timeit (np.bincount(a.ravel())!=0).sum()
...:
1 loop, best of 3: 3.09 s per loop
1 loop, best of 3: 394 ms per loop
1 loop, best of 3: 209 ms per loop
In [126]: a = create_input(n_unique=256)
In [127]: %timeit len(np.unique(a)) # Original soln
...: %timeit assign_method(a) # @Warren Weckesser's soln
...: %timeit (np.bincount(a.ravel())!=0).sum()
...:
1 loop, best of 3: 3.46 s per loop
1 loop, best of 3: 378 ms per loop
1 loop, best of 3: 212 ms per loop
Run Code Online (Sandbox Code Playgroud)