Numpy: incrementa los elementos de una matriz dados los índices requeridos para incrementar

Estoy tratando de convertir un tensor de segundo orden en un tensor binario de tercer orden. Dado un tensor de segundo orden como amxn numpy array: A, necesito tomar el valor de cada elemento: x, en A y reemplazarlo con un vector: v, con dimensiones iguales al valor máximo de A, pero con un valor de 1 incrementado en el índice de v correspondiente al valor x (es decir, v [x] = 1). He estado siguiendo esta pregunta: Incrementar los índices dados en una matriz , que trata la producción de una matriz con incrementos en los índices dados por coordenadas bidimensionales. He estado leyendo las respuestas y tratando de usar np.ravel_multi_index () y np.bincount () para hacer lo mismo pero con coordenadas tridimensionales, sin embargo sigo obteniendo un ValueError: “entrada no válida en la matriz de coordenadas”. Esto es lo que he estado usando:

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 

Si sabe lo que está mal aquí o si conoce un método aún mejor para lograr mi objective, ambos serían de gran ayuda, gracias.

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

Aquí hay una demostración:

 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]]]) 

Compruebe algunos elementos individuales de 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]) 

La expresión A[:,:,np.newaxis] == np.arange(A.max()+1) utiliza la difusión para comparar cada elemento de A con np.arange(A.max()+1) . Para un solo valor, esto se ve como:

 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] es una vista tridimensional de A con forma (3,4,1) . La dimensión adicional se agrega para que la comparación con np.arange(A.max()+1) se transmita a cada elemento, dando un resultado con la forma (3, 4, A.max()+1) .

Con un cambio trivial, esto funcionará para una matriz n-dimensional. Indexando una matriz numpy con puntos suspensivos ... significa “todas las otras dimensiones”. Asi que

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

convierte una matriz n-dimensional en una matriz (n + 1) dimensional, donde la última dimensión es el indicador binario del número entero en A Aquí hay un ejemplo con una matriz unidimensional:

 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]]) 

Puedes hacerlo funcionar de esta manera:

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

La diferencia es que agrego 1 al resultado de amax() , porque ravel_multi_index() espera que todos los índices sean estrictamente menores que las dimensiones, no menores o iguales.

No estoy 100% seguro de si esto es lo que querías; otra forma de hacer que el código se ejecute es especificando mode='clip' o mode='wrap' en ravel_multi_index() , que hace algo un poco diferente y supongo que es menos correcto. Pero puedes probarlo.