Numpy: increase array elements based on indices needed to increase

I am trying to turn a second order tensor into a third order binary tensor. Given a second-order tensor as amxn numpy array: A, I need to take each element value: x, b and replace it with a vector: v, with dimensions equal to the maximum value of A, but with 1 increment at the index v corresponding to the value of x (i.e. e. v [x] = 1). I asked this question: The increment of the given indices in the matrix , which refers to the creation of an array with increments in the indices given by two-dimensional coordinates. I read the answers and tried to use np.ravel_multi_index () and np.bincount () to do the same, but with 3D coordinates, however, I continue to get ValueError: "invalid record in coordinate array". This is what I used:

def expand_to_tensor_3(array): (x, y) = array.shape (a, b) = np.indices((x, y)) a = a.reshape(x*y) b = b.reshape(x*y) tensor_3 = np.bincount(np.ravel_multi_index((a, b, array.reshape(x*y)), (x, y, np.amax(array)))) return tensor_3 

If you know what is wrong here, or if you know an even better method to achieve my goal, both will be very helpful, thanks.

+2
source share
2 answers

You can use (A[:,:,np.newaxis] == np.arange(A.max()+1)).astype(int) .

Here's a demo:

 In [52]: A Out[52]: array([[2, 0, 0, 2], [3, 1, 2, 3], [3, 2, 1, 0]]) In [53]: B = (A[:,:,np.newaxis] == np.arange(A.max()+1)).astype(int) In [54]: B Out[54]: array([[[0, 0, 1, 0], [1, 0, 0, 0], [1, 0, 0, 0], [0, 0, 1, 0]], [[0, 0, 0, 1], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], [[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]]]) 

Check out a few individual elements of A :

 In [55]: A[0,0] Out[55]: 2 In [56]: B[0,0,:] Out[56]: array([0, 0, 1, 0]) In [57]: A[1,3] Out[57]: 3 In [58]: B[1,3,:] Out[58]: array([0, 0, 0, 1]) 

The expression A[:,:,np.newaxis] == np.arange(A.max()+1) uses broadcasting to compare each element of A with np.arange(A.max()+1) . For one value, it looks like this:

 In [63]: 3 == np.arange(A.max()+1) Out[63]: array([False, False, False, True], dtype=bool) In [64]: (3 == np.arange(A.max()+1)).astype(int) Out[64]: array([0, 0, 0, 1]) 

A[:,:,np.newaxis] is a three-dimensional view of A with the form (3,4,1) . An additional size is added so that a comparison with np.arange(A.max()+1) will be passed to each element, giving a result with the form (3, 4, A.max()+1) .

With a trivial change, this will work for an n-dimensional array. Indexing a numpy array with an ellipsis ... means "all other dimensions." So

 (A[..., np.newaxis] == np.arange(A.max()+1)).astype(int) 

converts an n-dimensional array into an (n + 1) -dimensional array, where the last dimension is a binary indicator of an integer in A Here is an example with a one-dimensional array:

 In [6]: a = np.array([3, 4, 0, 1]) In [7]: (a[...,np.newaxis] == np.arange(a.max()+1)).astype(int) Out[7]: array([[0, 0, 0, 1, 0], [0, 0, 0, 0, 1], [1, 0, 0, 0, 0], [0, 1, 0, 0, 0]]) 
+3
source

You can make it work as follows:

 tensor_3 = np.bincount(np.ravel_multi_index((a, b, array.reshape(x*y)), (x, y, np.amax(array) + 1))) 

The difference is that I am adding 1 to the result of amax() , because ravel_multi_index() expects the indexes to be strictly smaller than each other, no less or equal.

I am not 100% sure if this is what you wanted; another way to do a code run is to specify mode='clip' or mode='wrap' in ravel_multi_index() , which does something a little different, and I assume this is not right. But you can try.

0
source

Source: https://habr.com/ru/post/976601/


All Articles