逆行列というのは計算がとにかく厄介で、手計算で計算するのは大変。
これは、ホットケーキ、ドーナツ、カステラのレシピであり、
それぞれ、一個辺りの薄力粉の量、卵の量、牛乳の量、砂糖の量が書いてある。
この通りに作れば、秘伝の洋菓子を作れる...かもしれない。
なお、これまでの話では、対象が行で変数が列となる「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
このように、総分量を計算するのは至って簡単。
上手くやれば、洋菓子作りの分量計算を自動的にやってくれるソフトも作れる。
まぁ、現実問題として、そういったソフトの需要があるかという問題はあるが。
さて、以上のことが確認できたら、今度は、逆の場合を考えてみる。
すなわち、総分量があったとして、それで作れるお菓子の量を知りたい、
という状況を考えてみる。
薄力粉565g、卵15個、牛乳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個を作ることができる。
ところで、今回の場合は、きちんと計算することができたが、
かならず、キレイな計算結果が出てくるとは限らない。
つまり、そもそも、連立方程式が解けない場合が考えられる。
実は、そのような時でも、擬逆行列を使うと近似的に最適な答えを見つけてくれる。
最適な答えというのは、要するに、誤差の二乗が最も小さくなるような答えである。
この性質から、一連方法は、「最小二乗法」ととも呼ばれる。
このことは、後に中級編で解説する「重回帰分析」とも密接な関わりがある。
それ故に、通常は、コンピュータの力を借りることになる。
しかしながら、逆行列の性質を知らなくても良いということでは無い。
これまで、行列の足し算、引き算、掛け算を行なってきたが、
行列の「割り算」そのものは存在しない。その代わりに、存在するのが逆行列である。
逆行列は、スカラーにおける逆数に相当し、行列を基準化するために用いる。
つまり、逆行列は、厳密には「割り算」では無いけれど、
逆行列を掛ける(あるいは掛けられる)ということは、
スカラーにおいて逆数を掛けるような意味を持つ。
では、実際にどのような時に役立つのか?
実際には、様々なところで逆行列は登場するのであるが、
特に、逆行列を用いることで連立方程式が解ける、
というのは、逆行列の重要な性質の一つである。
私は辛党なのだが、ケーキ屋さんになったつもりになって、
洋菓子を作るための分量を考えてみることにする。
まず、以下のようなレシピとそれに対応する分量が与えられたとする。
しかしながら、逆行列の性質を知らなくても良いということでは無い。
これまで、行列の足し算、引き算、掛け算を行なってきたが、
行列の「割り算」そのものは存在しない。その代わりに、存在するのが逆行列である。
逆行列は、スカラーにおける逆数に相当し、行列を基準化するために用いる。
つまり、逆行列は、厳密には「割り算」では無いけれど、
逆行列を掛ける(あるいは掛けられる)ということは、
スカラーにおいて逆数を掛けるような意味を持つ。
では、実際にどのような時に役立つのか?
実際には、様々なところで逆行列は登場するのであるが、
特に、逆行列を用いることで連立方程式が解ける、
というのは、逆行列の重要な性質の一つである。
私は辛党なのだが、ケーキ屋さんになったつもりになって、
洋菓子を作るための分量を考えてみることにする。
まず、以下のようなレシピとそれに対応する分量が与えられたとする。
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
このように、総分量を計算するのは至って簡単。
上手くやれば、洋菓子作りの分量計算を自動的にやってくれるソフトも作れる。
まぁ、現実問題として、そういったソフトの需要があるかという問題はあるが。
さて、以上のことが確認できたら、今度は、逆の場合を考えてみる。
すなわち、総分量があったとして、それで作れるお菓子の量を知りたい、
という状況を考えてみる。
薄力粉565g、卵15個、牛乳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 件のコメント:
コメントを投稿