6.10. Broadcasting¶
Quando um operador binário recebe dois arrays cujas formas não correspondem exatamente, o numpy não levanta erro – faz broadcasting. O broadcasting é um pequeno conjunto de regras que decide se duas formas são compatíveis e, em caso afirmativo, como a menor é virtualmente esticada para corresponder à maior.
6.10.1. As regras¶
Quando os dois operandos têm formas A e B, o numpy percorre-os em dois passos.
Igualar as dimensões. Se um operando tiver menos eixos do que o outro, o
numpypreenche virtualmente a frente da sua forma com eixos de tamanho 1 até ambas as formas terem o mesmo número de eixos. Um operando 1-D de forma(3,)emparelhado com um operando 2-D de forma(2, 3)torna-se(1, 3)contra(2, 3).Verificar cada eixo. Percorrendo as formas de igual comprimento eixo a eixo, cada par de tamanhos deve satisfazer uma de duas condições: os tamanhos são iguais, ou um deles é 1. Um eixo de tamanho 1 é virtualmente esticado para o tamanho do outro lado para a operação. O par
(1, 3)contra(2, 3)é compatível porque o primeiro eixo tem um 1 (estica para 2) e o segundo eixo corresponde (3 == 3); o resultado tem a forma(2, 3).
Se algum par de eixos não satisfizer nenhuma das condições, as formas são incompatíveis e o operador levanta ValueError.
6.10.2. Exemplos¶
Escalar contra qualquer array. O escalar age como forma (1,) e estica para qualquer coisa:
a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float)
a + 10 # (2, 3) + scalar -> (2, 3)
Vetor 1-D através de uma matriz 2-D. A regra 1 acrescenta um eixo de tamanho 1 para transformar (3,) em (1, 3); a regra 2 estica essa linha ao longo de cada coluna de a
row = np.array([100, 200, 300], dtype=np.float)
a + row # (2, 3) + (3,) -> (2, 3)
Dois arrays 1-D de comprimento igual somam elemento a elemento – não é necessário broadcasting:
np.arange(4) + np.arange(4)
Vetor coluna contra um vetor linha produz uma forma 2-D «exterior»: (4, 1) emparelhado com (3,) torna-se (4, 1) contra (1, 3) após o acréscimo de dimensão, e a regra 2 estica cada operando ao longo do seu eixo de tamanho 1:
x = np.array([1, 2, 3, 4]).reshape((4, 1)) # column
y = np.array([10, 20, 30]) # row
x + y # (4, 3) matrix
As mesmas regras de forma aplicam-se a qualquer ufunc de dois argumentos, incluindo arctan2()
np.arctan2(y, 1.0)
np.arctan2(y, x)
6.10.3. O que o broadcasting não aloca¶
O estiramento é virtual. O numpy percorre ambos os operandos em conjunto, relendo o menor ao longo do seu eixo de broadcast em vez de o copiar. Os dados do array mais curto nunca são replicados em memória.
O que importa para a memória é o tamanho do array de saída. a + row aloca uma saída com a forma de a, não a forma de a mais a forma de row. Cadeias longas de broadcasting podem ainda assim produzir intermediários grandes.
6.10.4. Quando o broadcasting corre mal¶
O falhanço clássico ocorre com duas formas em que nenhuma tem um eixo de tamanho 1 para esticar e os tamanhos discordam – (3, 4) contra (4, 3), por exemplo. A regra 2 não consegue fazer corresponder um 3 a um 4, pelo que o numpy levanta ValueError.
Um problema mais subtil é um broadcasting que tem sucesso, mas não da forma que a aplicação pretendia. (5,) contra (5, 1) é o caso canónico: o acréscimo de dimensão transforma (5,) em (1, 5), que faz broadcasting contra (5, 1) para produzir uma matriz (5, 5) – a combinação exterior dos dois vetores, não o resultado elemento a elemento de comprimento 5 que a aplicação provavelmente pretendia. Em caso de dúvida, imprima shape em ambos os lados e percorra as regras antes de recorrer a reshape() ou transpose().