唯物是真 @Scaled_Wurm

プログラミング(主にPython2.7)とか機械学習とか

NumPyのブロードキャストのメモ

Pythonの行列演算ライブラリのNumPyはforループを使って計算すると遅いので、できるだけ行列演算やベクトル演算だけで計算を行いたい

NumPyでは大きさの違うarray同士で計算するときのブロードキャストという仕組みがあります
これを使うと複雑な計算が簡単なコードで計算できたりします

余談ですが、Rを使ったことがある人はベクトルの長さが足りない場合に定数倍で長さが合う場合は、定数倍にして長さを合わせて計算を行う的な処理があったのを覚えているかもしれません
ブロードキャストはそれに似たような処理で、NumPyの場合は各次元の大きさが等しいか、あるいは片方の大きさが1の場合に計算ができます(次元数が少ない場合には先頭から大きさ1として次元を拡張する)

大きさが1の場合にどのようになるかというと、相手の大きさに合わせてコピーして拡大したものと計算したときの結果が得られます

以下の例だとベクトルと1個の要素を足していて、相手のほうが長いのでその分伸びたかのように計算されます

import numpy as np
np.array([1, 2]) + 1

f:id:sucrose:20141214233905j:plain:w300

これは二次元以上になっても同じです

import numpy as np
np.array([[1, 2], [3, 4]]) + 1
np.array([[1, 2], [3, 4]]) + np.array([5, 6])

f:id:sucrose:20141214234048j:plain:w300f:id:sucrose:20141214234139j:plain:w300

これだけでも定数を全体に足したりかけたりするのに使えますが、もっと便利な使い方があります
ベクトルのそれぞれの要素の差や、複数のベクトルのそれぞれのペアの間のユークリッド距離の計算などができます

ベクトルのそれぞれの要素の差を計算する場合には同じベクトルを縦向きと横向きにして計算すればよいです

import numpy as np
data = np.array([1, 2])
data[:, np.newaxis] - data

f:id:sucrose:20141214234329j:plain:w300
他にも直積(outer product)を計算するのにも使えます(numpy.outerがありますが)

import numpy as np
data = np.array([1, 2])
data[:, np.newaxis] * data

同様に複数のベクトルのそれぞれのペアの間のユークリッド距離を計算してみます
3次元以上になるとわかりづらいので、それぞれの計算での行列の次元の大きさがあっているか確認しながらやったほうがよいと思います

import numpy as np
data = np.array([[1, 2], [3, 5], [6, 9]])
np.sqrt(((data[:, np.newaxis] - data)**2).sum(axis=2))

参考

ブロードキャストのより詳細な説明や使用例はこの資料(次のページ以降を含む)がわかりやすいと思います

数式をNumPyの行列演算にする話