Digamos que eu tenha uma série de permutações perm
que poderiam ser assim:
perm = np.array([[0, 1, 2], [1, 2, 0], [0, 2, 1], [2, 1, 0]])
Se eu quiser aplicá-lo a um eixo, posso escrever algo como:
v = np.arange(9).reshape(3, 3)
print(v[perm])
Saída:
array([[[0, 1, 2],
[3, 4, 5],
[6, 7, 8]],
[[3, 4, 5],
[6, 7, 8],
[0, 1, 2]],
[[0, 1, 2],
[6, 7, 8],
[3, 4, 5]],
[[6, 7, 8],
[3, 4, 5],
[0, 1, 2]]])
Agora gostaria de aplicá-lo a dois eixos ao mesmo tempo. Eu descobri que posso fazer isso através de:
np.array([v[tuple(np.meshgrid(p, p, indexing="ij"))] for p in perm])
Mas acho isso bastante ineficiente, porque precisa criar uma grade de malha e também requer um loop for. Criei um array pequeno neste exemplo, mas na realidade tenho arrays muito maiores com muitas permutações, então adoraria ter algo que fosse tão rápido e simples quanto a versão de um eixo.
Que tal:
O eixo zero de
p1
ep2
é apenas a dimensão de "lote" deperm
, o que permite fazer muitas permutações em uma operação.A outra dimensão de
perm
, que corresponde aos índices, está alinhada ao longo do primeiro eixop1
e do segundo emp2
. Como os eixos são ortogonais, os arrays são transmitidos , basicamente como os arrays que você usoumeshgrid
- mas ainda têm a dimensão do lote.É o melhor que posso fazer no meu celular :) Posso tentar esclarecer mais tarde, se necessário, mas a ideia principal é a transmissão.
Comparação:
Um exemplo mais simples (sem dimensão de lote) de índices de transmissão:
No código da solução na parte superior, a transmissão está implícita. Não precisamos ligar
broadcast_arrays
porque isso acontece automaticamente durante a indexação.Você pode se livrar do
meshgrid
comIsso é 5x mais rápido no seu array de exemplo:
Eu diria que o loop for é praticamente irrelevante. Se você estiver preocupado com otimização adicional, especifique as formas com as quais está trabalhando...
Para aplicar permutações a dois eixos simultaneamente sem usar loops ou meshgrid, você pode usar indexação e transmissão avançadas. Aqui está uma abordagem mais eficiente:
Essa abordagem é mais eficiente e evita loops explícitos e meshgrid .