「ベクトル (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