kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Numpy の dot() 関数は引数によって「ドット積(内積)」や「行列積」の計算になる

Numpydot() 関数を使うと配列同士の「ドット積(内積)」を計算できる.詳しくはドキュメントに載っているけど,dot() 関数は引数 ab に指定する値(1次元配列/2次元配列)によって挙動が異なる.個人的にわかりにくかったため,具体的に実装しながら整理することにした.またドキュメントには dot() 関数以外を使うべきシナリオもあり代替案も載っている.

numpy.org

1. ドット積(内積)🔡

まず,ab のどちらにも「1次元配列(ベクトル)」を指定すると,ベクトルの「ドット積(内積)」を計算できる.ドキュメントには以下のように載っている.

If both a and b are 1-D arrays, it is inner product of vectors (without complex conjugation).

なお,そもそも「ドット積(内積)」とはザッと表現するなら以下のような計算式になり,各ベクトルの要素を掛け算した総和となる.詳しくは Cognicull などの参考サイトを見てもらえればと!


  \sum\limits_{i=1}^n a_i b_i \

さっそく 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

f:id:kakku22:20210531092812p:plain

なお,以下のように要素数(ベクトルの次元数)が異なるとエラーになる.

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)

f:id:kakku22:20210531092837p:plain

2. 行列積 🔡

次に ab のどちらにも「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 などの参考サイトに載っている「行列積」の図解を見てもらえればと!


  \begin{pmatrix}
    a & b \\
    c & d
  \end{pmatrix}
  \begin{pmatrix}
    e & f \\
    g & h
  \end{pmatrix}
  =
  \begin{pmatrix}
    ae + bg & af + bh \\
    ce + dg & cf + dh
  \end{pmatrix}

さっそく 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]])

f:id:kakku22:20210531092950p:plain

なお,以下の (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)

f:id:kakku22:20210531093115p:plain

まとめ 🔡

Numpydot() 関数の挙動を整理するために試した.引数 ab に指定する値(1次元配列/2次元配列)によって「ドット積(内積)」「行列積」の計算になることを確認できた(正確には他の計算パターンもある).またドキュメントには dot() 関数以外を使うべきシナリオもあり代替案も載っているため,特に「行列積」の場合は matmul() 関数や Numpy@ 演算子を使うことを覚えておこう!

numpy.org

関連記事

kakakakakku.hatenablog.com

kakakakakku.hatenablog.com