2013-08-29 23 views
36

2次元配列の各項に1D配列の対応する項を掛けようとしています。 numpy.multiply関数に示すように、すべての列に1D配列を掛けたければ、これは非常に簡単です。しかし、私は逆のことをしたい、行の各用語を掛けてみたい。私が掛けたい言い換えれば :numpyのでそれを行うためのエレガントな方法があるかどうnumpyの配列を掛け合わせて

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

を取得誰もが知っていますか? どうもありがとう、 アレックス

+2

ああ私は質問を提出したのと同じように考え出した。最初に正方行列を転置し、乗算して、転置します。 –

+0

行を列の行列に転置する方がよい場合は、解を再転置する必要はありません。 'A * B'の場合、新しい軸(' None')を加えることによって 'B'を転置する' A * B [...、None] 'を行う必要があります。 – askewchan

+0

ありがとう、それは本当です。問題は、1D配列を.transpose()または.Tを呼び出すと列配列に変換されず、行として残るため、列として定義する必要があることがわかっている限りですバットからすぐに。 'x = [[1]、[2]、[3]]のようなものです。 –

答えて

49
あなたのような

通常の乗算​​を示した:

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

あなたはまた、二回移調できます。あなたは軸を追加した場合

>>> 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.T * c).T 
array([[ 0, 0, 0], 
     [ 4, 5, 6], 
     [14, 16, 18]]) 
+0

ありがとう、ちょうど私が探していたもの。 –

+0

新しい軸メソッドを使用すると、2つの1D配列を掛けて2次元配列を生成することができます。例えば、[a、b] op [c、d] - > [[a * c、b * c]、[a * d、b * d]] '。 –

15

行列乗算

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

numpy.dot(c,a) 

おそらく味の問題です。

+2

nice、+1、そのことを考えていなかった – jterrace

+8

'ドット'は本当に残酷です。あなたは0での不必要な乗算と0への加算だけを行っています。 –

+1

これは、nx1ベクトルをnxd行列に乗算したい場合にメモリの問題を引き起こす可能性があります。 – Jonasson

11

(バージョン1.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 

なお、ijnp.einsum('ij,j->ij',A,b)に、アレックスは望んでいないことを行列を生成する変更。そして、np.einsum('ji,j->ji',A,b)は、事実上、ダブルトランスポーズを行います。

+0

少なくとも数ミリ秒かかる結果を投稿するのに十分な大きさの配列を持つコンピュータでこれを実行する場合は、[ここ](http://stackoverflow.com/questions/18365073/why-is-numpys-einsum-faster- numpys-built-in-functions)と関連するシステム情報があればそれは非常に感謝しています。 – Daniel

+1

の配列が大きい(100x100)場合、相対数はほぼ同じです。 'einsumm'(25マイクロ)は他の2倍の速さです(ドット・ダイアグが遅くなります)。これは 'libatlas3gf-sse2'と 'libatlas-base-dev'(Ubuntu 10.4、シングルプロセッサ)で新しくコンパイルされたnp 1.7です。 'timeit'は10000ループの中で最良です。 – hpaulj

+1

これは素晴らしい答えです。私はそれが受け入れられているはずだと思います。しかし、上に書かれたコードは、実際には、アレックスが(私のマシン上で)回避しようとしていたマトリックスを与えています。 1つのhpauljが間違っていると言うのは、実際には正しいものです。 –

-2

あなただけ

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

をしないのはなぜ?

+2

その正確なアプローチはすでに受け入れられた回答に示されていますが、これがどのように追加されるかはわかりません。 –

5

私はスピードのためのさまざまなオプションを比較して、それを見つけた - ずっと私の驚きに - (小さなnと大nためdiageinsum除く)すべてのオプションが同等に高速である:

enter image description here


プロットを再現する

コード:

import numpy 
import perfplot 


def newaxis(data): 
    A, b = data 
    return A * b[:, numpy.newaxis] 


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.show(
    setup=lambda n: (numpy.random.rand(n, n), numpy.random.rand(n)), 
    kernels=[ 
     newaxis, double_transpose, double_transpose_contiguous, diag_dot, 
     einsum 
     ], 
    n_range=[2**k for k in range(10)], 
    logx=True, 
    logy=True, 
    xlabel='len(A), len(b)' 
    ) 
関連する問題