Provavelmente, a maneira mais limpa é usar np.repeat
:
a = np.array([[1, 2], [1, 2]])
print(a.shape)
# (2, 2)
# indexing with np.newaxis inserts a new 3rd dimension, which we then repeat the
# array along, (you can achieve the same effect by indexing with None, see below)
b = np.repeat(a[:, :, np.newaxis], 3, axis=2)
print(b.shape)
# (2, 2, 3)
print(b[:, :, 0])
# [[1 2]
# [1 2]]
print(b[:, :, 1])
# [[1 2]
# [1 2]]
print(b[:, :, 2])
# [[1 2]
# [1 2]]
Dito isso, muitas vezes você pode evitar a repetição de seus arrays completamente usando a transmissão . Por exemplo, digamos que eu queira adicionar um (3,)
vetor:
c = np.array([1, 2, 3])
a a
. Eu poderia copiar o conteúdo de a
3 vezes na terceira dimensão e, em seguida, copiar o conteúdo de c
duas vezes na primeira e na segunda dimensões, de forma que meus dois arrays fossem (2, 2, 3)
, então calcular sua soma. No entanto, é muito mais simples e rápido fazer isso:
d = a[..., None] + c[None, None, :]
Aqui, a[..., None]
tem forma (2, 2, 1)
e c[None, None, :]
tem forma (1, 1, 3)
*. Quando eu calculo a soma, o resultado é 'transmitido' ao longo das dimensões de tamanho 1, dando-me um resultado de forma (2, 2, 3)
:
print(d.shape)
# (2, 2, 3)
print(d[..., 0]) # a + c[0]
# [[2 3]
# [2 3]]
print(d[..., 1]) # a + c[1]
# [[3 4]
# [3 4]]
print(d[..., 2]) # a + c[2]
# [[4 5]
# [4 5]]
A transmissão é uma técnica muito poderosa porque evita a sobrecarga adicional envolvida na criação de cópias repetidas de seus arrays de entrada na memória.
* Embora eu os tenha incluído para maior clareza, os None
índices em c
não são realmente necessários - você também pode fazer a[..., None] + c
, ou seja, transmitir um (2, 2, 1)
array contra um (3,)
array. Isso ocorre porque, se um dos arrays tiver menos dimensões do que o outro, apenas as dimensões finais dos dois arrays precisam ser compatíveis. Para dar um exemplo mais complicado:
a = np.ones((6, 1, 4, 3, 1)) # 6 x 1 x 4 x 3 x 1
b = np.ones((5, 1, 3, 2)) # 5 x 1 x 3 x 2
result = a + b # 6 x 5 x 4 x 3 x 2
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)
.np.newaxis
é apenas um pseudônimo deNone
Outra forma é usar
numpy.dstack
. Supondo que você queira repetir osa
num_repeats
tempos da matriz :O truque é envolver a matriz
a
em uma lista de um único elemento e, em seguida, usar o*
operador para duplicar os elementos nesta listanum_repeats
vezes.Por exemplo, se:
Isso repete a matriz de
[1 2; 1 2]
5 vezes na terceira dimensão. Para verificar (em IPython):Ao final podemos ver que o formato da matriz é
2 x 2
, com 5 fatias na terceira dimensão.fonte
reshape
? Mais rápido? dá a mesma estrutura? É definitivamente mais puro.Use uma visualização e obtenha tempo de execução grátis! Estenda
n-dim
matrizes genéricas paran+1-dim
Introduzido no NumPy
1.10.0
, podemos alavancarnumpy.broadcast_to
para simplesmente gerar uma3D
visualização na2D
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 comn-dim
casos genéricos .Eu usaria a palavra
stack
no lugar decopy
, 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çãonp.broadcast_to
para criar a3D
visualização seria -Empilhar ao longo do terceiro / último eixo
Para empilhar a entrada
arr
ao longo do terceiro eixo, a solução para criar a3D
visualização seria -Se realmente precisarmos de uma cópia da memória, podemos sempre anexá
.copy()
-la. Portanto, as soluções seriam -Veja como funciona o empilhamento para os dois casos, mostrado com suas informações de forma para um caso de amostra -
A (s) mesma (s) solução (ões) funcionariam para estender uma
n-dim
entrada paran+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:
Caso de entrada 4D:
e assim por diante.
Horários
Vamos usar um grande
2D
caso de amostra e obter os tempos e verificar se a saída é aview
.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) -
Vamos ver os horários para mostrar que é virtualmente grátis -
Sendo uma vista, aumentando
N
de3
a3000
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!fonte
Edite @ Mr.F, para preservar a ordem das dimensões:
fonte
B.shape
impressões(N, 2, 2)
para qualquer valor deN
. Se você transporB
comB.T
, ele corresponde à saída esperada.B[0], B[1],...
, você terá a fatia certa, que vou argumentar e dizer que é mais fácil de digitar do que usarB[:,:,0], B[:,:,1]
, etc.B[:,:,i]
assim como é a que estou acostumada.Aqui está um exemplo de transmissão que faz exatamente o que foi solicitado.
Então
b*a
é o resultado desejado e(b*a)[:,:,0]
produzarray([[1, 2],[1, 2]])
, que é o originala
, como faz(b*a)[:,:,1]
, etc.fonte
Isso agora também pode ser obtido usando np.tile da seguinte maneira:
fonte