Estou tentando multiplicar cada um dos termos em uma matriz 2D pelos termos correspondentes em uma matriz 1D. Isso é muito fácil se eu quiser multiplicar todas as colunas pelo array 1D, conforme mostrado na função numpy.multiply . Mas eu quero fazer o oposto, multiplicar cada termo na linha. Em outras palavras, quero multiplicar:
[1,2,3] [0]
[4,5,6] * [1]
[7,8,9] [2]
e pegue
[0,0,0]
[4,5,6]
[14,16,18]
mas ao invés eu recebo
[0,2,6]
[0,5,12]
[0,8,18]
Alguém sabe se existe uma maneira elegante de fazer isso com o numpy? Muito obrigado Alex
A * B
você tiver que fazerA * B[...,None]
qual transpõeB
, adicione um novo eixo (None
).x = [[1],[2],[3]]
ou algo assim.Respostas:
Multiplicação normal como você mostrou:
>>> import numpy as np >>> m = np.array([[1,2,3],[4,5,6],[7,8,9]]) >>> c = np.array([0,1,2]) >>> m * c array([[ 0, 2, 6], [ 0, 5, 12], [ 0, 8, 18]])
Se você adicionar um eixo, ele se multiplicará da maneira que você deseja:
>>> m * c[:, np.newaxis] array([[ 0, 0, 0], [ 4, 5, 6], [14, 16, 18]])
Você também pode transpor duas vezes:
>>> (m.T * c).T array([[ 0, 0, 0], [ 4, 5, 6], [14, 16, 18]])
fonte
[a,b] op [c,d] -> [[a*c, b*c], [a*d, b*d]]
.Eu comparei as diferentes opções de velocidade e descobri que - para minha surpresa - todas as opções (exceto
diag
) são igualmente rápidas. Eu pessoalmente usoA * b[:, None]
(ou
(A.T * b).T
) porque é curto.Código para reproduzir o gráfico:
import numpy import perfplot def newaxis(data): A, b = data return A * b[:, numpy.newaxis] def none(data): A, b = data return A * b[:, None] def double_transpose(data): A, b = data return (A.T * b).T def double_transpose_contiguous(data): A, b = data return numpy.ascontiguousarray((A.T * b).T) def diag_dot(data): A, b = data return numpy.dot(numpy.diag(b), A) def einsum(data): A, b = data return numpy.einsum("ij,i->ij", A, b) perfplot.save( "p.png", setup=lambda n: (numpy.random.rand(n, n), numpy.random.rand(n)), kernels=[ newaxis, none, double_transpose, double_transpose_contiguous, diag_dot, einsum, ], n_range=[2 ** k for k in range(14)], logx=True, logy=True, xlabel="len(A), len(b)", )
fonte
Você também pode usar a multiplicação de matrizes (também conhecido como produto escalar):
a = [[1,2,3],[4,5,6],[7,8,9]] b = [0,1,2] c = numpy.diag(b) numpy.dot(c,a)
O que é mais elegante é provavelmente uma questão de gosto.
fonte
dot
é realmente um exagero aqui. Você está apenas fazendo multiplicação desnecessária por 0 e adições a 0.diag
matriz densa .Mais um truque (a partir de v1.6)
A=np.arange(1,10).reshape(3,3) b=np.arange(3) np.einsum('ij,i->ij',A,b)
Eu sou proficiente com a transmissão entorpecida (
newaxis
), mas ainda estou encontrando meu caminho em torno dessa novaeinsum
ferramenta. Então, eu tentei um pouco para encontrar essa solução.Timings (usando Ipython timeit):
einsum: 4.9 micro transpose: 8.1 micro newaxis: 8.35 micro dot-diag: 10.5 micro
Aliás, a mudança de uma
i
paraj
,np.einsum('ij,j->ij',A,b)
produz a matriz que Alex não quer. Enp.einsum('ji,j->ji',A,b)
faz, com efeito, a dupla transposição.fonte
einsumm
(25 micro) é duas vezes mais rápido que os outros (o ponto-diag desacelera mais). Este é o np 1.7, compilado recentemente com 'libatlas3gf-sse2' e 'libatlas-base-dev' (Ubuntu 10.4, processador único).timeit
dá o melhor de 10.000 loops.numpy
versões anteriores.Para aquelas almas perdidas no google, usar
numpy.expand_dims
entãonumpy.repeat
funcionará, e também funcionará em casos de dimensões superiores (isto é, multiplicar uma forma (10, 12, 3) por a (10, 12)).>>> import numpy >>> a = numpy.array([[1,2,3],[4,5,6],[7,8,9]]) >>> b = numpy.array([0,1,2]) >>> b0 = numpy.expand_dims(b, axis = 0) >>> b0 = numpy.repeat(b0, a.shape[0], axis = 0) >>> b1 = numpy.expand_dims(b, axis = 1) >>> b1 = numpy.repeat(b1, a.shape[1], axis = 1) >>> a*b0 array([[ 0, 2, 6], [ 0, 5, 12], [ 0, 8, 18]]) >>> a*b1 array([[ 0, 0, 0], [ 4, 5, 6], [14, 16, 18]])
fonte
Por que você apenas não faz
>>> m = np.array([[1,2,3],[4,5,6],[7,8,9]]) >>> c = np.array([0,1,2]) >>> (m.T * c).T
??
fonte