Transmitir una operación a lo largo de un eje específico en python

En python, supongamos que tengo una matriz cuadrada X , de tamaño nxn y tengo un vector numpy a de tamaño n .

Muy simplemente, quiero realizar una resta de transmisión de X – a , pero quiero poder especificar a lo largo de qué dimensión, de modo que puedo especificar que la resta sea a lo largo del eje 0 o del eje 1.

¿Cómo puedo especificar el eje?

Generemos matrices con elementos aleatorios.

Entradas:

 In [62]: X Out[62]: array([[ 0.32322974, 0.50491961, 0.40854442, 0.36908488], [ 0.58840196, 0.1696713 , 0.75428203, 0.01445901], [ 0.27728281, 0.33722084, 0.64187916, 0.51361972], [ 0.39151808, 0.6883594 , 0.93848072, 0.48946276]]) In [63]: a Out[63]: array([ 0.01278876, 0.01854458, 0.16953393, 0.37159562]) 

I. Resta a lo largo del axis=1

Vamos a hacer la resta siguiendo el axis=1 , es decir, queremos restar a de la primera fila de X , la segunda fila de X y así sucesivamente. Para facilitar la inspección de la corrección, solo usemos la primera fila de X :

 In [64]: X[0] - a Out[64]: array([ 0.31044099, 0.48637503, 0.23901049, -0.00251074]) 

Yendo más allá, lo que está pasando es:

 X[0,0] - a[0], X[0,1] - a[1], X[0,2] - a[2] , X[0,3] - a[3] 

Entonces, estamos haciendo coincidir el segundo eje de X con el primer eje de a . Como X es 2D y a es 1D , ambos ya están alineados:

 X : nxn a : n 

Entonces, simplemente hacemos Xa para obtener todas las restas:

 In [65]: Xa Out[65]: array([[ 0.31044099, 0.48637503, 0.23901049, -0.00251074], [ 0.5756132 , 0.15112672, 0.5847481 , -0.3571366 ], [ 0.26449405, 0.31867625, 0.47234523, 0.1420241 ], [ 0.37872932, 0.66981482, 0.76894679, 0.11786714]]) 

Y, finalmente, ver si tenemos X[0] - a obtenido anteriormente está aquí.

Nota importante: Lo que se debe tener en cuenta aquí es que a elemento estaría a lo largo de un eje y a lo largo de esa resta se haría y la transmisión se realizaría a lo largo del otro eje. Entonces, en este caso, aunque la resta ocurre a lo largo del axis=1 , los elementos de a se transmitirían a lo largo del axis=0 .

II. Resta a lo largo del axis=0

De manera similar, hagamos la resta a lo largo de axis=0 , es decir, queremos restar a de la primera columna de X , la segunda columna de X y así sucesivamente. Para facilitar la inspección de la corrección, solo usemos la primera columna de X :

 In [67]: X[:,0]-a Out[67]: array([ 0.31044099, 0.56985738, 0.10774888, 0.01992247]) 

Yendo más allá, lo que está pasando es:

 X[0,0] - a[0], X[1,0] - a[1], X[2,0] - a[2] , X[3,0] - a[3] 

Entonces, estamos haciendo coincidir el primer eje de X con el primer eje de a . Ya que, X es 2D y a es 1D , necesitamos extender a a 2D y mantener todos los elementos a lo largo de su primer eje con a[:,None] :

 X : nxn a[:,None] : nx 1 

Entonces, hacemos Xa[:,None] para obtener todas las restas:

 In [68]: Xa[:,None] Out[68]: array([[ 0.31044099, 0.49213085, 0.39575566, 0.35629612], [ 0.56985738, 0.15112672, 0.73573745, -0.00408557], [ 0.10774888, 0.16768691, 0.47234523, 0.34408579], [ 0.01992247, 0.31676379, 0.5668851 , 0.11786714]]) 

Y, finalmente, vea si tenemos X[:,0] - a obtenido anteriormente está aquí.

Comenzar con 2 dimensiones que son diferentes (al menos en la etiqueta)

  • Forma de X (n,m)
  • a forma (n,)
  • forma b (m,)

Las formas de combinar estos son:

 (n,m)-(n,) => (n,m)-(n,1) => (n,m) X - a[:,None] (n,m)-(m,) => (n,m)-(1,m) => (n,m) X - b[None,:] X - b # [None,:] is automatic, if needed. 

El punto básico es que cuando las dimensiones numéricas difieren, numpy puede agregar nuevas dimensiones al comienzo, pero debe ser explícito acerca de agregar nuevas dimensiones al final.

O para combinar 2 matrices 1d en un producto externo (diferencia):

 (n,) - (m,) => (n,1)-(1,m) => (n,m) a[:,None] - b[None,:] a[:,None] - b 

Sin estas reglas, ab podría resultar en un (n,m) o (m,n) o alguna otra cosa.

Y con 2 matrices de longitudes iguales:

 (n,) - (n,) => (n,) a - a 

o

 (n,) - (n,) => (n,1)-(1,n) => (n,n) a[:,None]-a[None,:] 

=============

Para escribir una función que tome un parámetro de axis , podría usar np.expand_dims :

 In [220]: np.expand_dims([1,2,3],0) Out[220]: array([[1, 2, 3]]) # like [None,:] In [221]: np.expand_dims([1,2,3],1) Out[221]: # like [:,None] array([[1], [2], [3]]) def foo(X, a, axis=0): return X - np.expand_dims(a, axis=axis) 

para ser utilizado como:

 In [223]: foo(np.eye(3),[1,2,3],axis=0) Out[223]: array([[ 0., -2., -3.], [-1., -1., -3.], [-1., -2., -2.]]) In [224]: foo(np.eye(3),[1,2,3],axis=1) Out[224]: array([[ 0., -1., -1.], [-2., -1., -2.], [-3., -3., -2.]])