ベクトルの内積
ベクトルの 内積 (inner product) は要素同士の積の総和として定義されます。
\[\boldsymbol{v}\cdot\boldsymbol{w}
=\begin{bmatrix}v_1\\v_2\\\vdots\\v_n\end{bmatrix}
\cdot\begin{bmatrix}w_1\\w_2\\\vdots\\w_n\end{bmatrix}
=v_1\cdot w_1+v_2 \cdot w_2+\ \cdots\ +v_n\cdot w_n\tag{1}\]
たとえば、$\boldsymbol{v}=\begin{bmatrix}2\\3\end{bmatrix}$ と $\boldsymbol{w}=\begin{bmatrix}5\\1\end{bmatrix}$ の内積は
\[\boldsymbol{v}\cdot\boldsymbol{w}
=\begin{bmatrix}2\\3\end{bmatrix}
\cdot\begin{bmatrix}5\\1\end{bmatrix}=2\times 5+3\times 1=13\]
のように計算できます。ベクトル $\boldsymbol{v}$ の自身との内積、すなわち $\boldsymbol{v}\cdot\boldsymbol{v}$ は $\parallel\boldsymbol{v}\parallel^2$ です。
\[\boldsymbol{v}\cdot\boldsymbol{v}=v_1^2+v_2^2+\ \cdots\ +v_n^2=\parallel\boldsymbol{v}\parallel^2\]
すなわち、ベクトル $\boldsymbol{v}$ の大きさ(ユークリッドノルム)は内積を使って
\[\parallel\boldsymbol{v}\parallel=\sqrt{\boldsymbol{v}\cdot\boldsymbol{v}}\tag{2}\]
のように表すことができます。
内積演算においては、交換法則、結合法則、分配法則が成り立ちます。
\[\begin{align*}
&\boldsymbol{v}\cdot\boldsymbol{w}=\boldsymbol{w}\cdot\boldsymbol{v}\tag{3}\\[6pt]
&c(\boldsymbol{v}\cdot\boldsymbol{w})=(c\boldsymbol{v})\cdot\boldsymbol{w}\tag{4}\\[6pt]
&(\boldsymbol{u}+\boldsymbol{v})\cdot\boldsymbol{w}
=\boldsymbol{u}\cdot\boldsymbol{w}+\boldsymbol{v}\cdot\boldsymbol{w}\tag{5}\end{align*}\]
線型代数では $(\boldsymbol{v}+\boldsymbol{w})^2$ を展開する機会が多いですが、これは (3) と (5) を用いて次のように計算できます。
\[\begin{align*}(\boldsymbol{v}+\boldsymbol{w})^2
&=(\boldsymbol{v}+\boldsymbol{w})\cdot(\boldsymbol{v}+\boldsymbol{w})\\[6pt]
&=(\boldsymbol{v}+\boldsymbol{w})\cdot\boldsymbol{v}
+(\boldsymbol{v}+\boldsymbol{w})\cdot\boldsymbol{w}\\[6pt]
&=\boldsymbol{v}\cdot\boldsymbol{v}+\boldsymbol{w}\cdot\boldsymbol{v}+\boldsymbol{v}\cdot\boldsymbol{w}
+\boldsymbol{w}\cdot\boldsymbol{w}\\[6pt]
&=\parallel\boldsymbol{v}\parallel^2+2\boldsymbol{v}\cdot\boldsymbol{w}+\parallel\boldsymbol{w}\parallel^2\end{align*}\]
もう少し先の記事で行列について学ぶことになりますが、ベクトル $\boldsymbol{v},\ \boldsymbol{w}$ を $1$ 列の行列と考えて、内積を $\boldsymbol{v}^T\boldsymbol{w}$ と表記することもできます。$\boldsymbol{v}^T$ は $\boldsymbol{v}$ を転置して要素を横に並べた行ベクトルです。
\[\boldsymbol{v}^T
=\begin{bmatrix}v_1&v_2&...&v_n\end{bmatrix}\]
行列表記と整合性がとれるので、講座の後半では行ベクトルによる表記が増えると思います。行ベクトルを $\boldsymbol{v}=(v_1,\ v_2,\ ...)$ と混同しないように注意してください。$()$ で括ってカンマで区切るベクトルは、普段使っている列ベクトルを便宜上横書きにしているだけです。
numpy.dot()
NumPy でベクトルの内積を計算する場合、普通は numpy.dot() 関数 、もしくは配列 (ndarrayオブジェクト) に備わっている dot()メソッドを使います。numpy.dot(a, b) は一般に行列積を計算する関数ですが、a, b に 1 次元配列(ベクトル)をわたせば内積を返します (1 列の行列同士の積はベクトルの内積と同じです)。
# SLA_005-1
# numpy.dot() による内積の計算
import numpy as np
# ベクトルv=[3 2 6]
v = np.array([3, 2, 6])
# ベクトルw=[4 7 2]
w = np.array([4, 7, 2])
# vとwの内積を計算
v_dot_w = np.dot(v, w)
print("v・w = {}".format(v_dot_w))
v・w = 38
# SLA_005-2
# ndarray.dot()による内積の計算
# ベクトルv=[3 2 6]
v = np.array([3, 2, 6])
# ベクトルw=[4 7 2]
w = np.array([4, 7, 2])
# vとwの内積を計算
v_dot_w = v.dot(w)
print("v・w = {}".format(v_dot_w))
v・w = 38
numpy.vdot()
numpy.vdot(a, b) にベクトル (1 次元配列) を渡して内積を計算することができます。
# SLA_006-1
# numpy.vdot()による内積の計算
import numpy as np
# ベクトルv=[7+2i 3+i]
v = np.array([7 + 2j, 3 + 1j])
# ベクトルw=[4+5i 8]
w = np.array([4 + 5j, 8])
# vとwの内積を計算
v_dot_w = np.dot(v, w)
print("v・w = {}".format(v_dot_w))
v・w = (42+51j)
numpy.vdot() の引数 a, b に 2 次元以上の配列を渡すと、1 次元配列に平坦化してから内積を計算します(テンソル複内積)。
# SLA_006-2
# numpy.vdot()による内積の計算
# 行列a
a = np.array([[1, 4],
[3, 5]])
# 行列b
b = np.array([[3, 7],
[4, 9]])
# 1*3+4*7+3*4+5*9
a_vdot_b = np.vdot(a, b)
print("a・b = {}".format(a_vdot_b))
a・b = 88
numpy.inner()
numpy.inner(a, b) にベクトル (1 次元配列) を渡して内積を計算することができます。
# SLA_007
# numpy.inner()による内積の計算
import numpy as np
# ベクトルv=[2 5 0]
v = np.array([2, 5, 0])
# ベクトルw=[3 1 4]
w = np.array([3, 1, 4])
# vとwの内積を計算
v_dot_w = np.inner(v, w)
print("v・w = {}".format(v_dot_w))
v・w = 11
引数 a, b に行列を渡すと、a と b.T の行列積を返します (b.T は b の転置行列)。すなわち、np.dot(a, b.T) と同じ結果を返します。
中古価格 | ![]() |

