index examples example array python arrays numpy variable-assignment in-place

examples - python array operations



Diferencia entre a-= b y a=a-b en Python (3)

Internamente, la diferencia es que esto:

a[1:] -= a[:-1]

es equivalente a esto:

a[1:] = a[1:].__isub__(a[:-1]) a.__setitem__(slice(1, None, None), a.__getitem__(slice(1, None, None)).__isub__(a.__getitem__(slice(1, None, None)))

mientras esto:

b[1:] = b[1:] - b[:-1]

mapas para esto:

b[1:] = b[1:].__sub__(b[:-1]) b.__setitem__(slice(1, None, None), b.__getitem__(slice(1, None, None)).__sub__(b.__getitem__(slice(1, None, None)))

En algunos casos, __sub__() y __isub__() funcionan de manera similar. Pero los objetos mutables deben mutar y devolverse cuando usan __isub__() , mientras que deben devolver un nuevo objeto con __sub__() .

La aplicación de operaciones de corte en objetos numpy crea vistas en ellos, por lo que usarlos accede directamente a la memoria del objeto "original".

Recientemente he aplicado this solución para promediar cada N filas de matriz. Aunque la solución funciona en general, tuve problemas cuando se aplicó a una matriz de 7x1. He notado que el problema es cuando se usa el operador -= . Para hacer un pequeño ejemplo:

import numpy as np a = np.array([1,2,3]) b = np.copy(a) a[1:] -= a[:-1] b[1:] = b[1:] - b[:-1] print a print b

que salidas:

[1 1 2] [1 1 1]

Entonces, en el caso de una matriz a -= b produce un resultado diferente que a = a - b . Pensé hasta ahora que estas dos formas son exactamente las mismas. ¿Cuál es la diferencia?

¿Cómo es que el método que estoy mencionando para sumar cada N filas en una matriz está funcionando, por ejemplo, para una matriz 7x4 pero no para una matriz 7x1?


Los documentos dicen:

La idea detrás de la asignación aumentada en Python es que no es solo una manera más fácil de escribir la práctica común de almacenar el resultado de una operación binaria en su operando de la izquierda, sino también una forma para que el operando de la izquierda en cuestión sepa que debe funcionar `en sí mismo '', en lugar de crear una copia modificada de sí mismo.

Como regla general, la sustracción aumentada ( x-=y ) es x.__isub__(y) , para la operación IN- place SI es posible, cuando la sustracción normal ( x = xy ) es x=x.__sub__(y) . En objetos no mutables como enteros es equivalente. Pero para los mutables, como matrices o listas, como en su ejemplo, pueden ser cosas muy diferentes.


Nota: el uso de operaciones in situ en matrices NumPy que comparten memoria ya no es un problema en la versión 1.13.0 en adelante (ver detalles here ). Las dos operaciones producirán el mismo resultado. Esta respuesta solo se aplica a versiones anteriores de NumPy.

¡Mutar los arreglos mientras se usan en los cálculos puede conducir a resultados inesperados!

En el ejemplo de la pregunta, la resta con -= modifica el segundo elemento de a y luego usa inmediatamente ese segundo elemento modificado en la operación en el tercer elemento de a .

Esto es lo que sucede con a[1:] -= a[:-1] paso a paso:

  • a es la matriz con los datos [1, 2, 3] .

  • Tenemos dos puntos de vista sobre estos datos: a[1:] es [2, 3] y a[:-1] es [1, 2] .

  • La resta en el lugar -= comienza. El primer elemento de a[:-1] , 1, se resta del primer elemento de a[1:] . Esto ha modificado a para que sea [1, 1, 3] . Ahora tenemos que a[1:] es una vista de los datos [1, 3] , y a[:-1] es una vista de los datos [1, 1] (el segundo elemento de la matriz a ha sido cambiado) .

  • a[:-1] ahora es [1, 1] y NumPy ahora debe restar su segundo elemento que es 1 (¡ya no es 2!) del segundo elemento de a[1:] . Esto hace que a[1:] una vista de los valores [1, 2] .

  • a ahora es una matriz con los valores [1, 1, 2] .

b[1:] = b[1:] - b[:-1] no tiene este problema porque b[1:] - b[:-1] crea primero una nueva matriz y luego asigna los valores de esta matriz a b[1:] . No modifica b sí durante la resta, por lo que las vistas b[1:] b[:-1] no cambian.

El consejo general es evitar modificar una vista in situ con otra si se superponen. Esto incluye los operadores -= , *= , etc. y el uso del parámetro out en funciones universales (como np.subtract y np.multiply ) para volver a escribir en una de las matrices.