[python]算数・数学⑧~行列~

#前回まで
[前回はこちら](https://qiita.com/hiroyuki_mrp/items/674bab9a49a5f7bffbf4)

#改めて
機械学習を始めるにも、算数や数学がわからないと、入門書すら読めない。ただそこまで、ちゃんと解説してあるものもない。ということで最低限必要な数学基礎をこの記事で書けたらいいなと思っています。

#環境
ほぼ影響ないですが、python3系を利用。

#前提
四則演算や累乗（2乗とか3乗とか）がわかっていること

#行列

行列はm行n列（m×nの行列）で表現される、以下みたいなやつのことです。

```math
A=\left( \begin{array}{cc}1\\ 2\\ 3\end{array} \right)
```

```py
import numpy as np
#3×１の行列
matrix31 = np.matrix([1,2,3])
matrix31
# ->matrix([[1, 2, 3]]) 
```

```math
B=\left( \begin{array}{cc}1&2&3\\ 4&5&6\\\end{array} \right)
```

```py
#2×3の行列
matrix23 = np.matrix([[1,2,3],
                     [4,5,6]])
matrix23
```

```math
B=\left( \begin{array}{cc}1&2&3\\ 4&5&6\\7&8&9\end{array} \right)
```

```py
#3×3の行列
matrix33 = np.matrix([[1,2,3],
                     [4,5,6],
                     [7,8,9]])
matrix33
```

※一瞬ベクトルと似ていますが、ベクトルは小文字で扱うことが多く、行列は大文字が多いです。


#行列の演算

###足し算と引き算
ベクトルと大きくは変わらず成分ごとで計算をします。
※当然成分の形が違うものは計算できません。

```math
A=\left( \begin{array}{cc}a_{11} &a_{12}\\ a_{21}&a_{22}\\ \end{array} \right),
B=\left( \begin{array}{cc}b_{11} &b_{12}\\ b_{21}&b_{22}\\ \end{array} \right)\\
　\\

A+B=\left( \begin{array}{cc}a_{11} &a_{12}\\ a_{21}&a_{22}\\ \end{array} \right)+\left( \begin{array}{cc}b_{11} &b_{12}\\ b_{21}&b_{22}\\ \end{array} \right)
=\left( \begin{array}{cc}a_{11}+b_{11} &a_{12}+b_{12}\\ a_{21}+b_{21}&a_{22}+b_{22}\\ \end{array} \right)\\


A-B=\left( \begin{array}{cc}a_{11} &a_{12}\\ a_{21}&a_{22}\\ \end{array} \right)-\left( \begin{array}{cc}b_{11} &b_{12}\\ b_{21}&b_{22}\\ \end{array} \right)
=\left( \begin{array}{cc}a_{11}-b_{11} &a_{12}-b_{12}\\ a_{21}-b_{21}&a_{22}-b_{22}\\ \end{array} \right)
```

pythonで書いてみます。
※numpyのarrayを利用すると二次元配列になってしまい、通常?の掛け算ができないので、matrixを利用します。

```py
import numpy as np
A = np.matrix([[2,3],
               [4,5]])
B = np.matrix([[6,7],
               [8,9]])
print(A+B)
print(A-B)

# ->
[[ 8 10]
 [12 14]]
[[-4 -4]
 [-4 -4]]
```

###行列の実数倍

とてもシンプルに、全部実数倍するだけ。

```math
A=\left( \begin{array}{cc}a_{11} &a_{12}\\ a_{21}&a_{22}\\ \end{array} \right)\\
kA = k\left( \begin{array}{cc}a_{11} &a_{12}\\ a_{21}&a_{22}\\ \end{array} \right)\\
kA = \left( \begin{array}{cc}ka_{11} &ka_{12}\\ ka_{21}&ka_{22}\\ \end{array} \right)\\
```

```py
import numpy as np
A = np.matrix([[1,2],
               [3,4]])
k = 5
k*A

# ->
matrix([[ 5, 10],
        [15, 20]])
```

###訳わらかなくなる人続出の積

まず大事な前提
[ l行m列 × m行n列 ]の掛け算は 
・mが**等しい**必要がある
・**結果はl行×n列**の行列になる

```math
A=\left( \begin{array}{cc}a_{11} &a_{12}\\ a_{21}&a_{22}\\ \end{array} \right),
B=\left( \begin{array}{cc}b_{11} &b_{12}\\ b_{21}&b_{22}\\ \end{array} \right)\\　
```

```math
A\times{B}=\left( \begin{array}{cc}a_{11} &a_{12}\\ a_{21}&a_{22}\\ \end{array} \right)\times\left( \begin{array}{cc}b_{11} &b_{12}\\ b_{21}&b_{22}\\ \end{array} \right)\\
=\left( \begin{array}{cc}a_{11}b_{11}+a_{12}b_{21} &a_{11}b_{12}+a_{12}b_{21} \\ a_{21}b_{11}+a_{22}b_{21} &a_{21}b_{12}+a_{22}b_{22}\\ \end{array} \right)
```

僕が高校生の時は、**「Aの上の行２人」が「B行列」に戦いを挑みにいく。まず対戦するのは「Bの前列２人」その次が「Bの後列２人」。戦いが終わると、次は「Aの下の行２人」が同じように戦う**と覚えさせられました。変な覚えかた。

```
import numpy as np
A = np.matrix([[2,3],
               [4,5]])
B = np.matrix([[6,7],
               [8,9]])
print(A*B)

#->
[[36 41]
 [64 73]]
```

ちなみにnumpyのarrayでやってみるとどうなるか。要素ごとの掛け算になります。

```math
A\times{B}=\left( \begin{array}{cc}a_{11} &a_{12}\\ a_{21}&a_{22}\\ \end{array} \right)\times\left( \begin{array}{cc}b_{11} &b_{12}\\ b_{21}&b_{22}\\ \end{array} \right)
=\left( \begin{array}{cc}a_{11}\times{b_{11}} &a_{12}\times{b_{12}}\\ a_{21}\times{b_{21}}&a_{22}\times{b_{22}}\\ \end{array} \right)\\
```

```py
import numpy as np
A = np.array([[2,3],
               [4,5]])
B = np.array([[6,7],
               [8,9]])
print(A*B)

#->
[[12 21]
 [32 45]]
```

#単位行列

簡単にいうと、**左上かから右下に対角線に１が入っている行列**のことで、整数でいう「１」を意味します。(EやIで表されるがあります)

みるとわかりやすいのでpython

```py
print(np.eye(5))
[[1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 1.]]

print(np.eye(10))
[[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0. 0. 1.]]
```

これを掛け算してみるとわかるんですが、整数の１と同じ意味になっています。（恒等写像）
つまり

$AE = EA = A$
となります。

```py
import numpy as np
A  = np.matrix([[1,2],
                [3,4]])
E = np.eye(2)#２＊2の単位行列
print(A*E)

# ->
[[1. 2.]
 [3. 4.]]
```

#逆行列

ある整数Aがある時に、かけることで1を求められる数値を**逆数A$^{-1}$**と言います。Aであれば$\frac{1}{A}$が逆数になります。

行列の世界においては、答えが「単位行列」になる行列ことを「**逆行列**」と言います。

```math
A \times A^{-1} = E
```
※−1乗ではなくて、逆数の意味です。

この計算ができる前提として、「正方行列(行と列が同じ長さ)」でかつ**行列式が0ではない** ことが必要になります。（逆行列がある行列を正則行列という）

行列式は

```math
|A|=detA=ad-bc
```
というものです。#二次正方出ない場合は「サラスの方法※ググってください」を利用する

例でいうと

```math
A=\left( \begin{array}{cc}1 &2\\ 3&4\\ \end{array} \right)\\
の時に\\
|A| = detA = 1\times{4} -2\times{3} = -2
```
という計算になります。

そして逆行列は

``` math
A^{-1} = \frac{1}{ad-bc}\left( \begin{array}{cc}d &-b\\ -c&a\\ \end{array} \right)
```

で計算ができます。掃き出し法とかもあります。

これを使うと連立方程式を解くこともできます。

```math
5x+3y = 9\\
2x+y = 4\\
```
という式は行列では

```math
\left( \begin{array}{cc}5 & 3 \\ 2&1\\ \end{array} \right)\left( \begin{array}{cc}x\\ y\\ \end{array}\right) = \left( \begin{array}{cc}9\\ 4\\ \end{array}\right)
```
と表すことができます。

となると両辺に**左側から**逆行列をかければ（x、y）だけ残すことができます。

```math
\left( \begin{array}{cc}−1 & 3 \\ 2&-5\\ \end{array} \right)\left( \begin{array}{cc}5 & 3 \\ 2&1\\ \end{array} \right)\left( \begin{array}{cc}x\\ y\\ \end{array}\right) = \left( \begin{array}{cc}−1 & 3 \\ 2&-5\\ \end{array} \right)\left( \begin{array}{cc}9\\ 4\\ \end{array}\right)\\
\left( \begin{array}{cc}1 & 0 \\ 0&1\\ \end{array} \right)\left( \begin{array}{cc}x\\ y\\ \end{array}\right) = \left( \begin{array}{cc}3\\ -2\\ \end{array}\right)\\
\left( \begin{array}{cc}x\\ y\\ \end{array}\right) = \left( \begin{array}{cc}3\\ -2\\ \end{array}\right)
```

普通に連立方程式するよりも簡単かもしれません。





#線形変換

ベクトルに行列を掛けてベクトルを作ることを線形変換と言います。

```math
A = \left( \begin{array}{cc}1 & 2 \\ 3&4\\ \end{array} \right),
\vec{b} = \left( \begin{array}{cc}5\\ 6\\ \end{array}\right)\\

A \times{\vec{b}}
```

シンプルに

```math
A \times{\vec{b}} = \left( \begin{array}{cc}1 & 2 \\ 3&4\\ \end{array} \right)\times{\left( \begin{array}{cc}5\\ 6\\ \end{array}\right)} = \left( \begin{array}{cc}17 \\ 39\\ \end{array} \right)
```
とできます。

また基準基底$e$を使って算出することもできます。

```math
b = 5\left( \begin{array}{cc}1\\ 0\\ \end{array}\right)+6\left( \begin{array}{cc}0\\ 1\\ \end{array}\right) = 5e_x+6e_y\\
```
Aを分解して$e_1,e_2$に分割します。

```math
e_1 = \left( \begin{array}{cc}1\\ 3\\ \end{array}\right),e_2 = \left( \begin{array}{cc}2\\ 4\\ \end{array}\right)\\
　\\
Ab = \left( \begin{array}{cc}1 & 2 \\ 3&4\\ \end{array} \right)\bigg(5\left( \begin{array}{cc}1\\ 0\\ \end{array}\right)+6\left( \begin{array}{cc}0\\ 1\\ \end{array}\right)\bigg)\\
= 5\left( \begin{array}{cc}1 & 2 \\ 3&4\\ \end{array} \right)\left( \begin{array}{cc}1\\ 0\\ \end{array}\right)+6\left( \begin{array}{cc}1 & 2 \\ 3&4\\ \end{array} \right)\left( \begin{array}{cc}0\\ 1\\ \end{array}\right)\\
= 5\left( \begin{array}{cc}1\\ 3\\ \end{array} \right)+6\left( \begin{array}{cc}2 \\ 4\\ \end{array} \right)\\
= 5e_1+6e_2\\
= \left( \begin{array}{cc}5\\ 15\\ \end{array} \right)+\left( \begin{array}{cc}12 \\ 24\\ \end{array} \right)\\
= \left( \begin{array}{cc}17\\ 39\\ \end{array} \right)
```
結果は同じになりました。

この式からわかるように$e_x$は$e_1$に、$e_y$は$e_2$に変化していくことで、回転や拡大をしていっています。こうした変化のことを線形変換と言います。

#固有値と固有ベクトル

次の式を満たすようなベクトルxが存在するときに、$\lambda$をAの**固有値**、xをAを**固有値ベクトル**と言います。行列Aにひもづくもので、**行列Aを掛けても、$\lambda$倍されるだけで方向が変わらないベクトルが$\vec{x}$になります。※
普通は方向も大きさも変わる。

```math
Ax = \lambda{Ex}
```
これを整理すると

```math
Ax - \lambda{Ex} = 0\\
(A-\lambda{E})x = 0
```

固有ベクトルが存在する条件を考えると、逆行列の$(A-\lambda{E})^{-1}$が存在しないことが前提となります。つまり**固有方程式**$det(A-\lambda{E})=0$になるはずです。

例を用いて説明します。

```math
A = \left( \begin{array}{cc}3 & 1 \\ 2&2\\ \end{array} \right)
```
の固有値と固有ベクトルを求めます。

```math
det(A-\lambda{E})
```
なので

```math
det\bigg(\left( \begin{array}{cc}3 & 1 \\ 2&2\\ \end{array} \right)-\lambda\left( \begin{array}{cc}1 & 0 \\ 0&1\\ \end{array} \right)\bigg)=0\\
det\bigg(\left( \begin{array}{cc}3 & 1 \\ 2&2\\ \end{array} \right)-\left( \begin{array}{cc}\lambda & 0 \\ 0&\lambda\\ \end{array} \right)\bigg)=0\\
det\left( \begin{array}{cc}3-\lambda & 1 \\ 2&2-\lambda \\ \end{array} \right)=0\\
(3-\lambda)(2-\lambda)- (1\times{2})=0\\
\lambda^2-5\lambda+4 = 0\\
(\lambda-4)(\lambda-1) = 0
```
なので$\lambda = 4,1$になります。

もともとの式に代入します。($\lambda = 4$の場合)

```math
(A-\lambda{E})x = 0\\
(A-4E)x = 0\\
\left( \begin{array}{cc}3-4 & 1 \\ 2&2-4\\ \end{array} \right)x = 0\\
\left( \begin{array}{cc}-1 & 1 \\ 2&-2\\ \end{array} \right)x = 0\\
```

```math
x = \left( \begin{array}{cc}a \\ b\\ \end{array} \right)
```

と置くと

```math
\left( \begin{array}{cc}-1 & 1 \\ 2&-2\\ \end{array} \right)\left( \begin{array}{cc}a \\ b\\ \end{array} \right) = 0\\
```

とすると固有値ベクトルxは

```math
x = \left( \begin{array}{cc}1 \\ 1\\ \end{array} \right)
```

の定数倍とすることができます。

さらにもともとの式に代入します。($\lambda = 1$の場合)

```math
(A-\lambda{E})x = 0\\
(A-E)x = 0\\
\left( \begin{array}{cc}3-1 & 1 \\ 2&2-1\\ \end{array} \right)x = 0\\
\left( \begin{array}{cc}2 & 1 \\ 2&1\\ \end{array} \right)x = 0\\
```

```math
x = \left( \begin{array}{cc}a \\ b\\ \end{array} \right)
```

と置くと

```math
\left( \begin{array}{cc}2 & 1 \\ 2&1\\ \end{array} \right)\left( \begin{array}{cc}a \\ b\\ \end{array} \right) = 0\\
```

とすると固有値ベクトルxは

```math
x = \left( \begin{array}{cc}1 \\ -2\\ \end{array} \right)
```

の定数倍とすることができます。

これらは主に主成分分析の中身で利用されており、複雑な行列のデータを二次元に次元削減することができるようになり、人間が理解しやすい形に変形することができます。

#ここまで

次回は[統計](https://qiita.com/hiroyuki_mrp/items/7d417bc91c583cc8c3d8)について投稿していきます。