数组中的Numpy sum元素基于其值

Mih*_*yev 5 python arrays performance numpy

我有未排序的索引数组:

i = np.array([1,5,2,6,4,3,6,7,4,3,2])
Run Code Online (Sandbox Code Playgroud)

我也有一个相同长度的值数组:

v = np.array([2,5,2,3,4,1,2,1,6,4,2])
Run Code Online (Sandbox Code Playgroud)

我有一个具有所需值的零的数组:

d = np.zeros(10)
Run Code Online (Sandbox Code Playgroud)

现在我想根据它在i中的索引添加v的d值中的元素.

如果我在普通的python中这样做,我会这样做:

for index,value in enumerate(v):
    idx = i[index]
    d[idx] += v[index]
Run Code Online (Sandbox Code Playgroud)

这是丑陋和低效的.我该怎么改变它?

use*_*ica 6

np.add.at(d, i, v)
Run Code Online (Sandbox Code Playgroud)

您认为d[i] += v可行,但如果您尝试以相同的方式对该方法进行多次添加,则其中一个会覆盖其他单元格.该ufunc.at方法避免了这些问题.


Div*_*kar 5

我们可以使用np.bincount据称对这种累积加权计数非常有效的方法,所以这里有一个-

counts = np.bincount(i,v)
d[:counts.size] = counts
Run Code Online (Sandbox Code Playgroud)

或者,使用minlength输入参数,对于一般情况,当d可以是任何数组,而我们想添加到该数组中时,

d += np.bincount(i,v,minlength=d.size).astype(d.dtype, copy=False)
Run Code Online (Sandbox Code Playgroud)

运行时测试

本节将本文中np.add.at列出的基础方法other post与本文np.bincount前面列出的基础方法进行比较。

In [61]: def bincount_based(d,i,v):
    ...:     counts = np.bincount(i,v)
    ...:     d[:counts.size] = counts
    ...: 
    ...: def add_at_based(d,i,v):
    ...:     np.add.at(d, i, v)
    ...:     

In [62]: # Inputs (random numbers)
    ...: N = 10000
    ...: i = np.random.randint(0,1000,(N))
    ...: v = np.random.randint(0,1000,(N))
    ...: 
    ...: # Setup output arrays for two approaches
    ...: M = 12000
    ...: d1 = np.zeros(M)
    ...: d2 = np.zeros(M)
    ...: 

In [63]: bincount_based(d1,i,v) # Run approaches
    ...: add_at_based(d2,i,v)
    ...: 

In [64]: np.allclose(d1,d2)  # Verify outputs
Out[64]: True

In [67]: # Setup output arrays for two approaches again for timing
    ...: M = 12000
    ...: d1 = np.zeros(M)
    ...: d2 = np.zeros(M)
    ...: 

In [68]: %timeit add_at_based(d2,i,v)
1000 loops, best of 3: 1.83 ms per loop

In [69]: %timeit bincount_based(d1,i,v)
10000 loops, best of 3: 52.7 µs per loop
Run Code Online (Sandbox Code Playgroud)