Nota: o uso de operações in-loco em matrizes NumPy que compartilham memória não é mais um problema na versão 1.13.0 em diante (veja os detalhes aqui ). As duas operações produzirão o mesmo resultado. Esta resposta se aplica apenas a versões anteriores do NumPy.
A mutação de matrizes enquanto estão sendo usadas em cálculos pode levar a resultados inesperados!
No exemplo da pergunta, a subtração com -=
modifica o segundo elemento de a
e, em seguida, usa imediatamente esse segundo elemento modificado na operação do terceiro elemento de a
.
Aqui está o que acontece com o a[1:] -= a[:-1]
passo a passo:
a
é a matriz com os dados [1, 2, 3]
.
Temos duas visões sobre esses dados: a[1:]
é [2, 3]
e a[:-1]
é [1, 2]
.
A subtração no local -=
começa. O primeiro elemento de a[:-1]
, 1, é subtraído do primeiro elemento de a[1:]
. Isso mudou a
para ser [1, 1, 3]
. Agora temos que a[1:]
é uma visão dos dados [1, 3]
e a[:-1]
é uma visão dos dados [1, 1]
(o segundo elemento do array a
foi alterado).
a[:-1]
é agora [1, 1]
e NumPy deve agora subtrair seu segundo elemento que é 1 (não mais 2!) do segundo elemento de a[1:]
. Isso dá a[1:]
uma visão dos valores [1, 2]
.
a
agora é uma matriz com os valores [1, 1, 2]
.
b[1:] = b[1:] - b[:-1]
não tem esse problema porque primeiro b[1:] - b[:-1]
cria uma nova matriz e, em seguida, atribui os valores nessa matriz a b[1:]
. Ele não se modifica b
durante a subtração, portanto, as visualizações b[1:]
e b[:-1]
não mudam.
O conselho geral é evitar modificar uma visualização no local com outra se elas se sobreporem. Isso inclui os operadores -=
, *=
etc. e o uso do out
parâmetro em funções universais (como np.subtract
e np.multiply
) para escrever de volta em um dos arrays.
Internamente, a diferença é que este:
é equivalente a isto:
enquanto isso:
mapeia para este:
Em alguns casos,
__sub__()
e__isub__()
funcionam de forma semelhante. Mas os objetos mutáveis devem sofrer mutação e retornar a si mesmos ao usar__isub__()
, enquanto devem retornar um novo objeto com__sub__()
.Aplicar operações de fatia em objetos numpy cria visualizações neles, portanto, usá-las acessa diretamente a memória do objeto "original".
fonte
Os documentos dizem:
Como regra geral, a subtração aumentada (
x-=y
) éx.__isub__(y)
, para a operação IN -place SE possível, quando a subtração normal (x = x-y
) éx=x.__sub__(y)
. Em objetos não mutáveis, como inteiros, é equivalente. Mas para os mutáveis como arrays ou listas, como no seu exemplo, eles podem ser coisas muito diferentes.fonte