Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Increment given indices in a matrix

Tags:

python

numpy

Briefly: there is a similar question and the best answer suggests using numpy.bincount. I need the same thing, but for a matrix.

I've got two arrays:

array([1, 2, 1, 1, 2])
array([2, 1, 1, 1, 1])

together they make indices that should be incremented:

>>> np.array([a, b]).T
array([[1, 2],
       [2, 1],
       [1, 1],
       [1, 1],
       [2, 1]])

I want to get this matrix:

array([[0, 0, 0],
       [0, 2, 1],  # (1,1) twice, (1,2) once
       [0, 2, 0]]) # (2,1) twice

The matrix will be small (like, 5×5), and the number of indices will be large (somewhere near 10^3 or 10^5).

So, is there anything better (faster) than a for-loop?

like image 354
kirelagin Avatar asked Apr 10 '13 07:04

kirelagin


2 Answers

You can still use bincount(). The trick is to convert a and b into a single 1D array of flat indices.

If the matrix is nxm, you could apply bincount() to a * m + b, and construct the matrix from the result.

To take the example in your question:

In [15]: a = np.array([1, 2, 1, 1, 2])

In [16]: b = np.array([2, 1, 1, 1, 1])

In [17]: cnt = np.bincount(a * 3 + b)

In [18]: cnt.resize((3, 3))

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

If the shape of the array is more complicated, it might be easier to use np.ravel_multi_index() instead of computing flat indices by hand:

In [20]: cnt = np.bincount(np.ravel_multi_index(np.vstack((a, b)), (3, 3)))

In [21]: np.resize(cnt, (3, 3))
Out[21]: 
array([[0, 0, 0],
       [0, 2, 1],
       [0, 2, 0]])

(Hat tip @Jaime for pointing out ravel_multi_index.)

like image 182
NPE Avatar answered Oct 14 '22 17:10

NPE


m1 = m.view(numpy.ndarray) # Create view
m1.shape = -1 # Make one-dimensional array
m1 += np.bincount(a+m.shape[1]*b, minlength=m1.size)
like image 40
monoid Avatar answered Oct 14 '22 17:10

monoid