6.10. Broadcasting

Wenn ein binärer Operator zwei Arrays erhält, deren Formen nicht exakt übereinstimmen, löst numpy keinen Fehler aus – es broadcastet. Broadcasting ist eine kleine Menge von Regeln, die entscheiden, ob zwei Formen kompatibel sind und, falls ja, wie die kleinere virtuell gedehnt wird, um zur größeren zu passen.

6.10.1. Die Regeln

Wenn die beiden Operanden die Formen A und B haben, arbeitet numpy sie in zwei Schritten ab.

  1. Ränge angleichen. Hat ein Operand weniger Achsen als der andere, füllt numpy den Anfang seiner Form virtuell mit Achsen der Größe 1 auf, bis beide Formen dieselbe Anzahl von Achsen haben. Ein 1D-Operand der Form (3,), kombiniert mit einem 2D-Operanden der Form (2, 3), wird zu (1, 3) gegen (2, 3).

  2. Jede Achse prüfen. Geht man die nun gleich langen Formen Achse für Achse durch, muss jedes Größenpaar eine von zwei Bedingungen erfüllen: Die Größen sind gleich, oder eine von ihnen ist 1. Eine Achse der Größe 1 wird für die Operation virtuell auf die Größe der anderen Seite gedehnt. Das Paar (1, 3) gegen (2, 3) ist kompatibel, weil die erste Achse eine 1 hat (dehnt sich auf 2) und die zweite Achse übereinstimmt (3 == 3); das Ergebnis hat die Form (2, 3).

Wenn ein Achsenpaar keine der beiden Bedingungen erfüllt, sind die Formen inkompatibel und der Operator löst einen ValueError aus.

6.10.2. Beispiele

Skalar gegen ein beliebiges Array. Der Skalar verhält sich wie die Form (1,) und dehnt sich auf alles:

a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float)
a + 10                 # (2, 3) + scalar -> (2, 3)

1D-Vektor über eine 2D-Matrix. Regel 1 stellt eine Achse der Größe 1 voran, um aus (3,) ein (1, 3) zu machen; Regel 2 dehnt diese Zeile dann über jede Spalte von a nach unten:

row = np.array([100, 200, 300], dtype=np.float)
a + row                # (2, 3) + (3,) -> (2, 3)

Zwei 1D-Arrays gleicher Länge addieren sich elementweise – kein Broadcasting nötig:

np.arange(4) + np.arange(4)

Spaltenvektor gegen einen Zeilenvektor erzeugt eine 2D-„äußere“ Form: (4, 1) kombiniert mit (3,) wird nach dem Voranstellen des Rangs zu (4, 1) gegen (1, 3), und Regel 2 dehnt jeden Operanden entlang seiner Achse der Größe 1:

x = np.array([1, 2, 3, 4]).reshape((4, 1))     # column
y = np.array([10, 20, 30])                      # row
x + y                                           # (4, 3) matrix

Dieselben Formregeln gelten für jede zweiargumentige ufunc, einschließlich arctan2():

np.arctan2(y, 1.0)
np.arctan2(y, x)

6.10.3. Was Broadcasting nicht reserviert

Die Dehnung ist virtuell. numpy durchläuft beide Operanden gemeinsam und liest den kleineren entlang seiner Broadcast-Achse erneut, anstatt ihn zu kopieren. Die Daten des kürzeren Arrays werden niemals im Speicher repliziert.

Was für den Speicher zählt, ist die Größe des Ausgabe-Arrays. a + row reserviert eine Ausgabe in der Form von a, nicht in der Form von a plus der Form von row. Lange Broadcasting-Ketten können dennoch große Zwischenergebnisse erzeugen.

6.10.4. Wenn Broadcasting schiefgeht

Der klassische Fehlschlag sind zwei Formen, bei denen keine eine Achse der Größe 1 zum Dehnen hat und die Größen nicht übereinstimmen – zum Beispiel (3, 4) gegen (4, 3). Regel 2 kann eine 3 nicht zu einer 4 passend machen, also löst numpy einen ValueError aus.

Ein subtileres Problem ist ein Broadcasting, das gelingt, aber nicht so, wie die Anwendung es meinte. (5,) gegen (5, 1) ist der typische Fall: Das Voranstellen des Rangs macht aus (5,) ein (1, 5), das gegen (5, 1) broadcastet und eine (5, 5)-Matrix erzeugt – die äußere Kombination der beiden Vektoren, nicht das elementweise Ergebnis der Länge 5, das die Anwendung wahrscheinlich wollte. Im Zweifelsfall geben Sie shape auf beiden Seiten aus und gehen Sie die Regeln durch, bevor Sie zu reshape() oder transpose() greifen.