Numpy で dot()
関数を使うと配列同士の「ドット積(内積)」を計算できる.詳しくはドキュメントに載っているけど,dot()
関数は引数 a
と b
に指定する値(1次元配列/2次元配列)によって挙動が異なる.個人的にわかりにくかったため,具体的に実装しながら整理することにした.またドキュメントには dot()
関数以外を使うべきシナリオもあり代替案も載っている.
1. ドット積(内積)🔡
まず,a
と b
のどちらにも「1次元配列(ベクトル)」を指定すると,ベクトルの「ドット積(内積)」を計算できる.ドキュメントには以下のように載っている.
If both a and b are 1-D arrays, it is inner product of vectors (without complex conjugation).
なお,そもそも「ドット積(内積)」とはザッと表現するなら以下のような計算式になり,各ベクトルの要素を掛け算した総和となる.詳しくは Cognicull などの参考サイトを見てもらえればと!
さっそく dot()
関数を試す.以下のように「1次元配列」と「1次元配列」を指定すると,期待通りに「ドット積(内積)」を計算できる.それぞれ (1x3) + (2x4) = 11
と (1x4) + (2x5) + (3x6) = 32
となる.
a = np.array([1, 2]) b = np.array([3, 4]) np.dot(a, b) # 11 a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) np.dot(a, b) # 32
なお,以下のように要素数(ベクトルの次元数)が異なるとエラーになる.
a = np.array([1, 2, 3]) b = np.array([4, 5, 6, 7]) np.dot(a, b) # ValueError: shapes (3,) and (4,) not aligned: 3 (dim 0) != 4 (dim 0)
2. 行列積 🔡
次に a
と b
のどちらにも「2次元配列(行列)」を指定すると「ドット積(内積)」ではなく「行列積」を計算できる.ドキュメントには以下のように載っている.そして「行列積」を計算するなら dot()
関数よりも matmul()
関数や Numpy の @
演算子を使うべし!とも載っている.
If both a and b are 2-D arrays, it is matrix multiplication, but using matmul or a @ b is preferred.
「行列積」とはザッと表現するなら以下のような計算式になり,行列同士を掛け算した結果となる.詳しくは Cognicull などの参考サイトに載っている「行列積」の図解を見てもらえればと!
さっそく dot()
関数と matmul()
関数と @
演算子 を試す.以下のように「2次元配列」と「2次元配列」を指定すると,期待通りに「行列積」を計算できる.以下には (2, 2) x (2, 2)
と (3, 3) x (3, 3)
の例を載せた.また列数(横)と行数(縦)が一致していれば「行列積」を計算できるため (3, 2) x (2, 2)
の例も載せた.そして mutmul()
関数や @
演算子を使っても同じ結果になっている.
a = np.array([[1, 2], [3, 4]]) b = np.array([[5, 6], [7, 8]]) np.dot(a, b) # array([[19, 22], # [43, 50]]) np.matmul(a, b) # array([[19, 22], # [43, 50]]) a@b # array([[19, 22], # [43, 50]]) a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) b = np.array([[10, 11, 12], [13, 14, 15], [16, 17, 18]]) np.dot(a, b) # array([[ 84, 90, 96], # [201, 216, 231], # [318, 342, 366]]) np.matmul(a, b) # array([[ 84, 90, 96], # [201, 216, 231], # [318, 342, 366]]) a@b # array([[ 84, 90, 96], # [201, 216, 231], # [318, 342, 366]]) a = np.array([[1, 2], [3, 4], [5, 6]]) b = np.array([[7, 8], [9, 10]]) np.dot(a, b) # array([[ 25, 28], # [ 57, 64], # [ 89, 100]]) np.matmul(a, b) # array([[ 25, 28], # [ 57, 64], # [ 89, 100]]) a@b # array([[ 25, 28], # [ 57, 64], # [ 89, 100]])
なお,以下の (2, 3) x (2, 2)
のように,列数(横)と行数(縦)が一致していない場合はエラーになる.
a = np.array([[1, 2, 3], [4, 5, 6]]) b = np.array([[7, 8], [9, 10]]) np.dot(a, b) # ValueError: shapes (2,3) and (2,2) not aligned: 3 (dim 1) != 2 (dim 0) np.matmul(a, b) # ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 2 is different from 3) a@b # ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 2 is different from 3)
まとめ 🔡
Numpy の dot()
関数の挙動を整理するために試した.引数 a
と b
に指定する値(1次元配列/2次元配列)によって「ドット積(内積)」や「行列積」の計算になることを確認できた(正確には他の計算パターンもある).またドキュメントには dot()
関数以外を使うべきシナリオもあり代替案も載っているため,特に「行列積」の場合は matmul()
関数や Numpy の @
演算子を使うことを覚えておこう!