第5回:RとPythonで学ぶデータサイエンス数学~行列基礎~

前回はベクトルの基礎を扱いました。今回は、ベクトルの進化系である行列について書いていきます。行列までを学んでしまえば、数学嫌いな方でも、データサイエンスの様々な参考書を読み進めることができるでしょう!

今回の目的は以下になります。

  • 行列の性質を理解する。
  • 行列を使って、連立方程式を解いてみる。

誰が読んでも理解できることを目指していますので、分かりにくい、理解できない等ありましたら、お気軽にコメント頂けると幸いです。なお、RやPythonを使わなくても、学ぶことができる内容ですので、数学の知識だけ学びたいという方も是非ご覧ください(^^)

行列の基礎

行列は、ベクトルを縦や横に並べたもので、こんなイメージです。

データサイエンス数学

ベクトルは上に矢印をつけるか太文字で表しましたが、行列の場合は基本的に大文字で表すことが一般的です。今回は大文字のAで表します。この行列は、2本の縦ベクトル、もしくは3本の横ベクトルで構成されているとみなすことができるので、行列の計算にはベクトルの性質をそのまま利用できます。また、行列は横を行、縦を列と呼ぶので、これは3行2列の行列となります。

行列の足し算引き算

足し算、引き算は、ベクトル同様それぞれの要素で計算ができます。行列Bを作り、足し算を行ってみます。

 B=  \begin{pmatrix}
2&3\\
1&-2\\
-4&3 
\end{pmatrix}
\\\ A + B =\begin{pmatrix}
3&-6\\
3&2\\
2&1 
\end{pmatrix}+
\begin{pmatrix}
2&3\\
1&-2\\
-4&3 
\end{pmatrix}\\\
= \begin{pmatrix}
5&-3\\
4&0\\
-2&4 
\end{pmatrix}

引き算も同様に要素ごとに要素ごとに引き算を行うだけです。ここまではベクトルと変わりませんね。Rではmatrix、pythonではnumpy.arrayを使って行列を作ります。

#行列をつくる
A <- matrix(c(3,3,2,-6,2,1),ncol=2)
B <- matrix(c(2,1,-4,3,-2,3),ncol=2)
#足し算
print(A+B)
import numpy as np
#行列をつくる
A = np.array([[3,-6],
         [3,2],
         [2,1]])
B = np.array([[2,-3],
         [1,-2],
         [-4,3]])

#足し算
print(A+B)

行列の定数倍とかけ算

行列の定数倍もベクトル同様にすべての要素を定数倍するだけになります。

 2A = 2\times\begin{pmatrix}
3&-6\\
3&2\\
2&1 
\end{pmatrix}=\begin{pmatrix}
6&-12\\
6&4\\
4&2 
\end{pmatrix}

次にかけ算ですが、いくつかポイントがあります。やり方はベクトルの内積を使って、横×縦で計算していきますが、ベクトルの内積は長さが同じである必要がありました。行列も同様に、横(列)と縦(行)が同じ長さになる必要があります。今回のように行列Aが3行2列、行列Bも3行2列のかけ算の場合、行列Aを転置させ、2行3列にする必要があります。こうすることで、横と縦が同じ長さになり、かけ算することができます。

データサイエンス数学

そして、横と縦でそれぞれのベクトル同士の内積を求めていくイメージで、計算します。通常のかけ算では、 a\times b b\times aも同じ値になります。しかし、行列のかけ算は、方向の要素をもつベクトルや行列になるので、かける方向によって結果が異なることに注意しましょう。

データサイエンス数学

データサイエンス数学

また、右側の行列の横と左側の行列の縦の長さが同じであれば、形が違っていても計算ができます。

 C=  \begin{pmatrix}
-5&2\\
3&1
\end{pmatrix}
\\\ A \cdot C =
\begin{pmatrix}
3&-6\\
3&2\\
2&1 
\end{pmatrix}
 \begin{pmatrix}
-5&2\\
3&1
\end{pmatrix}\\\
= \begin{pmatrix}
-33&0\\
-9&8\\
-7&5 
\end{pmatrix}

この場合はC \cdot Aは計算できないことに注意しましょう。

データサイエンス数学

#定数倍
print(2*A)

#内積
naiseki_AB <- t(A) %*% B
print(naiseki_AB)

naiseki_BA <- t(B) %*% A
print(naiseki_BA)

#形が違っても大丈夫
C <- matrix(c(-5,3,2,1),ncol=2)
naiseki_AC <- A %*% C
print(naiseki_AC)

