Python'da a - = b ve a = a - b arasındaki fark


90

Yakın zamanda bu çözümü her N matris satırının ortalamasını almak için uyguladım . Çözüm genel olarak işe yarasa da 7x1 dizisine uygulandığında sorunlar yaşadım. -=Operatörü kullanırken sorunun olduğunu fark ettim . Küçük bir örnek vermek gerekirse:

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

hangi çıktılar:

[1 1 2]
[1 1 1]

Bu nedenle, bir dizi durumunda, bundan a -= bfarklı bir sonuç üretir a = a - b. Şimdiye kadar bu iki yolun tamamen aynı olduğunu düşündüm. Fark ne?

Nasıl oluyor da bir matristeki her N satırı toplamak için bahsettiğim yöntem örneğin 7x4 matris için çalışıyor ama 7x1 dizisi için çalışmıyor?

Yanıtlar:


80

Not: 1.13.0 sürümünden itibaren belleği paylaşan NumPy dizilerinde yerinde işlemleri kullanmak artık bir sorun değil (ayrıntılara buradan bakın ). İki operasyon aynı sonucu verecektir. Bu cevap yalnızca NumPy'nin önceki sürümleri için geçerlidir.


Dizileri hesaplamalarda kullanılırken değiştirmek, beklenmedik sonuçlara yol açabilir!

Söz konusu örnekte, ile çıkarma, -=öğesinin ikinci öğesini değiştirir ave ardından, öğesinin üçüncü öğesindeki işlemde hemen değiştirilen ikinci öğeyi kullanır a.

İşte a[1:] -= a[:-1]adım adım neler olduğu :

  • averileri içeren dizidir [1, 2, 3].

  • Bu verilerle ilgili iki görüşümüz var: a[1:]eşittir [2, 3]ve a[:-1]eşittir [1, 2].

  • Yerinde çıkarma işlemi -=başlar. İlk elemanı a[:-1]1, birinci elemanın çıkartılmaktadır a[1:]. Bu değiştirdi aolmak [1, 1, 3]. Şimdi buna sahip a[1:]bir veri görünüşüdür [1, 3], ve a[:-1]verilerin bir görünüştür [1, 1](dizinin ikinci elemanı adeğişmiştir).

  • a[:-1]şimdi [1, 1]ve NumPy artık ikinci eleman olan 1'i (artık 2 değil!) ikinci elemanından çıkarmak zorunda a[1:]. Bu a[1:], değerlerin bir görünümünü oluşturur [1, 2].

  • aartık değerleri içeren bir dizidir [1, 1, 2].

b[1:] = b[1:] - b[:-1]bu soruna sahip değildir çünkü önce yeni bir dizi b[1:] - b[:-1]oluşturur ve sonra bu dizideki değerleri öğesine atar . Çıkarma sırasında kendini değiştirmez , bu nedenle görünümler ve değişmez.b[1:]bb[1:]b[:-1]


Genel tavsiye, bir görünümü diğeriyle örtüşüyorlarsa yerinde değiştirmekten kaçınmaktır. Bu, operatörler -=, *=vb. Ve dizilerden birine geri yazmak için outparametrenin evrensel işlevlerde ( np.subtractve gibi np.multiply) kullanılmasını içerir.


4
Bu cevabı şu anda kabul edilen cevaba daha çok tercih ediyorum. Değiştirilebilir nesneleri yerinde değiştirmenin etkisini göstermek için çok net bir dil kullanır. Daha da önemlisi, son paragraf, örtüşen görüşler için yerinde değişiklik yapmanın önemini doğrudan vurgulamaktadır ki bu, bu sorudan yola çıkarak alınması gereken ders olmalıdır.
Reti43

43

Dahili olarak, fark şudur:

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

şuna eşdeğerdir:

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)))

bu sırada:

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

bununla eşleşir:

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)))

Bazı durumlarda __sub__()ve __isub__()benzer şekilde çalışır. Ancak değiştirilebilir nesneler, kullanım sırasında değişmeli ve kendilerini geri dönmelidir.__isub__() , yeni bir nesne döndürmeleri gerekirken, kullanırken dönmelidir __sub__().

Numpy nesnelere dilim işlemleri uygulamak, bunlar üzerinde görünümler oluşturur, bu nedenle bunları kullanmak doğrudan "orijinal" nesnenin belleğine erişir.


11

Dokümanlar şöyle diyor:

Python'da artırılmış atamanın arkasındaki fikir, bir ikili işlemin sonucunu sol el operandında depolamanın genel uygulamasını yazmanın daha kolay bir yolu değil, aynı zamanda söz konusu sol el operandının kendisinin değiştirilmiş bir kopyasını oluşturmak yerine, `` kendi başına '' çalışması gerektiğini bilir.

Bir başparmak kural olarak, güçlendirilmiş çıkarmasıdır ( x-=y) 'dir x.__isub__(y)için, IN -Yeri operasyon EĞER Normal çıkarmasıdır (mümkünse x = x-y)' dir x=x.__sub__(y). Tamsayılar gibi değiştirilebilir olmayan nesnelerde eşdeğerdir. Ancak diziler veya listeler gibi değiştirilebilir olanlar için, sizin örneğinizde olduğu gibi, bunlar çok farklı şeyler olabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.