Nota: el uso de operaciones in situ en matrices NumPy que comparten memoria ya no es un problema a partir de la versión 1.13.0 (consulte los detalles aquí ). Las dos operaciones producirán el mismo resultado. Esta respuesta solo se aplica a versiones anteriores de NumPy.
¡La mutación de matrices mientras se utilizan en cálculos puede dar lugar a resultados inesperados!
En el ejemplo de la pregunta, la resta con -=modifica el segundo elemento de ay luego usa inmediatamente ese segundo elemento modificado en la operación sobre el tercer elemento de a.
Esto es lo que sucede con el a[1:] -= a[:-1]paso a paso:
aes 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].
-=Comienza la resta in situ . El primer elemento de a[:-1], 1, se resta del primer elemento de a[1:]. Esto ha cambiado apara ser [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 aha sido cambiado).
a[:-1]es ahora [1, 1]y NumPy ahora debe restar su segundo elemento, que es 1 (¡ya no 2!) del segundo elemento de a[1:]. Esto hace a[1:]una vista de los valores [1, 2].
aahora 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 una nueva matriz primero y luego asigna los valores de esta matriz a b[1:]. No se modifica bdurante la resta, por lo que las vistas b[1:]y 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 usando el outparámetro en funciones universales (como np.subtracty np.multiply) para escribir de nuevo a uno de los arrays.
Internamente, la diferencia es que esto:
es equivalente a esto:
mientras esto:
mapas a esto:
En algunos casos,
__sub__()y__isub__()funcionan de manera similar. Pero los objetos mutables deben mutar y volver a sí mismos cuando se usan__isub__(), mientras que deben devolver un nuevo objeto con__sub__().La aplicación de operaciones de corte en objetos numpy crea vistas sobre ellos, por lo que su uso accede directamente a la memoria del objeto "original".
fuente
Los doctores dicen:
Como regla general, la sustracción aumentada (
x-=y) esx.__isub__(y), para la operación IN- place SI es posible, cuando la sustracción normal (x = x-y) esx=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.fuente