J'essaie de multiplier chacun des termes d'un tableau 2D par les termes correspondants d'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 de 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 un moyen élégant de le faire avec numpy? Merci beaucoup, Alex
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 aussi transposer deux fois:
>>> (m.T * c).T
array([[ 0, 0, 0],
[ 4, 5, 6],
[14, 16, 18]])
J'ai comparé les différentes options de vitesse et constaté qu'à ma grande surprise, toutes les options (à l'exception de diag
) sont toutes aussi rapides. J'utilise personnellement
A * b[:, None]
(ou (A.T * b).T
) parce que c'est court.
Code pour reproduire l'intrigue:
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)",
)
Encore une astuce (à partir de 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 me débrouille toujours dans ce nouvel outil einsum
. J'ai 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
en j
, np.einsum('ij,j->ij',A,b)
, produit la matrice que Alex ne veut pas. Et np.einsum('ji,j->ji',A,b)
effectue en effet la double transposition.
Vous pouvez également utiliser la multiplication de matrice (aussi appelé 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 plus élégant est probablement une question de goût.
Pour les âmes perdues sur Google, utilisez numpy.expand_dims
puis numpy.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]])