122 votes

Multiplier à travers dans un tableau numpy

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 le montre l'exemple ci-dessous. numpy.multiply fonction. Mais je veux faire l'inverse, multiplier chaque terme de la ligne. 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, j'obtiens

[0,2,6]
[0,5,12]
[0,8,18]

Quelqu'un sait-il s'il existe un moyen élégant de faire cela avec numpy ? Merci beaucoup, Alex

151voto

jterrace Points 21939

Une 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]])

80voto

Nico Points 893

J'ai comparé les différentes options de vitesse et j'ai constaté, à ma grande surprise, que toutes les options (à l'exception de l'option diag ) sont tout aussi rapides. J'utilise personnellement

A * b[:, None]

(ou (A.T * b).T ) parce que c'est court.

enter image description here


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(13)],
    xlabel="len(A), len(b)",
)

18voto

James K Points 2794

Vous pouvez également utiliser la multiplication matricielle (alias 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.

17voto

hpaulj Points 6132

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 suis compétent avec la diffusion de numpy ( newaxis ), mais je suis toujours en train de trouver mon chemin dans cette nouvelle einsum outil. J'ai donc dû jouer 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

Par ailleurs, la modification d'un i a j , np.einsum('ij,j->ij',A,b) produit la matrice qu'Alex ne veut pas. Et np.einsum('ji,j->ji',A,b) fait, en effet, la double transposition.

1voto

Pour les âmes perdues sur google, en utilisant 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 une (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]])

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X