矢量化numpy对于子阵列是唯一的

时间:2015-09-03 15:33:39

标签: python numpy

我有一个形状(N,20,20)的numpy数组数据,N是一些非常大的数字。 我想获得每个20x20子阵列中唯一值的数量。 使用循环:

values = []
for i in data:
    values.append(len(np.unique(i)))

我怎样才能对这个循环进行矢量化?速度是一个问题。

如果我尝试np.unique(数据),我得到整个数据数组的唯一值,而不是单独的20x20块,所以这不是我需要的。

1 个答案:

答案 0 :(得分:3)

首先,您可以使用data.reshape(N,-1),因为您有兴趣对最后2个维度进行排序。

获取每行唯一值的简单方法是将每一行转储到一个集合中并让它进行排序:

[len(set(i)) for i in data.reshape(data.shape[0],-1)]

但这是一个迭代,可能是一个快速的。

'向量化'的一个问题是每行中唯一值的集合或列表的长度不同。 “矢量化”时,“具有不同长度的行”是一个红色标记。您不再具有“矩形”数据布局,使大多数矢量化成为可能。

您可以对每一行进行排序:

np.sort(data.reshape(N,-1))

array([[1, 2, 2, 3, 3, 5, 5, 5, 6, 6],
       [1, 1, 1, 2, 2, 2, 3, 3, 5, 7],
       [0, 0, 2, 3, 4, 4, 4, 5, 5, 9],
       [2, 2, 3, 3, 4, 4, 5, 7, 8, 9],
       [0, 2, 2, 2, 2, 5, 5, 5, 7, 9]])

但是如何在不迭代的情况下识别每行中的唯一值?计算非零差异的数量可能只是诀窍:

In [530]: data=np.random.randint(10,size=(5,10))

In [531]: [len(set(i)) for i in data.reshape(data.shape[0],-1)]
Out[531]: [7, 6, 6, 8, 6]

In [532]: sdata=np.sort(data,axis=1)
In [533]: (np.diff(sdata)>0).sum(axis=1)+1            
Out[533]: array([7, 6, 6, 8, 6])

我打算添加关于浮点数的警告,但如果np.unique适用于您的数据,我的方法应该也能正常工作。

[(np.bincount(i)>0).sum() for i in data]

这是一个迭代解决方案,明显快于我的len(set(i))版本,并且与diff...sort具有竞争力。

在[585]中:data.shape 出[585] :( 10000,400)

In [586]: timeit [(np.bincount(i)>0).sum() for i in data]
1 loops, best of 3: 248 ms per loop

In [587]: %%timeit                                       
sdata=np.sort(data,axis=1)
(np.diff(sdata)>0).sum(axis=1)+1
   .....: 
1 loops, best of 3: 280 ms per loop

我刚刚找到了一种更快捷的方式来使用bincountnp.count_nonzero

In [715]: timeit np.array([np.count_nonzero(np.bincount(i)) for i in data])
10 loops, best of 3: 59.6 ms per loop

我对速度提升感到惊讶。但后来我回忆起count_nonzero用于其他函数(例如np.nonzero)来为返回结果分配空间。所以有意义的是,这个函数将被编码以获得最大速度。 (它在diff...sort情况下没有帮助,因为它不接受轴参数)。