J'essaie de multiplier chacun des termes dans un tableau 2D par les termes correspondants dans un tableau 1D. C'est très facile si je veux multiplier chaque colonne par le tableau 1D, comme indiqué dans la fonction numpy.multiply . Mais je veux faire le contraire, multiplier chaque terme dans la rangée. En d'autres termes, je veux multiplier:
[1,2,3] [0]
[4,5,6] * [1]
[7,8,9] [2]
et obtenir
[0,0,0]
[4,5,6]
[14,16,18]
mais à la place je reçois
[0,2,6]
[0,5,12]
[0,8,18]
Est-ce que quelqu'un sait s'il existe une façon élégante de le faire avec numpy? Merci beaucoup, Alex
A * B
vous deviez faireA * B[...,None]
ce qui transposeB
en ajoutant un nouvel axe (None
).x = [[1],[2],[3]]
ou quelque chose.Réponses:
Multiplication normale comme vous l'avez montré:
>>> 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]])
Si vous ajoutez un axe, il se multipliera comme vous le souhaitez:
>>> m * c[:, np.newaxis] array([[ 0, 0, 0], [ 4, 5, 6], [14, 16, 18]])
Vous pouvez également transposer deux fois:
>>> (m.T * c).T array([[ 0, 0, 0], [ 4, 5, 6], [14, 16, 18]])
la source
[a,b] op [c,d] -> [[a*c, b*c], [a*d, b*d]]
.J'ai comparé les différentes options pour la vitesse et j'ai constaté que - à ma grande surprise - toutes les options (sauf
diag
) sont également rapides. J'utilise personnellementA * b[:, None]
(ou
(A.T * b).T
) parce que c'est court.Code pour reproduire le tracé:
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)", )
la source
Vous pouvez également utiliser la multiplication matricielle (aka produit scalaire):
a = [[1,2,3],[4,5,6],[7,8,9]] b = [0,1,2] c = numpy.diag(b) numpy.dot(c,a)
Ce qui est le plus élégant est probablement une question de goût.
la source
dot
est vraiment exagéré ici. Vous faites juste des multiplications inutiles par 0 et des ajouts à 0.diag
matrice dense .Encore une autre astuce (à partir de la v1.6)
A=np.arange(1,10).reshape(3,3) b=np.arange(3) np.einsum('ij,i->ij',A,b)
Je maîtrise la diffusion numpy (
newaxis
), mais je trouve toujours mon chemin dans ce nouveleinsum
outil. J'avais donc joué un peu pour trouver cette solution.Timings (en utilisant Ipython timeit):
einsum: 4.9 micro transpose: 8.1 micro newaxis: 8.35 micro dot-diag: 10.5 micro
Incidemment, changer un
i
enj
,np.einsum('ij,j->ij',A,b)
produit la matrice dont Alex ne veut pas. Etnp.einsum('ji,j->ji',A,b)
fait, en effet, la double transposition.la source
einsumm
(25 micro) est deux fois plus rapide que les autres (dot-diag ralentit davantage). Il s'agit de np 1.7, fraîchement compilé avec 'libatlas3gf-sse2' et 'libatlas-base-dev' (Ubuntu 10.4, processeur unique).timeit
donne le meilleur de 10000 boucles.numpy
versions sont en arrière.Pour ces âmes perdues sur google, utiliser
numpy.expand_dims
thennumpy.repeat
fonctionnera, et fonctionnera également dans les cas de dimension supérieure (c'est-à-dire en multipliant une forme (10, 12, 3) par un (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]])
la source
Pourquoi tu ne fais pas juste
>>> m = np.array([[1,2,3],[4,5,6],[7,8,9]]) >>> c = np.array([0,1,2]) >>> (m.T * c).T
??
la source