在没有循环的情况下累积数组中的数字。 (蟒蛇)

时间:2017-09-13 16:56:06

标签: python numpy for-loop optimization vectorization

所以我有一个(看似)简单的问题,我现在正在通过for循环做这个问题。

基本上,我想在numpy矩阵中增加特定单元格,但是如果可能的话,我想在没有for循环的情况下进行。

提供更多详细信息:我有100 x 100 numpy矩阵X。我还有一个2x1000 numpy矩阵PP只会将索引存储到X中,因此,例如,每个P列都有单元格的行列索引,我希望在X中递增。

我现在做的是:

for p in range(P.shape[1]):
  X[P[0,p], P[1,p]] += 1

我的问题是,有没有办法在没有for循环的情况下做到这一点?

谢谢!

2 个答案:

答案 0 :(得分:3)

使用add ufunc的at方法advanced indexing

numpy.add.at(X, (P[0], P[1]), 1)
如果P保证永远不会选择X两次相同的单元格,那么

或只是高级索引:

X[P[0], P[1]] += 1

答案 1 :(得分:2)

使用linear-indicesbincount -

lidx = np.ravel_multi_index(P, X.shape)
X += np.bincount(lidx, minlength=X.size).reshape(X.shape)

基准

对于不重复索引的情况,@user2357112's post中建议的基于advanced indexing的方法似乎非常有效。

对于重复的情况,我们有np.add.atnp.bincount,性能数字似乎取决于index数组相对于输入数组大小的大小。

方法 -

 def app0(X,P): # @user2357112's soln1
     np.add.at(X, (P[0], P[1]), 1)

 def app1(X, P): # Proposed in this ppst
     lidx = np.ravel_multi_index(P, X.shape)
     X += np.bincount(lidx, minlength=X.size).reshape(X.shape)

这里有几个时间测试表明 -

案例#1:

 In [141]: X = np.random.randint(0,9,(100,100))
      ...: P = np.random.randint(0,100,(2,1000))
      ...: 

 In [142]: %timeit app0(X, P)
      ...: %timeit app1(X, P)
      ...: 
 10000 loops, best of 3: 68.9 µs per loop
 100000 loops, best of 3: 15.1 µs per loop

案例#2:

 In [143]: X = np.random.randint(0,9,(1000,1000))
      ...: P = np.random.randint(0,1000,(2,10000))
      ...: 

 In [144]: %timeit app0(X, P)
      ...: %timeit app1(X, P)
      ...: 
 1000 loops, best of 3: 687 µs per loop
 1000 loops, best of 3: 1.48 ms per loop

案例#3:

 In [145]: X = np.random.randint(0,9,(1000,1000))
      ...: P = np.random.randint(0,1000,(2,100000))
      ...: 

 In [146]: %timeit app0(X, P)
      ...: %timeit app1(X, P)
      ...: 
 100 loops, best of 3: 11.3 ms per loop
 100 loops, best of 3: 2.51 ms per loop