运行np.unique()时,它首先将数组平整,对数组进行排序,然后查找唯一值。当我有形状的阵列(10,3000,3000)时,需要大约一秒钟的时间才能找到唯一身份,但这很快就会加起来,因为我需要多次调用np.unique()。由于我只关心数组中唯一数字的总数,排序似乎是浪费时间。有效地计算唯一元素的数量--NumPy/Python
是否有更快的方法找到除np.unique()以外的大数组中唯一值的总数?
运行np.unique()时,它首先将数组平整,对数组进行排序,然后查找唯一值。当我有形状的阵列(10,3000,3000)时,需要大约一秒钟的时间才能找到唯一身份,但这很快就会加起来,因为我需要多次调用np.unique()。由于我只关心数组中唯一数字的总数,排序似乎是浪费时间。有效地计算唯一元素的数量--NumPy/Python
是否有更快的方法找到除np.unique()以外的大数组中唯一值的总数?
下面是一个适用于dtype为np.uint8
的数组比np.unique
快的方法。
首先,创建一个阵列的工作:
In [128]: a = np.random.randint(1, 128, size=(10, 3000, 3000)).astype(np.uint8)
对于以后的比较,使用np.unique
找到独特的价值观:
In [129]: u = np.unique(a)
这里的更快的方法; v
将包含结果:
In [130]: q = np.zeros(256, dtype=int)
In [131]: q[a.ravel()] = 1
In [132]: v = np.nonzero(q)[0]
验证我们得到了相同的结果:
In [133]: np.array_equal(u, v)
Out[133]: True
时间:
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)
所以2.86秒为np.unique()
,和0.3秒的替代方法。
这工作完美。谢谢。它似乎也可以用来返回一个排序的唯一数组。我想知道为什么numpy决定实施他们独特的()方式。 – onepint16oz
'numpy.unique'可以处理任意数据类型的数组(所有的各种整数和浮点类型,复数类型和结构化数组)。对于'numpy.unique'来说,使用这种方法处理一个(可能是两个)字节整数类型是一种特殊情况,这似乎是可行的。 –
我们可以利用这样一个事实:元素被限制在uint8
范围内,通过与np.bincount
分箱计数,然后简单地计算其中的非零数。因为np.bincount
需要1D
阵列,我们会用np.ravel()
将输入平坦化,然后将其输入bincount
。
因此,实现将是 -
(np.bincount(a.ravel())!=0).sum()
运行测试
助手函数来创建与各种数目的唯一号码的输入数组 -
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)
其他方法(ES ):
# @Warren Weckesser's soln
def assign_method(a):
q = np.zeros(256, dtype=int)
q[a.ravel()] = 1
return len(np.nonzero(q)[0])
验证提出的方法的 -
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
计时 -
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
不错。我也尝试过'bincount',但它似乎比较慢。实际上,当我使用你的代码时,'assign_method(a)'为295 ms,'(np.bincount(a.ravel())!= 0).sum()'为425 ms。去搞清楚。 –
@WarrenWeckesser可能是硬件(CPU,RAM)。我在英特尔i7-6700HQ,16GB RAM。但是,您的ideone具有可重现性:https://ideone.com/WDWq9j – Divakar
我使用的是“2013年后期”Macbook Pro,2.6 GHz Intel Core i7,16 GB 1600 MHz DDR3。另外:Python 3.5.2,numpy 1.13.1。 –
你是什么阵列的数据类型(例如什么是“a.dtype”)? –
@WarrenWeckesser uint8 – onepint16oz
熊猫的独特功能不排序,因此速度更快。您可能需要检查:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.unique.html – ayhan