在没有循环的数组中累加数字。(python)

在没有循环的数组中累加数字。(python),python,numpy,for-loop,optimization,vectorization,Python,Numpy,For Loop,Optimization,Vectorization,所以我有一个(看起来)简单的问题,我现在通过for循环来解决这个问题 基本上,我希望在numpy矩阵中增加特定的单元格,但如果可能的话,我希望不使用for循环 要提供更多详细信息:我有100x100numpy矩阵,x。我还有一个2x1000numpy矩阵PP只是将索引存储到X,因此,例如,P的每一列都有单元格的行-列索引,我想在X中增加该索引 我现在做的是: for p in range(P.shape[1]): X[P[0,p], P[1,p]] += 1 我的问题是,有没有一种不使用f

所以我有一个(看起来)简单的问题,我现在通过for循环来解决这个问题

基本上,我希望在numpy矩阵中增加特定的单元格,但如果可能的话,我希望不使用for循环

要提供更多详细信息:我有
100x100
numpy矩阵,
x
。我还有一个
2x1000
numpy矩阵
P
P
只是将索引存储到
X
,因此,例如,
P
的每一列都有单元格的行-列索引,我想在
X
中增加该索引

我现在做的是:

for p in range(P.shape[1]):
  X[P[0,p], P[1,p]] += 1
我的问题是,有没有一种不使用for循环的方法来实现这一点

谢谢

使用
add
ufunc的方法:

或者,如果
p
保证不会选择
X
的同一单元格两次,则只需进行高级索引:

X[P[0], P[1]] += 1
使用
add
ufunc的方法:

或者,如果
p
保证不会选择
X
的同一单元格两次,则只需进行高级索引:

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

使用
线性指数
bincount
-

lidx = np.ravel_multi_index(P, X.shape)
X += np.bincount(lidx, minlength=X.size).reshape(X.shape)
标杆管理 对于索引不重复的情况,中建议的基于的高级索引方法似乎非常有效

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

接近-

 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:

案例2:

案例3:


使用
线性指数
bincount
-

lidx = np.ravel_multi_index(P, X.shape)
X += np.bincount(lidx, minlength=X.size).reshape(X.shape)
标杆管理 对于索引不重复的情况,中建议的基于的高级索引方法似乎非常有效

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

接近-

 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:

案例2:

案例3:


对于范围内的p(p.shape[1]):
可能?@Divakar是的,抱歉,更正了错误<代码>范围内的p(p.shape[1]):可能?@Divakar是的,抱歉,更正了错误!我花了一段时间才明白你为什么这么做。重复指数是一种痛苦。我花了一段时间才意识到你为什么这么做。重复索引是一种痛苦。
P[0],P[1]
可以更一般地表示为
(*P,)
。所以
numpy.add.at(X,(*P,),1)
X[(P,)]+=1
。这很好,因为它不会在维度数上进行硬编码。@Mad物理学家:或者只是
tuple(P)
,但我选择
P[0],P[1]
,因为我觉得这种情况更清楚。嗨,很可能有重复的索引。这是否意味着我应该使用第一个选项?第二个问题是,为什么第一个选项比for循环更好?谢谢@他们是用石墨笔写的。Python
for
循环对于速度不是很好。从功能上讲,循环与使用
add.at
没有什么不同,但它的速度要慢得多,需要输入更多的文本。@Grapebyond:就是这样,假设您编写了类似的包装器和类似的C级代码,那么是的。
P[0],P[1]
可以更一般地表示为
(*P,)
。所以
numpy.add.at(X,(*P,),1)
X[(P,)]+=1
。这很好,因为它不会在维度数上进行硬编码。@Mad物理学家:或者只是
tuple(P)
,但我选择
P[0],P[1]
,因为我觉得这种情况更清楚。嗨,很可能有重复的索引。这是否意味着我应该使用第一个选项?第二个问题是,为什么第一个选项比for循环更好?谢谢@他们是用石墨笔写的。Python
for
循环对于速度不是很好。从功能上讲,循环与使用
add.at
没有什么不同,但它的速度要慢得多,需要输入更多的文本。@TheGraphibeyond:就是这样,假设您编写了类似的包装器和类似的C级代码,那么是的。
 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