「ベクトル (vector)」の本来の意味は、方向を持った量のことでした。高校の数学や物理では、二次元ベクトルや三次元ベクトルを使いましたが、広い意味でのベクトルはそれだけではなく、数をいくつも並べることで、5 次元や 10 次元など高次元のベクトルを表すことができます。本ページでは、n 個の数 \(v_1, v_2, \ldots, v_n\) を並べたものを n 次元空間のベクトル \(\vec v\) として扱うことにします。
\(v_i\) をベクトル \(\vec v\) の第 \(i\) 成分といいます。ベクトルは文字の上に矢印を付けるだけではなく、\(\overrightarrow{AB}\) のように 2 文字の上に矢印を付けたり、\(\boldsymbol A\) のように太い文字で表すこともあります。
ベクトルの大きさを「ノルム (norm)」といいます。ノルムにはいくつかの定義ありますが、よく用いられるのがユークリッドノルムで \(|\vec v|\) と表します。以下にノルムの定義を示します。
ノルムは成分の二乗和の平方根になります。特に、大きさが 0 のベクトルをゼロ・ベクトルといい、\(\vec O\) と表記します。大きさが 1 のベクトルを単位ベクトル、一つの成分が 1 でそれ以外の成分が 0 のベクトルを基本ベクトルといいます。単位ベクトルや基本ベクトルは \(\vec e\) と表記することが多いです。
大きさが同じで方向が反対のベクトルを「逆ベクトル」といいます。\(\overrightarrow{AB}\) の逆ベクトルは \(\overrightarrow{BA}\) と表記し、\(\vec v\) の逆ベクトルは \(-\vec v\) と表記することが多いです。
プログラミング言語の場合、ベクトルは一次元配列で表すことができます。たとえば、Python であれば [1, 2, 3, 4, 5] のようにリスト (一次元配列) を使うと簡単です。ただし、リストをそのまま使うと不便なことが多いので、ベクトルや行列をサポートしている言語、Python であれば NumPy や SymPy を使ったほうが簡単だと思います。
NumPy での使用例を示します。NumPy については、拙作のページ お気楽 NumPy プログラミング超入門 をお読みくださいませ。
>>> import numpy as np >>> a = np.array([1.0,2.0,3.0,4.0,5.0]) >>> a array([1., 2., 3., 4., 5.]) >>> b = np.array([-1.0,-2.0,-3.0,-4.0,-5.0]) >>> b array([-1., -2., -3., -4., -5.]) >>> z = np.zeros(5) >>> z array([0., 0., 0., 0., 0.]) >>> np.linalg.norm(a) 7.416198487095663 >>> np.linalg.norm(b) 7.416198487095663 >>> np.linalg.norm(z) 0.0
ベクトルの和は成分同士の足し算、差は成分同士の引き算になります。
ベクトルの和は以下の法則が成り立ちます。
ベクトルの和は数と同様に交換法則や結合法則が成立します。また、単位元はゼロ・ベクトルになり、逆元は逆ベクトルになります。
NumPy を使うと、ベクトルの和と差は演算子 +, - で求めることができます。簡単な実行例を示します。
>>> u = np.array([1.,1.,1.,1.,1.]) >>> v = np.array([1.,2.,3.,4.,5.]) >>> w = np.array([5.,4.,3.,2.,1.]) >>> z = np.zeros(5) >>> v + w array([6., 6., 6., 6., 6.]) >>> w + v array([6., 6., 6., 6., 6.]) >>> (u + v) + w array([7., 7., 7., 7., 7.]) >>> u + (v + w) array([7., 7., 7., 7., 7.]) >>> v + z array([1., 2., 3., 4., 5.]) >>> v + (- v) array([0., 0., 0., 0., 0.]) >>> v - v array([0., 0., 0., 0., 0.]) >>> v - w array([-4., -2., 0., 2., 4.]) >>> v + (- w) array([-4., -2., 0., 2., 4.])
k を実数とすると、\(k\vec v\) は各成分 \(v_i\) を \(k\) 倍したものになります。
\(m, n\) を実数とすると、ベクトルの実数倍は以下の法則が成り立ちます。
第 i 成分が 1 で残りの成分が 0 の基本ベクトルを \(\vec {e_i}\) とします。ベクトル \(\vec v\) は成分 \(v_i\) と基本ベクトル \(\vec {e_i}\) を使って、次のように表すことができます。
NumPy を使うと、ベクトルの和と差は演算子 * で求めることができます。簡単な実行例を示します。
>>> v = np.array([1.0,2.0,3.0,4.0,5.0]) >>> v array([1., 2., 3., 4., 5.]) >>> 3 * v array([ 3., 6., 9., 12., 15.]) >>> v * 3 array([ 3., 6., 9., 12., 15.]) >>> 3 * (5 * v) array([15., 30., 45., 60., 75.]) >>> 5 * (3 * v) array([15., 30., 45., 60., 75.]) >>> 3 * 5 * v array([15., 30., 45., 60., 75.]) >>> (3 + 5) * v array([ 8., 16., 24., 32., 40.]) >>> 3 * v + 5 * v array([ 8., 16., 24., 32., 40.]) >>> w = np.array([5.0,4.0,3.0,2.0,1.0]) >>> w array([5., 4., 3., 2., 1.]) >>> 3 * (v + w) array([18., 18., 18., 18., 18.]) >>> 3 * v + 3 * w array([18., 18., 18., 18., 18.]) >>> e1 = np.array([1.0,0.0,0.0,0.0,0.0]) >>> e2 = np.array([0.0,1.0,0.0,0.0,0.0]) >>> e3 = np.array([0.0,0.0,1.0,0.0,0.0]) >>> e4 = np.array([0.0,0.0,0.0,1.0,0.0]) >>> e5 = np.array([0.0,0.0,0.0,0.0,1.0]) >>> v array([1., 2., 3., 4., 5.]) >>> 1*e1 + 2*e2 + 3*e3 + 4*e4 + 5*e5 array([1., 2., 3., 4., 5.])
ベクトル同士の掛け算は 2 つの考え方があり、ひとつが「内積 (nner product)」で、もう一つが「外積 (outer product)」です。
ベクトルとベクトルを掛け算した結果がスカラー (量) なる演算を内積といい、結果がベクトルになる演算を外積といいます。内積のことをドット積、外積のことをクロス積と呼ぶこともあります。本ページでは内積について説明し、外積の説明は割愛させていただきます。あしからずご了承くださいませ。
内積の定義を示します。
内積は対応する成分同士の掛け算を足したものになります。上の定義により、\(\vec v\) 自身の内積 \(\vec v \cdot \vec v\) は、\(\vec v\) のノルムの 2 乗 \(|\vec v|^2\) になることがわかります。
ベクトルの内積にはもう一つ定義があります。
\(\theta\) は \(\vec v\) と \(\vec w\) のなす角を表します。高校の数学では、これを内積の定義としています。この定義は平面上で考えるとわかりやすいと思います。両方の定義が同じものであることを示します。
ベクトルの内積には以下の法則が成り立ちます。
NumPy の場合、ベクトルの内積は演算子 @ や関数 dot(), vdot() を使います。演算子 * は成分同士の掛け算になります。@ や dot() は行列の積も求めることができますが、vdot() はベクトル専用の関数です。
簡単な実行例を示します。
>>> v = np.array([1.0,2.0,3.0,4.0]) >>> w = np.array([5.0,6.0,7.0,8.0]) >>> v @ w 70.0 >>> np.dot(v, w) 70.0 >>> np.vdot(v, w) 70.0 >>> v @ v 30.0 >>> np.linalg.norm(v) 5.477225575051661 >>> math.sqrt(v @ v) 5.477225575051661 >>> v @ w 70.0 >>> w @ v 70.0 >>> u = np.array([2.0,4.0,6.0,8.0]) >>> u @ (v + w) 200.0 >>> u @ v + u @ w 200.0 >>> (5 * v) @ w 350.0 >>> v @ (5 * w) 350.0 >>> 5 * (v @ w) 350.0 >>> v * w array([ 5., 12., 21., 32.])
「行列 (matrix)」は要素 (element) を長方形または正方形に並べた「表 (table)」みたいなものです。
行列は丸カッコや角カッコで囲んで表すことが多いです。要素のことを成分と呼ぶこともあります。行列の横方向の並びを「行 (row)」といい、縦方向の並びを「列 (column)」といいます。一番左の例は 2 行 3 列の行列で、二番目の例は 3 行 2 列の行列になります。
行の数と列の数が等しい行列 (n 行 n 列の行列) を「正方行列」といいます。3, 4 番目の例は 3 行 3 列の正方行列になります。正方行列 \(A\) の左上から右下の対角成分が 1 で、それ以外の成分が 0 の行列を「単位行列」といいます。最後の例は単位行列です。単位行列は \(I\) または \(E\) で表すのがふつうです。また、すべての成分が 0 の行列を「零行列」といいます。零行列は \(O\) と表記します。。
行列 \(A\) と \(B\) において、行の数 m と列の数 n が等しいとき、\(A\) と \(B\) を同じ型であるといいます。同じ型の行列 \(A\) と \(B\) において、対応する成分がすべて等しいとき、\(A\) と \(B\) は等しいといい、\(A = B\) と表記します。それから、1 行だけの行列を「行ベクトル」、1 列だけの行列を「列ベクトル」といいます。
行列の和と差は同じ型の行列で成立し、結果は成分同士の足し算または引き算になります。2 行 2 列の正方行列を例を示します。
行列の加法は零行列が単位元になります。
行列の実数 (k) 倍は各成分に k を掛け算するだけです。
行列 \(A\) と \(B\) の積は \(A\) の列数と \(B\) の行数が等しいときに成立します。
n 行 l 列の行列 \(A\) と l 行 m 列の行列 \(B\) を掛け算すると、結果は n 行 m 列の行列 \(C\) になります。その成分 \(c_{ij}\) は次式のようになります。
行列 \(A\) に \(O\) を掛けると \(O\) になります。また、行列の積の単位元は単位行列になります。
行列の計算には以下の法則が成り立ちます。
行列の積の場合、乗法の交換法則は成立しません。一般に、\(AB \ne BA\) になるので注意してください。
NumPy の場合、行列の和と積は演算子 +, - で、行列の実数倍は演算子 * で、行列の積は演算子 @ や関数 dot() で行うことができます。簡単な実行例を示します。
>>> a = np.array([[1,2],[3,4]]) >>> a array([[1, 2], [3, 4]]) >>> b = np.array([[5,6],[7,8]]) >>> b array([[5, 6], [7, 8]]) >>> a + b array([[ 6, 8], [10, 12]]) >>> b + a array([[ 6, 8], [10, 12]]) >>> a - b array([[-4, -4], [-4, -4]]) >>> c = 10 * a >>> c array([[10, 20], [30, 40]]) >>> (a + b) + c array([[16, 28], [40, 52]]) >>> a + (b + c) array([[16, 28], [40, 52]]) >>> a @ b array([[19, 22], [43, 50]]) >>> b @ a array([[23, 34], [31, 46]]) >>> (a @ b) @ c array([[ 850, 1260], [1930, 2860]]) >>> a @ (b @ c) array([[ 850, 1260], [1930, 2860]]) >>> a @ (b + c) array([[ 89, 122], [193, 270]]) >>> a @ b + a @ c array([[ 89, 122], [193, 270]]) >>> (b + c) @ a array([[ 93, 134], [181, 266]]) >>> b @ a + c @ a array([[ 93, 134], [181, 266]]) >>> e = np.array([[1,0],[0,1]]) >>> e array([[1, 0], [0, 1]]) >>> e @ e array([[1, 0], [0, 1]]) >>> a @ e array([[1, 2], [3, 4]]) >>> e @ a array([[1, 2], [3, 4]])
なお、NumPy では行列 \(A\) の n 乗 (\(A^n\)) を演算子 ** で求めることはできません。モジュール numpy.linalg の関数 matrix_power(M, n) か、行列専用のクラス matrix を使ってください。コンストラクタは matrix() です。matrix の場合、行列の積は演算子 * を使います。演算子 ** を使って行列の累乗を計算することもできます。
>>> f = np.array([[1,1],[1,0]]) >>> f array([[1, 1], [1, 0]]) >>> np.linalg.matrix_power(f, 10) array([[89, 55], [55, 34]]) >>> np.linalg.matrix_power(f, 20) array([[10946, 6765], [ 6765, 4181]]) >>> np.linalg.matrix_power(f, 40) array([[165580141, 102334155], [102334155, 63245986]])
正方行列 \(A\) について、\(AX = XA = E\) となるような行列 \(X\) を \(A\) の逆行列といい、\(A^{-1}\) と表記します。つまり、\(AA^{-1} = A^{-1}A = E\) となります。2 行 2 列の逆行列を示します。
逆行列の性質を示します。
連立 1 次方程式の解は逆行列を使って求めることができます。
正方行列 \(A\) に逆行列 \(A^{-1}\) が存在するとき、\(A\) は「正則行列 (regular matrix)」であるといいます。\(A\) が正則行列であれば、連立方程式 \(Ax = b\) の解 \(x\) は一意に定まります。
NumPy の場合、逆行列はモジュール linalg の関数 inv() で求めることができます。また、linalg には連立方程式を解く関数 solve() も用意されています。簡単な使用例を示します。
>>> a = np.array([[2, 3], [1, 2]]) >>> a array([[2, 3], [1, 2]]) >>> b = np.linalg.inv(a) >>> b array([[ 2., -3.], [-1., 2.]]) >>> a @ b array([[1., 0.], [0., 1.]]) >>> b @ a array([[1., 0.], [0., 1.]]) >>> np.linalg.inv(np.linalg.inv(a)) array([[2., 3.], [1., 2.]]) >>> c = np.array([[2,3],[1,2]]) >>> c array([[2, 3], [1, 2]]) >>> np.linalg.inv(c) array([[ 2., -3.], [-1., 2.]]) >>> np.linalg.inv(a @ c) array([[ 7., -12.], [ -4., 7.]]) >>> np.linalg.inv(c) @ np.linalg.inv(a) array([[ 7., -12.], [ -4., 7.]])
x + y = 100 2x + 4y = 272
>>> a = np.array([[1, 1], [2, 4]]) >>> b = np.array([100, 272]) >>> np.linalg.solve(a, b) array([64., 36.]) >>> np.linalg.inv(a) @ b array([64., 36.])
x + y + z = 10 2x + 4y + 6z = 38 2x + 4z = 14
>>> a = np.array([[1, 1, 1], [2, 4, 6], [2, 0, 4]]) >>> b = np.array([10, 38, 14]) >>> np.linalg.solve(a, b) array([3., 5., 2.]) >>> np.linalg.inv(a) @ b array([3., 5., 2.])
「行列式 (determinant)」は正方行列に対して決まる重要な量 (スカラー) です。行列 \(A\) の行列式は \(\det A\) とか \(|A|\) と表します。2 行 2 列と 3 行 3 列の行列の行列式を示します。
行列式が 0 の場合、その行列に逆行列は存在しません。これは 2 行 2 列, 3 行 3 列だけではなく、n 行 n 列の正方行列でも同じです。
NumPy の場合、モジュール linalg に行列式を求める関数 det() が用意されています。簡単な使用例を示します。
>>> a1 = np.array([[2,3],[1,2]]) >>> a1 array([[2, 3], [1, 2]]) >>> np.linalg.det(a1) 1.0 >>> a2 = np.array([[1, 1, 1], [2, 4, 6], [2, 0, 4]]) >>> a2 array([[1, 1, 1], [2, 4, 6], [2, 0, 4]]) >>> np.linalg.det(a2) 11.999999999999995 >>> a3 = np.array([[2, 4, 2, 2], [4, 10, 3, 3], [2, 6, 1, 1], [3, 7, 1, 4]]) >>> a3 array([[ 2, 4, 2, 2], [ 4, 10, 3, 3], [ 2, 6, 1, 1], [ 3, 7, 1, 4]]) >>> np.linalg.det(a3) 0.0