内積の幾何学的意味
ベクトル $\boldsymbol{v}$ と $\boldsymbol{w}$ のなす角を $\theta$ とすると、二つのベクトルの内積は
\[\boldsymbol{v}\cdot\boldsymbol{w}=\parallel\boldsymbol{v}\parallel\parallel\boldsymbol{w}\parallel\cos\theta\tag{6}\]
と表されます。この定義は (1) と同値であり(余弦定理を使って証明できます)、幾何学的には下図のように $\boldsymbol{v}$ の射影と $\boldsymbol{w}$ の長さの積を意味します。
2 つのベクトルのなす角度が直角であるとき、射影がなくなるので内積は $0$ になることがわかります(下図)。
たとえば、$\begin{bmatrix}1\\0\end{bmatrix}$ と $\begin{bmatrix}0\\1\end{bmatrix}$ は互いに直交するので内積は $0$ です。
また、式 (6) より、ベクトル $\boldsymbol{v}$ と $\boldsymbol{w}$ の間の角度の余弦 (cosine) は
\[\cos\theta=\frac{\boldsymbol{v}\cdot\boldsymbol{w}}{\parallel\boldsymbol{w}\parallel\parallel\boldsymbol{v}\parallel}\tag{7}\]
となるので、$\cos$ の逆関数 $\mathrm{Arccos}$ を使うと、
\[\theta=\mathrm{Arccos}\left(\frac{\boldsymbol{v}\cdot\boldsymbol{w}}{\parallel\boldsymbol{v}\parallel\parallel\boldsymbol{w}\parallel}\right)\tag{8}\]
によって角度を計算できます。4 次元以上のベクトルのなす角度も(想像するのは難しいですが)、(2) で定義できます。Python で角度を求める関数を実装してみましょう。
# SLA_008-1
import numpy as np
# 2つのベクトルのなす角度を求める関数
def v_angle(v1, v2, deg = False):
# v1とv2の大きさ(ノルム)を計算
v1_n = np.linalg.norm(v1)
v2_n = np.linalg.norm(v2)
# v1とv2の内積を計算
v1_dot_v2 = np.dot(v1, v2)
# 角度の余弦を計算
cos_theta = v1_dot_v2 / (v1_n * v2_n)
# 逆三角関数を使って角度を計算
theta = np.arccos(cos_theta)
# 引数degがTrueならば、角度を度数単位(degree)に変換
if deg == True:
theta = np.degrees(theta)
return theta
deg は結果を度数法単位 (deg) とラジアン (rad) のどちらで返すか決定するオプション引数です。デフォルトでは False に設定されているので、この引数を省略するとラジアンで返してきます。
v_angle() を使って、$\begin{bmatrix}1\\0\end{bmatrix}$ と $\begin{bmatrix}1\\\sqrt{3}\end{bmatrix}$ の間の角度を求めてみましょう。
deg は True に設定して結果を度数単位で返すようにします。
# SLA_008-2
# ベクトルを定義
v = np.array([1, 0])
w = np.array([1, np.sqrt(3)])
# vとwの間の角度を計算
theta = v_angle(v, w, deg = True)
print("θ = {:.3f}".format(theta))
θ = 60.000
コメントを書く