numpy配列で乗算する


89

2D配列の各用語に、1D配列の対応する用語を掛けようとしています。numpy.multiply関数に示されているように、すべての列に1D配列を乗算する場合、これは非常に簡単です。しかし、私は反対のことをしたいと思います。行の各項を乗算します。言い換えれば、私は乗算したい:

[1,2,3]   [0]
[4,5,6] * [1]
[7,8,9]   [2]

取得します

[0,0,0]
[4,5,6]
[14,16,18]

しかし、代わりに私は得る

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

numpyでそれを行うエレガントな方法があるかどうか誰かが知っていますか?どうもありがとう、アレックス


3
ああ、私は質問を提出したのと同じようにそれを理解しました。最初に正方行列を転置し、乗算してから、答えを転置します。
Alex S

行を列行列に転置する方がよいので、答えを再転置する必要はありません。新しい軸()を追加A * BA * B[...,None]て転置する必要がある場合。BNone
askewchan 2013

ありがとう、それは本当です。問題は、.transpose()または.Tを呼び出す1D配列が、それを列配列に変換せず、行として残す場合です。私が知る限り、それを列として定義する必要があります。すぐに。のようにx = [[1],[2],[3]]または何か。
Alex S

回答:


119

あなたが示したような通常の乗算​​:

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

軸を追加すると、希望どおりに乗算されます。

>>> m * c[:, np.newaxis]
array([[ 0,  0,  0],
       [ 4,  5,  6],
       [14, 16, 18]])

2回転置することもできます。

>>> (m.T * c).T
array([[ 0,  0,  0],
       [ 4,  5,  6],
       [14, 16, 18]])

新しい軸法を使用すると、2つの1D配列を乗算して2D配列を生成することができます。例えば[a,b] op [c,d] -> [[a*c, b*c], [a*d, b*d]]
kon psych 2015年

50

速度のさまざまなオプションを比較したところ、驚いたことに、すべてのオプション(を除くdiag)が同じように高速であることがわかりました。私は個人的に使用します

A * b[:, None]

(または(A.T * b).T)短いので。

ここに画像の説明を入力してください


プロットを再現するコード:

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)",
)

2
プロットのコードを提供するいい感じ。ありがとう。
rocksNwaves

17

行列乗算(別名ドット積)を使用することもできます。

a = [[1,2,3],[4,5,6],[7,8,9]]
b = [0,1,2]
c = numpy.diag(b)

numpy.dot(c,a)

どちらがよりエレガントかはおそらく好みの問題です。


2
いいね、+ 1、それは考えていなかった
jterrace 2013

10
dotここでは本当にやり過ぎです。あなただけの0に0・追加することにより、不必要な乗算をやっている
バイリコ

2
これは、dがnより大きいnxd行列にnx1ベクトルを乗算する場合にもメモリの問題を引き起こす可能性があります。
Jonasson 2017年

これは遅く、密行列を作成するときに大量のメモリ使用するため反対票を投じdiagます。
ニコシュレーマー2018年

16

さらに別のトリック(v1.6以降)

A=np.arange(1,10).reshape(3,3)
b=np.arange(3)

np.einsum('ij,i->ij',A,b)

私はnumpyブロードキャスト(newaxis)に習熟していますが、この新しいeinsumツールを回避する方法をまだ見つけています。だから私はこの解決策を見つけるために少し遊んでいました。

タイミング(Ipython timeitを使用):

einsum: 4.9 micro
transpose: 8.1 micro
newaxis: 8.35 micro
dot-diag: 10.5 micro

ちなみに、aiを、に変更するとjnp.einsum('ij,j->ij',A,b)Alexが望まないマトリックスが生成されます。そしてnp.einsum('ji,j->ji',A,b)、事実上、二重転置を行います。


1
少なくとも数ミリ秒かかるほど大きなアレイを備えたコンピューターでこれを計時し、関連するシステム情報とともに結果をここに投稿する場合は、大いに感謝します。
ダニエル

1
より大きな配列(100x100)では、相対数はほぼ同じです。 einsumm(25マイクロ)は他の2倍の速度です(dot-diagはさらに遅くなります)。これはnp1.7であり、「libatlas3gf-sse2」および「libatlas-base-dev」(Ubuntu 10.4、シングルプロセッサ)で新たにコンパイルされています。 timeit最高の10000ループを提供します。
hpaulj 2013

1
これは素晴らしい答えであり、受け入れられるべきだったと思います。ただし、上記のコードは、実際には、Alexが(私のマシンで)回避しようとしていたマトリックスを提供します。hpauljが間違っていると言ったのは、実際には正しいものです。
Yair Daon 2014年

ここではタイミングが誤解を招きます。dot-diagは、他の3つのオプションよりもはるかに悪く、einsumも他のオプションよりも高速ではありません。
ニコシュレーマー2018年

@NicoSchlömer、私の答えは5年近く前のもので、多くのnumpyバージョンが戻ってきました。
hpaulj

1

グーグルで失われた魂の場合、numpy.expand_dimsthennumpy.repeatを使用すると機能し、高次元の場合にも機能します(つまり、形状(10、12、3)に(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]])

-4

やってみませんか

>>> m = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> c = np.array([0,1,2])
>>> (m.T * c).T

??


6
その正確なアプローチは、受け入れられた回答にすでに示されていますが、これがどのように何かを追加するのかわかりません。
Baum mitAugen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.