#反対はエラー
C %*% A
Error in C %*% A : non-conformable arguments
#定数倍
print(2*A)

#内積
naiseki_AB = np.dot(A.T,B)
print(naiseki_AB)

naiseki_BA = np.dot(B.T,A)
print(naiseki_BA)

#形が違っても大丈夫
C = np.array([[-5,2],
         [3,1]])
naiseki_AC = np.dot(A,C)
print(naiseki_AC)

#反対はエラー
np.dot(C,A)
ValueError: shapes (2,2) and (3,2) not aligned: 2 (dim 1) != 3 (dim 0)

行列の割り算

ベクトルに割り算はありませんでしたが、行列には割り算のような計算があります。普通の割り算では、マイナス1乗という表現を使って、分数の表現で割り算を表すことがありますよね。

 5を5で割る: 5\times\dfrac{1}{5}= 5\times 5^{-1}

同じように行列でもマイナス1乗を使って、

CをCで割る : C \cdot C^{-1}

と表します。これを逆行列といいます。逆行列は、もとの行列にかけたときに、対角線上に1が並び、そのほかの要素が0なる単位行列となります。単位行列は単位ベクトルと似た概念で、Iで表すことが多いです。

 C \cdot C^{-1} = \begin{pmatrix}
1&0\\
0&1
\end{pmatrix}=I

通常のかけ算では、どんな数字に1をかけても元の値になりますが、単位行列も同様にどんな行列やベクトルをかけても、形はかわりません。また、反対に逆行列をかけると単位行列になる行列のことを正則行列ともいいます。すべての行列に逆行列が存在するとは限らないので、このように特別な名前がついています。(実は逆行列を持つことは、正則行列となる条件の1つに過ぎないのですが、今回は入門ということで、ご了承下さい。)逆行列を求める計算方法ですが、とても複雑かつ、現代の計算資源を使えばほとんどの場面で手計算する必要がないことから、ここでは割愛します。気になる方はこちらが分かりやすいです(^^)

https://atarimae.biz/archives/24004

