2012/10/04

文系のための「擬逆行列」(2)

逆行列というのは計算がとにかく厄介で、手計算で計算するのは大変。
それ故に、通常は、コンピュータの力を借りることになる。
しかしながら、逆行列の性質を知らなくても良いということでは無い。

これまで、行列の足し算引き算掛け算を行なってきたが、
行列の「割り算」そのものは存在しない。その代わりに、存在するのが逆行列である。
逆行列は、スカラーにおける逆数に相当し、行列を基準化するために用いる

つまり、逆行列は、厳密には「割り算」では無いけれど、
逆行列を掛ける(あるいは掛けられる)ということは、
スカラーにおいて逆数を掛けるような意味を持つ。

では、実際にどのような時に役立つのか?

実際には、様々なところで逆行列は登場するのであるが、
特に、逆行列を用いることで連立方程式が解ける
というのは、逆行列の重要な性質の一つである。

私は辛党なのだが、ケーキ屋さんになったつもりになって、
洋菓子を作るための分量を考えてみることにする。
まず、以下のようなレシピとそれに対応する分量が与えられたとする。


pancake doughnut sponge cake
cake flour
(gram per piece)
50.0
7.0
75.0
egg
(per piece)
0.5
0.2
3.0
milk
(millilitre per piece)
50.0
0.0
20.0
sugar
(gram per piece)
5.0
6.0
50.0

これは、ホットケーキドーナツカステラのレシピであり、
それぞれ、一個辺りの薄力粉の量卵の量牛乳の量砂糖の量が書いてある。
この通りに作れば、秘伝の洋菓子を作れる...かもしれない。

なお、これまでの話では、対象が行で変数が列となる「n×p行列」を扱ってきたが、
今回に関しては、対象が列で変数が行となる「p×n行列」となっている。
これは、後の話を理解しやすくするためであり、例外的なデータ構造となっている。

まずは、上記のレシピの分量を行列としてRに入れてみる。

# 各レシピにおける材料の分量をベクトルとして準備する
pancake <- c(50, 0.5, 50, 5.0)
doughnut <- c(7.0, 0.2, 0.0, 6.0)
spongecake <- c(75, 3.0, 20.0, 50.0)

# 作成したベクトルを結合して行列を作成する。
A <- cbind(pancake, doughnut, spongecake)

# 対称名を付ける
rownames(A) <- c("flour", "egg", "milk", "sugar")

ここで、cbind()関数というのは、ベクトルあるいは行列列に追加するための関数。
この関数も非常に良く使う。列を追加(結合)するためにはrbind()関数を使う。

上手くできると、以下のような行列が出来るはず。

> A
      pancake doughnut spongecake
flour    50.0      7.0         75
egg       0.5      0.2          3
milk     50.0      0.0         20
sugar     5.0      6.0         50

まずは、復習から。とりあえず、行列の掛け算を用いて、
ホットケーキ2ドーナッツ10カステラ1
を作ったときの総分量はどのようになるのか?これを考えてみる。

とりあえず、小麦粉の総量例を考えてみると、
ホットケーキの小麦粉、ドーナツの小麦粉、カステラの小麦粉のそれぞれの分量と
作りたい個数を掛けて足せば良いのだから、この場合は、

小麦粉の総分量= (50.0 ✕ 2)+(7.0 ✕ 10) +(75 ✕ 1)

となる。これは行列の掛け算で簡単に計算することができる。
行列の掛け算のルールは、「横✕縦」が原則であった。
つまり、以下のような式を考えれば良いことになる。



となるはず。Rで実際に計算して確かめてみる。
たしか、行列の「掛け算」のときには「%*%」を使うのだった。

# 作りたい個数を変数にセットする。
pieces <- c(2, 10, 1)

# 次に、行列の掛け算を実行
A %*% pieces

以下がこの行列の計算結果。

> # 次に、行列の掛け算を実行
> A %*% pieces
      [,1]
flour  245
egg      6
milk   120
sugar  120

このように、総分量を計算するのは至って簡単。
上手くやれば、洋菓子作りの分量計算を自動的にやってくれるソフトも作れる。
まぁ、現実問題として、そういったソフトの需要があるかという問題はあるが。

さて、以上のことが確認できたら、今度は、逆の場合を考えてみる。
すなわち、総分量があったとして、それで作れるお菓子の量を知りたい、
という状況を考えてみる。

