5

I'm trying to sum +1 to some specific cells of a numpy array but I can't find any way without slow loops:

coords = np.array([[1,2],[1,2],[1,2],[0,0]])
X      = np.zeros((3,3))

for i,j in coords:
  X[i,j] +=1 

Resulting in:

X = [[ 1.  0.  0.]
     [ 0.  0.  3.]
     [ 0.  0.  0.]]

X[coords[:,0],coords[:,1] += 1 returns

X = [[ 1.  0.  0.]
     [ 0.  0.  1.]
     [ 0.  0.  0.]]

Any help?

3 Answers 3

5

numpy.at is exactly for those situations.

In [1]: np.add.at(X,tuple(coords.T),1)

In [2]: X
Out[2]: 
array([[ 1.,  0.,  0.],
       [ 0.,  0.,  3.],
       [ 0.,  0.,  0.]])
Sign up to request clarification or add additional context in comments.

2 Comments

This is good, but a for loop in numba is 80 times faster :/ stackoverflow.com/q/57561500/125507
Deleted question?
4

You can use np.bincount, like so -

out_shape = (3,3) # Input param

# Get linear indices corresponding to coords with the output array shape.
# These form the IDs for accumulation in the next step.
ids = np.ravel_multi_index(coords.T,out_shape)

# Use bincount to get 1-weighted accumulations. Since bincount assumes 1D
# array, we need to do reshaping before and after for desired output.
out = np.bincount(ids,minlength=np.prod(out_shape)).reshape(out_shape)

If you are trying to assign values other than 1s, you can use the additional input argument to feed in weights to np.bincount.

Sample run -

In [2]: coords
Out[2]: 
array([[1, 2],
       [1, 2],
       [1, 2],
       [0, 0]])

In [3]: out_shape = (3,3) # Input param
   ...: ids = np.ravel_multi_index(coords.T,out_shape)
   ...: out = np.bincount(ids,minlength=np.prod(out_shape)).reshape(out_shape)
   ...: 

In [4]: out
Out[4]: 
array([[1, 0, 0],
       [0, 0, 3],
       [0, 0, 0]], dtype=int64)

2 Comments

Thanks, I haven't think about it. I was expecting numpy to provide a much simpler solution for such a trivial operation.
@memecs: IMHO trivial or not, I don't think it is that common, and that is what matters when implementing simpler solutions to problems. ;-)
2

Another option is np.histogramdd:

bins = [np.arange(d + 1) for d in X.shape]
out, edges = np.histogramdd(coords, bins)

print(out)
# [[ 1.  0.  0.]
#  [ 0.  0.  3.]
#  [ 0.  0.  0.]]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.