逆行列を求めるにはRではsolve、pythonでは`numpy.linalg.inv

# 逆行列
print(solve(C))
         [,1]      [,2]
[1,] -0.09090909 0.1818182
[2,]  0.27272727 0.4545455
#単位行列になる
print(C %*% solve(C))
       [,1]          [,2]
[1,] 1.000000e+00 -1.110223e-16
[2,] 5.551115e-17  1.000000e+00
# 逆行列
inv_C = np.linalg.inv(C)
print(inv_C)
[[-0.09090909  0.18181818]
 [ 0.27272727  0.45454545]]

#単位行列になる
print(np.dot(inv_C,C))
[[1. 0.]
 [0. 1.]]

行列式で逆行列を判断する。

逆行列を直接求めることはなくても、逆行列が存在するかどうかは、案外簡単に判断できます。まず、第一条件として形が四角形、つまり、行と列が同じ次元である必要があります。これを正方行列と呼びます。(正則行列もあってややこしい、、)そして、もう一つの条件として行列式が0ではないことがあげられます。行列式は英語のdeterminantの略detを使うか、横棒2本で表します。

 M = \begin{pmatrix}
a&b\\
c&d
\end{pmatrix}\\\
\,\\\
det(M) = |M| = ad-cd

と表します。これを使って行列Cの行列式を求めてみると、

 C=  \begin{pmatrix}
-5&2\\
3&1
\end{pmatrix}\\\
\,
\\\det(C) = -5\times1-3\times2 = -11

となります。行列式の直感的な理解としては、行列式の絶対値が行列を構成するベクトルが表す面積もしくは体積と同様の意味を持ちます。例えば、行列Cのような2×2の行列式は、2本のベクトルが作る平行四辺形の面積です。

データサイエンス数学

行列が3×3以上になった場合の行列式は少し複雑ですので、また後ほどご紹介します。Rではdet、pythonでは、numpy.linalg.detで行列式を求めることができます。

print(det(C))
[1] -11
print(np.linalg.det(C))
>-11

行列と連立方程式

さて、ここで行列計算に慣れるために連立方程式を行列を使って解いてみましょう。

ある商品Aと商品Bがある。商品Aを2個、商品Bを3個買うと21万円、商品AをBを1個ずつ買うと9万円である。 商品Aと商品Bの値段はそれぞれいくらか?

懐かし算数の問題ですね。これを行列を使って解いていきます。商品Aの値段を\beta_{1}商品Bの値段を\beta_{2}として、連立方程式を作ると、

\left\{
    \begin{array}{l}
      2\beta_{1} + 3\beta_{2} = 21 \\
      \beta_{1} + \beta_{2} = 9
    \end{array}
  \right.

となります。まずは、この式をベクトルと行列表現に変えてみましょう。

 \begin{pmatrix}
2&3\\
1&1
\end{pmatrix}
\begin{pmatrix}
\beta_{1}\\
\beta_{2}
\end{pmatrix} = \begin{pmatrix}
21\\
9
\end{pmatrix}

どうでしょう?横×縦のかけ算はイメージできるでしょうか?今はまだ混乱する方も少しづつ慣れていきましょう。さて、ここから、さらに式を変形させます。

 X = \begin{pmatrix}
2&3\\
1&1
\end{pmatrix}\,
\boldsymbol{\beta} =
\begin{pmatrix}
\beta_{1}\\
\beta_{2}
\end{pmatrix} \, \boldsymbol{y} = \begin{pmatrix}
21\\
9
\end{pmatrix}

とすると、

 X \boldsymbol{\beta} = \boldsymbol{y}

と表すことができます。ここから、 \boldsymbol{\beta} = の形にするため、両辺に左からXの逆行列をかけます。そして、

  • 行列にその行列の逆行列をかけると単位行列になる
  • 単位行列に何をかけても形をかえることはない

という性質を使うと、

 X^{-1}X \boldsymbol{\beta} = X^{-1}\boldsymbol{y}\\\
\boldsymbol{\beta} = X^{-1}\boldsymbol{y}

となります。これは、

 5\beta = y

という式を両辺に1/5をかけて、\beta=に変形することに似ています。そして、行列はかける方向によって値が変わるのでどちらからかけるのかを明記します。ここまでくれば、あとはXの逆行列にyをかけた答えが\beta_{1}\,,\beta_{2}の答えになります。

 X^{-1}=\begin{pmatrix}
-1&3\\
1&2
\end{pmatrix}\\\
\begin{pmatrix}
\beta_{1}\\
\beta_{2}
\end{pmatrix}=
X^{-1}\boldsymbol{y} = \begin{pmatrix}
-1&3\\
1&2
\end{pmatrix}\begin{pmatrix}
21\\
9
\end{pmatrix}
= \begin{pmatrix}
6\\
3
\end{pmatrix}

商品Aは6万、商品Bは3万であることが分かりました!今回のように逆行列をかけて、式変形を行う方法は、とてもよく使うテクニックなので覚えておきましょう!

y <- c(21,9)
X <- matrix(c(2,1,3,1),ncol=2)
#Xの逆行列
inv_X <- solve(X)
#答え
print(inv_X %*% y)
    [,1]
[1,]    6
[2,]    3
y = np.array([21,9])
X = np.array([[2,3],
             [1,1]])

#Xの逆行列
inv_X = np.linalg.inv(X)

#答え
print(np.dot(inv_X,y))
>[6. 3.]

まとめ

行列はベクトルを使うと、最後の連立方程式のように式を簡潔に、そして処理速度を高速にできます。ベクトルや行列表現に慣れないうちは、頭が混乱するかもしれませんが、慣れてくれば、どんなに数の多いデータでもかたまりとして考えることができるので、少しづつ慣れていきましょう。最後に今回の内容をまとめておきます。

  • 行列はベクトルを縦か横に並べたようなもの。
  • 縦を行、横を列と呼ぶ。
  • 行列のかけ算は、右側の横と左側の縦の長さを同じにする。
  • 対角線上に1が並び、そのほかの要素が0なる行列を単位行列と呼ぶ。
  • ある行列に、その行列の逆行列をかけると単位行列となる。
  • 単位行列に何をかけても形をかえることはない。
  • 逆行列が存在する行列を正則行列と呼ぶ。
  • 形が正方形の行列を正方行列と呼ぶ。

※本記事は筆者が個人的に学んだことをまとめた記事なります。所属する組織の意見・見解とは無関係です。また、数学の記法や詳細な理論、用語等で誤りがあった際はご指摘頂けると幸いです。

参考

データサイエンスで必要となる数学がほとんど網羅されています。初めての方には、少し難易度が高いですが、数式の導出など丁寧にまとめてあり、脱初心者を目指す方にはとてもおすすめです。

データサイエンスを学び始めて右も左も分からなかったときこの本に出会い、”統計、機械学習を学ぶための数学を学ぶ本”というコンセプトがぴったりで感動した。今、読み直してみるとさらに理解が深まり、データサイエンス数学入門書としては間違いなくおすすめです。