薄力粉565g15牛乳260ml砂糖290gを使ったときに、
ホットケーキドーナッツカステラはそれぞれいくつ作れるのか?
今度は、これを考えてみる。まずは、式を考えなくてはならない。



知りたい場所が変わったので、今度はこのような式を考えることができる。
おそらく、ここまでは、想像できたはず。知りたい場所が変わっただけ。
計算はしないが、試しに、スカラーの計算に展開してみる。



そうそう。このようなものを連立方程式と呼ぶのであった。
我々が中学校までに習った連立方程式は、実は行列で表すことができる。
計算の順番を確認してみると、ちゃんと、横✕縦の形式になっていて対応がとれるハズ。

では、いよいよ、この連立方程式を解くことを考えてみる。
ここで、先程の行列の式を、よく観察してみる。
すると、あることに気づく。

左辺にxのベクトルを残し、右辺を基準化したら答えが解るのではないか?
ここで、スカラーの世界では、両辺を同じ数で割れば良かったはずだが、
残念ながら、行列の世界には「割り算」は存在しない。そこで、逆行列が登場する。



思わず割り算をしたくなるかもしれない。でも、割り算をしてはいけない
移動したレシピの行列を良く見てみる。右上に「-1」が付いている。
この右上の記号が逆行列を意味するのであった。

さて、もう一つ思い出してもらいたい。通常の逆行列の条件は何だったか?
既に述べたように、逆行列は正方行列にしか対応しなかった
つまり、ここでは、擬逆行列を使う必要が出てくる。

今の状況では、少々解りにくい。記号を使って式を般化してみる。



元の行列の転置行列元の行列を掛けると正方行列になる。
この正方行列の逆行列は、転置行列の分だけ余分に基準化しているので、
さらに、転置行列を掛けて、元の状態に対応する行列に戻す

また、特異値分解から、次のようにして計算することも可能。



詳しくは、特異値分解の話に書いてあるが、
スカラーにおける因数分解のように、行列においても分解というものが存在する。
要するに、行列の状態の見通しを良くするのであるが、これを使うと擬逆行列も求まる。

とりあえず、この二つの方法で、先程の問題を解決してみる。
まずは、転置行列を使った方法。

# 材料の総量
total <- c(565, 15, 260, 290)

# 連立方程式を解く
solve((t(A)%*%A))%*%t(A)%*%total

ここで、solve()関数というのが逆行列を求める方法であった。
以下がこの計算の結果。

> # 連立方程式を解く
> solve((t(A)%*%A))%*%t(A)%*%total
           [,1]
pancake       4
doughnut     20
spongecake    3

次に、特異値分解を用いた方法。

# 材料の総量
total <- c(565, 15, 260, 290)

# 特異値分解を行う
A.svd <- svd(A)

# 解りやすいように変数を入れなおす。
D <- diag(A.svd$d)
V <- A.svd$v
U <- A.svd$u

# 連立方程式を解く
V %*% solve(D)%*%t(U)%*%total

そして、この結果。

> # 連立方程式を解く
> V %*% solve(D)%*%t(U)%*%total
     [,1]
[1,]    4
[2,]   20
[3,]    3

そうそう。逆行列の関数ginv()関数も存在していた。一応、それも比較。

# ライブラリを読み込む
library(MASS)

# 連立方程式を解く
ginv(A)%*%total

そして、この結果を以下に。

> # 連立方程式を解く
> ginv(A)%*%total
     [,1]
[1,]    4
[2,]   20
[3,]    3

以上の結果から、いずれの方法も同じ結果を導いていることが確認できる。
結論としては、ホットケーキ4枚と、ドーナツ20個カステラ3個を作ることができる。

ところで、今回の場合は、きちんと計算することができたが、
かならず、キレイな計算結果が出てくるとは限らない
つまり、そもそも、連立方程式が解けない場合が考えられる。

実は、そのような時でも、擬逆行列を使うと近似的に最適な答えを見つけてくれる。
最適な答えというのは、要するに、誤差の二乗が最も小さくなるような答えである。
この性質から、一連方法は、「最小二乗法」ととも呼ばれる。

このことは、後に中級編で解説する「重回帰分析」とも密接な関わりがある。

0 件のコメント:

コメントを投稿