6.10. Broadcasting¶
Amikor egy bináris operátor két olyan tömböt kap, amelyek alakja nem egyezik meg pontosan, a numpy nem vált ki kivételt – broadcastol. A broadcasting szabályok kis halmaza, amelyek eldöntik, hogy két alak kompatibilis-e, és ha igen, hogyan nyúlik virtuálisan a kisebb a nagyobbhoz illeszkedve.
6.10.1. A szabályok¶
Amikor a két operandus alakja A és B, a numpy két lépésben dolgozza fel őket.
Igazítsd a rangokat. Ha az egyik operandusnak kevesebb tengelye van, mint a másiknak, a
numpyvirtuálisan 1 méretű tengelyekkel tölti ki az alakja elejét, amíg mindkét alaknak ugyanannyi tengelye nem lesz. Egy(3,)alakú 1D operandus egy(2, 3)alakú 2D operandussal párosítva(1, 3)lesz a(2, 3)ellenében.Ellenőrizz minden tengelyt. Végighaladva a most azonos hosszúságú alakokon tengelyenként, minden méretpárnak teljesítenie kell a két feltétel egyikét: a méretek egyenlők, vagy az egyikük 1. Egy 1 méretű tengely virtuálisan a másik oldal méretére nyúlik a művelethez. A
(1, 3)pár a(2, 3)ellenében kompatibilis, mert az első tengelynek 1-ese van (2-re nyúlik), a második tengely pedig egyezik (3 == 3); az eredmény alakja(2, 3).
Ha bármelyik tengelypár egyik feltételt sem teljesíti, az alakok inkompatibilisek, és az operátor ValueError kivételt vált ki.
6.10.2. Példák¶
Skalár bármilyen tömb ellenében. A skalár úgy viselkedik, mint egy (1,) alak, és bármihez nyúlik:
a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float)
a + 10 # (2, 3) + scalar -> (2, 3)
1D vektor egy 2D mátrixon át. Az 1. szabály egy 1 méretű tengelyt fűz elé, hogy a (3,) (1, 3) legyen; a 2. szabály ezután lenyújtja azt a sort a minden oszlopán:
row = np.array([100, 200, 300], dtype=np.float)
a + row # (2, 3) + (3,) -> (2, 3)
Két azonos hosszúságú 1D tömb elemenként ad össze – nincs szükség broadcastingra:
np.arange(4) + np.arange(4)
Oszlopvektor egy sorvektor ellenében egy 2D „külső” alakot hoz létre: a (4, 1) a (3,) értékkel párosítva a rang elé fűzése után (4, 1) lesz a (1, 3) ellenében, és a 2. szabály mindegyik operandust az 1 méretű tengelye mentén nyújtja:
x = np.array([1, 2, 3, 4]).reshape((4, 1)) # column
y = np.array([10, 20, 30]) # row
x + y # (4, 3) matrix
Ugyanazok az alakszabályok vonatkoznak bármely kétargumentumú ufunc-ra, beleértve az arctan2() függvényt is:
np.arctan2(y, 1.0)
np.arctan2(y, x)
6.10.3. Mit nem allokál a broadcasting¶
A nyújtás virtuális. A numpy mindkét operandust együtt járja be, a kisebbet a broadcast tengelye mentén újraolvasva, ahelyett hogy másolná. A rövidebb tömb adatai soha nem replikálódnak a memóriában.
A memória szempontjából a kimeneti tömb mérete számít. Az a + row az a alakjának megfelelő kimenetet allokál, nem az a alakja plusz a row alakja méretűt. A hosszú broadcasting láncok mégis nagy köztes eredményeket produkálhatnak.
6.10.4. Amikor a broadcasting rosszul sül el¶
A klasszikus hiba két olyan alak, ahol egyiknek sincs 1 méretű tengelye a nyújtáshoz, és a méretek nem egyeznek – például (3, 4) a (4, 3) ellenében. A 2. szabály nem tud egy 3-ast egy 4-eshez illeszteni, így a numpy ValueError kivételt vált ki.
Egy finomabb probléma egy olyan broadcast, amely sikerül, de nem úgy, ahogy az alkalmazás szándékozta. Az (5,) a (5, 1) ellenében a kanonikus eset: a rang elé fűzése a (5,) értéket (1, 5) értékké alakítja, amely a (5, 1) ellen broadcastolva egy (5, 5) mátrixot hoz létre – a két vektor külső kombinációját, nem pedig az 5 hosszúságú elemenkénti eredményt, amelyet az alkalmazás valószínűleg akart. Ha kétségeid vannak, írasd ki a shape értéket mindkét oldalon, és lépkedj végig a szabályokon, mielőtt a reshape() vagy a transpose() után nyúlnál.