Use uma visualização e obtenha tempo de execução grátis! Estenda n-dim
matrizes genéricas paran+1-dim
Introduzido no NumPy1.10.0
, podemos alavancar numpy.broadcast_to
para simplesmente gerar uma 3D
visualização na 2D
matriz de entrada. O benefício seria sem sobrecarga de memória extra e tempo de execução virtualmente livre. Isso seria essencial nos casos em que os arrays são grandes e podemos trabalhar com visualizações. Além disso, isso funcionaria com n-dim
casos genéricos .
Eu usaria a palavra stack
no lugar de copy
, pois os leitores podem confundi-la com a cópia de matrizes que cria cópias de memória.
Empilhar ao longo do primeiro eixo
Se quisermos empilhar a entrada arr
ao longo do primeiro eixo, a solução np.broadcast_to
para criar a 3D
visualização seria -
np.broadcast_to(arr,(3,)+arr.shape) # N = 3 here
Empilhar ao longo do terceiro / último eixo
Para empilhar a entrada arr
ao longo do terceiro eixo, a solução para criar a 3D
visualização seria -
np.broadcast_to(arr[...,None],arr.shape+(3,))
Se realmente precisarmos de uma cópia da memória, podemos sempre anexá .copy()
-la. Portanto, as soluções seriam -
np.broadcast_to(arr,(3,)+arr.shape).copy()
np.broadcast_to(arr[...,None],arr.shape+(3,)).copy()
Veja como funciona o empilhamento para os dois casos, mostrado com suas informações de forma para um caso de amostra -
# Create a sample input array of shape (4,5)
In [55]: arr = np.random.rand(4,5)
# Stack along first axis
In [56]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[56]: (3, 4, 5)
# Stack along third axis
In [57]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[57]: (4, 5, 3)
A (s) mesma (s) solução (ões) funcionariam para estender uma n-dim
entrada para n+1-dim
visualizar a saída ao longo do primeiro e do último eixo. Vamos explorar alguns casos de maior dim -
Caso de entrada 3D:
In [58]: arr = np.random.rand(4,5,6)
# Stack along first axis
In [59]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[59]: (3, 4, 5, 6)
# Stack along last axis
In [60]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[60]: (4, 5, 6, 3)
Caso de entrada 4D:
In [61]: arr = np.random.rand(4,5,6,7)
# Stack along first axis
In [62]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[62]: (3, 4, 5, 6, 7)
# Stack along last axis
In [63]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[63]: (4, 5, 6, 7, 3)
e assim por diante.
Horários
Vamos usar um grande 2D
caso de amostra e obter os tempos e verificar se a saída é a view
.
# Sample input array
In [19]: arr = np.random.rand(1000,1000)
Vamos provar que a solução proposta é de fato uma visão. Usaremos empilhamento ao longo do primeiro eixo (os resultados seriam muito semelhantes para empilhamento ao longo do terceiro eixo) -
In [22]: np.shares_memory(arr, np.broadcast_to(arr,(3,)+arr.shape))
Out[22]: True
Vamos ver os horários para mostrar que é virtualmente grátis -
In [20]: %timeit np.broadcast_to(arr,(3,)+arr.shape)
100000 loops, best of 3: 3.56 µs per loop
In [21]: %timeit np.broadcast_to(arr,(3000,)+arr.shape)
100000 loops, best of 3: 3.51 µs per loop
Sendo uma vista, aumentando N
de 3
a 3000
não mudou nada nas temporizações e ambos são insignificantes nas unidades de temporização. Conseqüentemente, eficiente tanto em memória quanto em desempenho!
b[:,:,0]
,b[:,:,1]
eb[:,:,2]
. Cada fatia da terceira dimensão é uma cópia da matriz 2D original. Isso não é tão óbvio apenas olhandoprint(b)
.