6.10. Broadcasting¶
Když binární operátor dostane dvě pole, jejichž tvary se přesně neshodují, numpy nevyvolá chybu – provede broadcasting. Broadcasting je malá sada pravidel, která rozhodují, zda jsou dva tvary kompatibilní, a pokud ano, jak je menší z nich virtuálně roztažen tak, aby odpovídal většímu.
6.10.1. Pravidla¶
Když mají oba operandy tvary A a B, numpy je zpracuje ve dvou krocích.
Sjednocení řádů (ranků). Pokud má jeden operand méně os než druhý,
numpyvirtuálně doplní začátek jeho tvaru osami velikosti 1, dokud oba tvary nemají stejný počet os. 1D operand tvaru(3,)spárovaný s 2D operandem tvaru(2, 3)se stane(1, 3)proti(2, 3).Kontrola každé osy. Při procházení nyní stejně dlouhých tvarů osu po ose musí každá dvojice velikostí splňovat jednu ze dvou podmínek: velikosti jsou stejné, nebo je jedna z nich rovna 1. Osa velikosti 1 je pro danou operaci virtuálně roztažena na velikost druhé strany. Dvojice
(1, 3)proti(2, 3)je kompatibilní, protože první osa má 1 (roztáhne se na 2) a druhá osa se shoduje (3 == 3); výsledek má tvar(2, 3).
Pokud některá dvojice os nesplňuje ani jednu podmínku, jsou tvary nekompatibilní a operátor vyvolá ValueError.
6.10.2. Příklady¶
Skalár proti libovolnému poli. Skalár se chová jako tvar (1,) a roztáhne se na cokoli:
a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float)
a + 10 # (2, 3) + scalar -> (2, 3)
1D vektor přes 2D matici. Pravidlo 1 předřadí osu velikosti 1, aby z (3,) vzniklo (1, 3); pravidlo 2 pak roztáhne tento řádek dolů přes každý sloupec a
row = np.array([100, 200, 300], dtype=np.float)
a + row # (2, 3) + (3,) -> (2, 3)
Dvě 1D pole stejné délky se sčítají po prvcích – broadcasting není potřeba:
np.arange(4) + np.arange(4)
Sloupcový vektor proti řádkovému vektoru produkuje 2D „vnější“ tvar: (4, 1) spárované s (3,) se po předřazení řádu stane (4, 1) proti (1, 3) a pravidlo 2 roztáhne každý operand podél jeho osy velikosti 1:
x = np.array([1, 2, 3, 4]).reshape((4, 1)) # column
y = np.array([10, 20, 30]) # row
x + y # (4, 3) matrix
Stejná pravidla pro tvary platí pro libovolnou ufunc se dvěma argumenty, včetně arctan2()
np.arctan2(y, 1.0)
np.arctan2(y, x)
6.10.3. Co broadcasting nealokuje¶
Roztažení je virtuální. numpy prochází oba operandy společně a místo kopírování menšího z nich jej znovu čte podél jeho osy broadcastingu. Data kratšího pole se nikdy v paměti nereplikují.
Pro paměť je rozhodující velikost výstupního pole. a + row alokuje výstup tvaru a, nikoli tvar a plus tvar row. Dlouhé řetězce broadcastingu mohou přesto produkovat velké mezivýsledky.
6.10.4. Když se broadcasting pokazí¶
Klasickým selháním jsou dva tvary, kde ani jeden nemá osu velikosti 1 k roztažení a velikosti se neshodují – například (3, 4) proti (4, 3). Pravidlo 2 nedokáže spojit 3 se 4, takže numpy vyvolá ValueError.
Záludnějším problémem je broadcasting, který uspěje, ale ne tak, jak aplikace zamýšlela. (5,) proti (5, 1) je kanonický případ: předřazení řádu změní (5,) na (1, 5), což se broadcastuje proti (5, 1) a vyprodukuje matici (5, 5) – vnější kombinaci obou vektorů, nikoli výsledek po prvcích délky 5, který aplikace pravděpodobně chtěla. V případě pochybností vypište shape na obou stranách a projděte pravidla krok za krokem, než sáhnete po reshape() nebo transpose().