views:

126

answers:

3

I have a Numpy array and a list of indices whose values I would like to increment by one. This list may contain repeated indices, and I would like the increment to scale with the number of repeats of each index. Without repeats, the command is simple:

a=np.zeros(6).astype('int')
b=[3,2,5]
a[b]+=1

With repeats, I've come up with the following method.

b=[3,2,5,2]                     # indices to increment by one each replicate
bbins=np.bincount(b)
b.sort()                        # sort b because bincount is sorted
incr=bbins[np.nonzero(bbins)]   # create increment array
bu=np.unique(b)                 # sorted, unique indices (len(bu)=len(incr))
a[bu]+=incr

Is this the best way? Is there are risk involved with assuming that the np.bincount and np.unique operations would result in the same sorted order? Am I missing some simple Numpy operation to solve this?

+1  A: 

Why not?

for i in b:
    a[i] += 1
ralu
+2  A: 

After you do

bbins=np.bincount(b)

why not do:

a[:len(bbins)] += bbins

(Edited for further simplification.)

Alok
Would this not be slower, when b contains just a few large bin numbers?
EOL
Yes, it will be slower than a simple Python loop in that case, but still faster than OP's code. I did a quick timing test with `b = [99999, 99997, 99999]`, and `a = np.zeros(1000, 'int')`. Timings are: OP: 2.5 ms, mine: 495 us, simple loop: 84 us.
Alok
This works well. A simple loop has generally been slower in my program. Thanks.
fideli
+1  A: 

If b is a small subrange of a, one can refine Alok's answer like this:

import numpy as np
a = np.zeros( 100000, int )
b = np.array( [99999, 99997, 99999] )

blo, bhi = b.min(), b.max()
bbins = np.bincount( b - blo )
a[blo:bhi+1] += bbins

print a[blo:bhi+1]  # 1 0 2
Denis
Nice. Thanks for this.
Alok