2016-09-27 12 views
0

これは私が以前に尋ねた問題と同様の問題だと思いますが、わかりません。これらの2行のコードをforループなしで1行に変換するにはどうすればよいですか?Pythonコードからforループを削除しようとしたときに、ルックアップテーブルで行列を操作する

for i in xrange(X.shape[0]): 
    dW[:,y[i]] -= X[i] 

英語では、行列Xの各行は、ベクトルyによって与えられる行列dWの対応する列から減算される必要があります。

dWはDXCであり、XはNXDなので、Xの転置はWと同じ形ではありません。そうでなければ、Xの行を並べ替えて転置を直接行うことができます。ただし、dWの列は、減算する必要がある複数の対応する行を持つことができます。

私は、Pythonのインデックス作成がどのように機能するのかをしっかりと把握していないようで、不要なfor-loopsを取り除くことや、for-loopsを削除することができないことさえ知りません。

+0

Pythonでの索引付けは1つのことです。 NumPyのインデックス作成は別のものです。 Python + NumPyコンボは強力なツールですが、まったく新しい言語に似ています。 –

答えて

1

アプローチ#1はここ​​を使用してmatrix-multiplicationとワンライナーベクトル化のアプローチだとNumPy broadcasting -

dWout -= (np.arange(dW.shape[1])[:,None] == y).dot(X).T 

説明:何が起こっているか理解するために、小さな例を見てみましょう -

入力を:

In [259]: X 
Out[259]: 
array([[ 0.80195208, 0.40566743, 0.62585574, 0.53571781], 
     [ 0.56643339, 0.4635662 , 0.4290103 , 0.14457036], 
     [ 0.31823491, 0.12329964, 0.41682841, 0.09544716]]) 

In [260]: y 
Out[260]: array([1, 2, 2]) 

まず、dWの第2軸の長さに渡ってyインデックスの2Dマスクを作成します。

dW4 x 5の形状の配列とする。だから、マスクは次のようになります。これは2Dマスクを作成するためにここにNumPy broadcastingを使用している

In [261]: mask = (np.arange(dW.shape[1])[:,None] == y) 

In [262]: mask 
Out[262]: 
array([[False, False, False], 
     [ True, False, False], 
     [False, True, True], 
     [False, False, False], 
     [False, False, False]], dtype=bool) 

。アップ

次に、我々は和集合体には、同じインデックスをyからマトリックス乗算を使用 -

In [264]: mask.dot(X) 
Out[264]: 
array([[ 0.  , 0.  , 0.  , 0.  ], 
     [ 0.80195208, 0.40566743, 0.62585574, 0.53571781], 
     [ 0.8846683 , 0.58686584, 0.84583872, 0.24001752], 
     [ 0.  , 0.  , 0.  , 0.  ], 
     [ 0.  , 0.  , 0.  , 0.  ]]) 

したがって、第二および第三列でTrue値を持つマスクの第3行に対応する、我々 2番目と3番目の行をXからその行列乗算で合計します。これは、乗算出力の第3行として配置される。

元のループコードでは、列全体でdWを更新しているので、乗算結果を転置して更新する必要があります。


アプローチ#2ここでワンライナーがnp.add.reduceat使用していないが、別のベクトル化の方法だ - ベクトル化する簡単な方法は次のようになり

sidx = y.argsort() 
unq,shift_idx = np.unique(y[sidx],return_index=True) 
dWout[:,unq] -= np.add.reduceat(X[sidx],shift_idx,axis=0).T 
+0

アプローチ1の仕組みを説明できますか?特に、私は "== y"部分が行列を返す理由を理解していません。 – resistancefm

+0

@resistancefm説明を追加しました。それが役立つかどうかを見てください。 – Divakar

1

を:、

dW[:,y] -= X.T 

除き、それほど明白ではないが、文書化されているにもかかわらず、これは繰り返しインデックスに問題が生じる可能性がある。y。これらの状況には、ufunc.atメソッドがあります(numpyの要素単位操作は "ufuncの"または "汎用関数"として実装されています)。引用the docsから:

ufunc.at(指数、B =なし)オペランドに代え動作におけるバッファなし

実行「」「指数」によって指定された要素のために。 ufuncを追加する場合、このメソッドは[indexes] + = bと同等ですが、複数回インデックスされた要素に対して結果が累積される点が異なります。たとえば、[[0,0]] + = 1はバッファリングのために最初の要素を1回だけインクリメントしますが、add.at(a、[0,0]、1)は最初の要素を2回インクリメントします。だからあなたの場合

np.subtract.at(dW.T, y, X) 

は残念ながら、ufunc.atは限りベクトル化技術が行くように比較的非効率的であるので、ループに比べてスピードアップが印象的なことではないかもしれません。

+0

ああラブリー。私は 'np.ufunc.at 'も試していましたが、その転置がありませんでした。ニース! – Divakar