2012/08/07

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

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

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

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

では、いかにして計算するのか?実は、結構大変。手計算はしたくない。
次元数と対象数が増えるとさらに大変。逆行列が存在しないこともあり得る。
これは、非常に厄介なことである。

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

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

ということで、「R」をダウンロードしてインストール。
このソフトは無料でオープンソースのソフトウェア。タダで使える。
インストールが完了したら起動する。

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

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

コピーすると、コンピュータ上では一時的にデータが保持される。
一般的には「クリップボード」と呼ばれている。
なお、Win Linux、Macで方法が異なる。

まず、WindowsLinuxの人は以下のコマンド…

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

次に、Mac の人は以下のコマンド…

X <- read.table(pipe("pbpaste"), header = FALSE, sep = ",")
X <- as.matrix(X)

コピーした状態で、以下のコマンドを入力し、エンターキーを押下する。
二行目のコマンドは「型変換」に関するコマンド。
データフレーム型(dataframe)」から「行列型(matrix)」に変換される。

今は、ちょっとした呪文だと思えば良い。
見た目には何の変化も無いのだが、
これをしないと、後にエラーが出る。

Linux の場合は以下のようなエラーが出るが、改行コードの問題。気にしない。
それ以外のエラーメッセージが出なければ大丈夫。
英語が苦手な人は卒倒するかもしれないが、慣れれば大丈夫。

incomplete final line found by readTableHeader on 'clipboard'

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

> 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

ふむふむ。どうやら上手くいったようである。
さて、元の行列に対して逆行列を掛けるとどうなるのだったか?
あるスカラー数にその逆数を掛けると「1」となるが…行列の場合は?

> 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

一応、おさらい。Rでは通常の掛け算には「*」を使い、
ベクトルと行列の掛け算では「%*%」を使う。
今回は行列の掛け算なので「%*%」を使っている。

さて、話を元に戻して、この出力結果を観察してみる…。

対角線上は、確かに「1」が並んでいる。それ以外のところは...何だコレ!?
慌ててはいけない。とりあえず、一列目の二行目の値を見てみる。
これは「指数表記」と呼ばれる数値の表記方法。Excelでも時々見かける。

 -4.440892e-16

つまり、-4.440892 の 10 の -16乗 という意味である。
ようするに、ほぼ「0」である。計算誤差分が出ているのである。
試しに、小数点(digits)を第7位までで丸め込んでみると…。

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

round()関数は小数点を丸め込むための関数。行列に対しても実行できる。

> round(X %*% solve(X),digits=7)
     [,1] [,2] [,3] [,4]
[1,]    1    0    0    0
[2,]    0    1    0    0
[3,]    0    0    1    0
[4,]    0    0    0    1



要するに対角成分以外は「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」なので、
同様に、「単位行列」が出ていることがわかる。
一応、先ほどと同様にround()関数で丸め込む。




> round(solve(X) %*% X,digits=7)
   V1 V2 V3 V4
V1  1  0  0  0
V2  0  1  0  0
V3  0  0  1  0
V4  0  0  0  1

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

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

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

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 件のコメント:

コメントを投稿