2012/08/07

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

このブログでは、如何にして中学校までの知識で、
定量的な解析をある程度理解して行うか、というの課題。
とは言え、中学校の知識だけでは何ともならない。

例えば、「割り算」という考え方は、
実は、「逆数を掛ける」ということであって、
こういった考え方の切り替えは出来なければならない。
中学校までの知識と矛盾するわけではないのだが、
観点を変えるということは重要なことなのである。

さてさて、最初から話が逸れてしまった。
そうだ、ここでは「逆行列」の話をするのだった。
「逆行列」とは、スカラーにおける「逆数」に対応し、
したがって、概念的には「割り算」に近いものであった。

では、いかにして計算するのか?実は、これは非常に難しい。
次元数と対象数が増えると、手計算では不可能に近い。
また、逆行列が存在しない、ということもあり得る。
これは、非常に厄介なことである。

最近の計算機は凄いのである。いわゆる、電卓のことではない。
一般的には、パソコンとかPCなどと呼ばれているものである。
何が凄いのか?逆行列を一瞬で解いてくれる。素晴らしい。

ここでは、「R」というオープンソースの数値計算パッケージを使う。
何でもやってしまう、魔法のソフトである。使いこなせれば、何でもできる。
空間分析とか、テキストマイニングとか、画像処理とか、本当に何でも。

とりあえず、以下のようなデータを準備する。
意味はないが、語呂合わせになっている。どうでも良いが。
とにかく、コピーする。

6, 3, 4, 0
9, 9, 4, 8
6, 4, 9, 1
4, 6, 4, 9

まずは、データを読み込む。Win Linux、Macで方法が異なる。
なお、二行目のコマンドは、ちょっとした呪文である。
見た目は、何の変化も無いのだが、
「データフレーム型」から「行列型」に変換されている。
これをしないと、後にエラーが出る。

## Windows と Linux
X <- read.table("clipboard", header = FALSE, sep = ",")
X <- as.matrix(X)



## Mac OS X(10.6 以上は以下で動作)
X <- read.table(pipe("pbpaste"), header = FALSE, sep = ",")
X <- as.matrix(X)


エラーメッセージが出なければ大丈夫。
ただし、Linux の場合は以下のようなエラーが出るが、
データは、ちゃんと入っているようである。

incomplete final line found by readTableHeader on 'clipboard'

Rでは、逆行列を solve() 関数を用いて求める。
実際に、計算してみると次のようになる。


> solve(X)
          [,1]        [,2]       [,3]        [,4]
V1  0.78425656 -0.32361516 -0.3498542  0.32653061
V2 -1.15743440  0.76384840  0.5014577 -0.73469388
V3 -0.05830904 -0.08746356  0.1486880  0.06122449
V4  0.44897959 -0.32653061 -0.2448980  0.42857143

ふむふむ。どうやら上手くいったようだ。
元の行列に対して、逆行列を掛けるとどうなるのだったか?

> X %*% solve(X)
              [,1]          [,2]          [,3]         [,4]
[1,]  1.000000e+00 -1.665335e-16 -3.330669e-16 3.053113e-16
[2,] -4.440892e-16  1.000000e+00  0.000000e+00 0.000000e+00
[3,]  5.551115e-17 -1.110223e-16  1.000000e+00 2.775558e-16
[4,] -4.996004e-16  3.885781e-16  4.718448e-16 1.000000e+00

対角線上は、確かに「1」が並んでいる。
それ以外のところは...何だコレ!?

慌ててはいけない。とりあえず、一列目の二行目の値を見てみる。

 -4.440892e-16

つまり、-4.440892 の 10 の -16乗 という意味である。
ようするに、ほぼ「0」である。計算誤差分が出ているのである。
したがって、以下のように、入力すると、

> round( -4.440892e-16, digits = 7)
[1] 0

小数点第7位まで取っても「0」である。限りなく「0」。
したがって、元の行列に「逆行列」を掛けると、
対角成分がすべて「1」であり、他がすべて「0」であるような、
そういう「対角行列」が出てきたのである。

では、そういう「対角行列」のことを何というのだったか?
確か、「単位行列」というのだった。確かに、定義通りである。

もうひとつ実験をしてみよう。今度は、掛け算の順番を変えてみる。
すると、以下のようになる。

> solve(X) %*% X
              V1            V2            V3            V4
V1  1.000000e+00  1.110223e-16  0.000000e+00  1.665335e-16
V2 -4.440892e-16  1.000000e+00  4.440892e-16 -1.110223e-16
V3 -1.387779e-16 -4.163336e-17  1.000000e+00  1.040834e-16
V4 -2.220446e-16  1.110223e-16 -2.220446e-16  1.000000e+00

ふむふむ。計算誤差の部分が若干違うが、実質的には「0」なので、
同様に、「単位行列」が出ていることがわかる。

一般的に、行列の掛け算は、順番が変わると答えが変わるのだが、
逆行列の場合は、順番が入れ替わっても良いのである。
この性質は、頻繁に利用されるので覚えておく必要がある。

最後に、データを少し変えてみる。一行追加。オハヨー!

6, 3, 4, 0
9, 9, 4, 8
6, 4, 9, 1
4, 6, 4, 9
0, 8, 4, 0

そして、同様に計算してみる。どうなるか?


> X <- as.matrix(X)
> solve(X)
Error in solve.default(X) : only square matrices can be inverted

何か、エラーらしきものが出て、計算ができない。
エラーメッセージは多くの場合、有益な情報である。
要するに、以下のように書いてある。

solve.default(X) でエラーが出た: 正方行列のみ逆にすることができる。

つまり、solve()関数では、正方行列しか逆行列が出せないのである。
これはバグではない。そもそも、逆行列というのは、
正方行列でしか計算できないのである。

これは、少々厄介なのである。実際の多次元データでは、
むしろ、正方行列であることの方が少ないのである。
では、どうすれば良いのか?

結論から言うと、ある特殊な「分解」を行い、
ちょっとした操作をすることで、
逆行列を計算することができるのである。

その分解とは、「特異値分解」と呼ばれるものである。
「特異値分解」の解説は、別途設けてあるので、
次に進む前に、目を通しておくことをおすすめする。

http://cis-jp.blogspot.jp/2012/08/blog-post_4.html

0 件のコメント:

コメントを投稿