Numpy: divide cada fila por un elemento vectorial


119

Supongamos que tengo una matriz numpy:

data = np.array([[1,1,1],[2,2,2],[3,3,3]])

y tengo un "vector" correspondiente

vector = np.array([1,2,3])

¿Cómo opero a lo datalargo de cada fila para restar o dividir para que el resultado sea:

sub_result = [[0,0,0], [0,0,0], [0,0,0]]
div_result = [[1,1,1], [1,1,1], [1,1,1]]

En pocas palabras: ¿Cómo realizo una operación en cada fila de una matriz 2D con una matriz 1D de escalares que corresponden a cada fila?

Respuestas:


181

Aqui tienes. Solo necesita usar None(o alternativamente np.newaxis) combinado con transmisión:

In [6]: data - vector[:,None]
Out[6]:
array([[0, 0, 0],
       [0, 0, 0],
       [0, 0, 0]])

In [7]: data / vector[:,None]
Out[7]:
array([[1, 1, 1],
       [1, 1, 1],
       [1, 1, 1]])

13
aquí está el doc.
sábado


@ user108569 usando la última versión de numpy (1.18.1), Nonetodavía funciona de manera equivalente a np.newaxis. No estoy seguro de cuál es su configuración o del problema exacto que está experimentando, pero la respuesta sigue siendo válida.
JoshAdel

11

Como se ha mencionado, cortar con Noneo con np.newaxeses una excelente manera de hacer esto. Otra alternativa es utilizar transposiciones y radiodifusión, como en

(data.T - vector).T

y

(data.T / vector).T

Para matrices de mayor dimensión, es posible que desee utilizar el swapaxesmétodo de matrices NumPy o la rollaxisfunción NumPy . Realmente hay muchas formas de hacer esto.

Para obtener una explicación más completa de la transmisión, consulte http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html


4

La solución de JoshAdel usa np.newaxis para agregar una dimensión. Una alternativa es usar reshape () para alinear las dimensiones en preparación para la transmisión .

data = np.array([[1,1,1],[2,2,2],[3,3,3]])
vector = np.array([1,2,3])

data
# array([[1, 1, 1],
#        [2, 2, 2],
#        [3, 3, 3]])
vector
# array([1, 2, 3])

data.shape
# (3, 3)
vector.shape
# (3,)

data / vector.reshape((3,1))
# array([[1, 1, 1],
#        [1, 1, 1],
#        [1, 1, 1]])

La realización de reshape () permite que las dimensiones se alineen para la transmisión:

data:            3 x 3
vector:              3
vector reshaped: 3 x 1

Tenga en cuenta que data/vectorestá bien, pero no le da la respuesta que desea. Divide cada columna de array(en lugar de cada fila ) por cada elemento correspondiente de vector. Es lo que obtendría si cambiara la forma explícitamente vectorpara ser en 1x3lugar de 3x1.

data / vector
# array([[1, 0, 0],
#        [2, 1, 0],
#        [3, 1, 1]])
data / vector.reshape((1,3))
# array([[1, 0, 0],
#        [2, 1, 0],
#        [3, 1, 1]])

2

La forma pitónica de hacer esto es ...

np.divide(data.T,vector).T

Esto se encarga de la remodelación y también los resultados están en formato de punto flotante. En otras respuestas, los resultados están en formato de entero redondeado.

#NOTA: El número de columnas en los datos y el vector debe coincidir


Nota: Esto no hace lo que solicita el OP. El resultado final es una matriz ([[1., 0.5, 0.33333333], [2., 1., 0.66666667], [3., 1.5, 1.]]). Puede ser 'Pythonic' pero es incorrecto.
Mark Cramer

1
@MarkCramer Gracias. He corregido mi respuesta para proporcionar el resultado correcto.
shantanu pathak

1

Agregando a la respuesta de stackoverflowuser2010, en el caso general solo puede usar

data = np.array([[1,1,1],[2,2,2],[3,3,3]])

vector = np.array([1,2,3])

data / vector.reshape(-1,1)

Esto convertirá su vector en un column matrix/vector. Permitiéndole realizar las operaciones de elemento como desee. Al menos para mí, esta es la forma más intuitiva de hacerlo y dado que (en la mayoría de los casos) numpy solo usará una vista de la misma memoria interna para la remodelación, también es eficiente.


Esta debería ser la respuesta aceptada. La creación de un vector de columna con .reshape(-1,1) es la forma más intuitiva de utilizar la transmisión.
Paul Rougieux
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.