2012/08/09

文系のための「行列の演算」

ここまでの話は、行列に関する基本概念の話であった。
だから、覚えないといけないことも、それなりにあった。

このブログを最初から呼んでいる人の中には、
なぜ、わざわざ「行列」という話から入ったのか、
イマイチ、解らないという人もいるかも知れない。
新しいことなので、そのように思うことがあるかもしれない。

しかしながら、「Σ」が一杯並んだ数式をよりも、
様々な計算が簡略化され、慣れてしまえば意外に楽な事も多い。

以前にも述べたことであるが、多次元データというのは、
ある事象を空間的に布置するという意味がある。
例えば、「人」という事象があって、その事象が、
「慎重」、「体重」、「年齢」、「体脂肪率」という
四つの属性によって定義されていたとする。
すると、この「人」というのは「四次元」の空間に布置できる。

「次元」や「空間」という言葉を聞いて「図形」の話と思ってはいけない。
ただし、多次元データは、空間に布置できる。これが重要。
要するに、人が知覚しやすいように、空間として考えるのである。

なぜ、わざわざ、このようなことを強調しているのか。
理由は、「ベクトル」と「行列」を使うと「空間」に布置された対象の「変換」が楽になる。
例えば、3Dゲームの多くは、視点の変化と三次元オブジェクトの見え方を
瞬時に計算し、それを二次元平面のディスプレイに表示するが、
その処理は、「ベクトル」や「行列」の演算を用いる(ハズである)。

前置きは、この辺りで止めておこう。長くなる。

さて、スカラーにおける四則演算があるように、
ベクトル」や「行列」においても四則演算は存在する。
少々、複雑ではあるが。これを理解しない限りは、先にすすまない。

ということで、まずは、「行列」の「足し算」と「引き算」から始めよう。
これは、それほど難しくはない。手計算もできる。

なお、今回の説明に関しては、あくまで文系向けであって、
厳密には「ベクトル」の足し算ではあるのだが、
理工系の方々で、事情を解っている方々には目をつむってもらえると幸いである。

では、始めよう。サンプルデータを用意し、統計パッケージの「R」で実習する。

最初に、「R」を起動し、以下のコマンドを貼付ける。
貼付けるだけで、まだ、実行してはいけない。
(実行とは、エンターキーを押す事である。)

# Windows と Linuxの場合
shape <- read.table("clipboard", sep = ",")


# Mac の場合
shape <- read.table(pipe("pbpaste"), sep = ",")

貼付けたら、今度は、下のデータをコピーし、
コピーしてから、上記のコマンドを実行する。

x,y
P1,0,0
P2,40,40
P3,40,0
P4,0,0

何もエラーが出なければ問題なく読み込めたハズ。
一連の操作で、shape という変数に行列データが代入された。

なお、Linux の場合は、以下のようなエラーが出るかもしれないが、
データは入る。おそらく、改行コードの問題であろう。

Warning message:
In read.table("clipboard", sep = ",") :
  incomplete final line found by readTableHeader on 'clipboard'

とにかく、shape と入力し、以下のように出力されれば問題ない。

> shape
    x  y
P1  0  0
P2 40 40
P3 40  0
P4  0  0

この程度であれば頭で想像できるが、いや、苦手な人もいるかもしれない。
それはそれで良い。とにかく、「可視化」というものをやってみる。

plot(shape, type="b")

とする。要するに、shape という変数が入ったデータを「プロット(布置)」する。
plot()関数は、様々なデータを布置して可視化するための関数である。
type = "b" というのは、表示方法のパラメータ(引数)であり、
線(line)と点(point)の両方(both)を表示するという指定である。
なるほど、英語の最初の一文字を使っているのである。
したがって、線のみで表示したい場合には type = "l" とし、
点のみで表示したければ、type = "p" とすれば良い。

問題が無ければ、以下のような図が表示されるはずである。
もっと複雑な形状でも構わないのだが、
モノグサな私には大掛かりな準備が億劫であったので、
このようなシンプルな図形にしてみた。
図形の想像もしやすいので、これで良いことにする。
さて、今回のテーマである行列の「足し算」と「引き算」というのは何か?
図形として考えると、足し算と引き算は、空間上の「移動」に相当する。
例えば、GISや地図ソフトの水平移動の機能は、内部的にこの計算を行っている。

行列の「足し算」と「引き算」というのは、直感的に理解しやすい。
おそらく、一回説明を聞けば誰でも理解できる。
ようするに、「同じサイズ」の2つの行列を準備し、
同じ場所にある要素同士を足したり、引いたりするだけ。

ここで重要なポイントは、同じサイズの行列同士でしか出来ない、
ということである。


例えば、x軸方向に10移動し、y方向に15移動する。
中学校までの知識では、以下のようになる。

P1(x,y)=(0 + 10, 0 + 15)
P1(x,y)=(40 + 10, 40 + 15)
P3(x,y)=(40 + 10, 0 + 15)
P4(x,y)=(0 + 10, 0 + 15)

確かに、そのようであった。
これを、「行列」を使って表現すると、以下のようになる。



どういう計算であるか、見れば分かる。
2つの同じサイズの行列があって、
同じ場所にある、要素同士を足しているだけである。
これが、空間上の操作であると考えると、「移動」に相当する。

では、本当にそのようになるのか、実際に「R」を使って計算してみる。
とりあえず、加える行列を作ってみる。

A <- matrix(c(10,10,10,10,15,15,15,15), nrow=4, ncol=2)

どういう行列かと言うと、

> A
     [,1] [,2]
[1,]   10   15
[2,]   10   15
[3,]   10   15
[4,]   10   15

では、実際に計算してみる。

> shape + A
    x  y
P1 10 15
P2 50 55
P3 50 15
P4 10 15

ふむ。予想通りの結果となった。
要するに、各要素に足し算を行なっているだけである。
どういう図形になっているかを確認する。

plot(shape + A, type="b")

一見すると、最初の図と変わっていないように見えるが、
原点位置を確認してみると、移動していることがわかる。
試しに、2つの図を重ねてみる。以下をコピー・アンド・ペースト。

plot(shape + A, type="b", col = "blue", xlim = c(0,60), ylim = c(0, 60))
par(new=TRUE)
plot(shape, type="b", col = "red", xlim = c(0,60), ylim = c(0, 60))

すると、以下のようなプロットが出てくる。
赤い方が、shape をプロットしたものであり、
青い方が、shape + A をプロットしたものである。
卒倒する人もいるかもしれない。一行目のコマンドを確認してみる。
plot()関数 は、色々と任意のパラメータを加えることができる。
まず、col = "blue" のところで、出力結果を「青色」で表示させ、
xlim = c(0, 60) の部分で、x軸の最小値と最大値を決めている。
同様に、ylim = c(0, 60) でy軸の最小値と最大値を決めている。
xlimylim を設定しない場合、最初の図の表示範囲に依存するので、
いずれかの図が、はみ出てしまうのである。

ついでに、「引き算」もやってみる。次のような状況を考える。
x軸方向は、マイナス方向に20、
y軸方向は、マイナス方向に10、移動するような計算。

足し算」と同様に、「同じサイズの行列を準備し、
元の行列から別の行列を引く。



この処理は以下のようになる。


B <- matrix(c(20,20,20,20,10,10,10,10), nrow=4, ncol=2)


plot(shape, type="b", col = "red", xlim = c(-20,40), ylim = c(-10, 40))
par(new=TRUE)
plot(shape - B, type="b", col = "blue", xlim = c(-20,40), ylim = c(-10, 40))

同様に可視化してみる。すると、次のようになる。

行列の足し算は、大して難しいものではない。
次は、「掛け算」の話が必要なのだが、それは少々複雑である。

3 件のコメント:

  1. はじめまして。先日こちらのブログを発見し、勉強させていただいています。上記の plot(shape, type="b")を実行すると
    以下にエラー plot.default(...) :
    仮引数 ”type” が複数の実引数にマッチしました
    というエラーが出てしまいます・・・。pにしてもlにしても同様のエラーが出ます。とくに関数を割り当てたりはしていなのですが・・・。どのようにすれば解決できるのでしょうか?本筋からはずれてしまいますが、ご教示いただけますと幸いです。

    返信削除
    返信
    1. コメントありがとうございます。勉強のお役に立てれば幸いです。

      さて、上記コマンドの部分、私の方でも確認してみましたが、問題無く動くようです。
      ひょっとしたら、「shape」の変数に、データが上手く入っていないのかもしれません。
      Rコンソール上で、単に「shape」と入力したときにデータは表示されるでしょうか?

      あるいは、何かの変数が邪魔をしているのかもしれません。
      まず、「rm(list=ls(all=TRUE))」を実行し、Rを再起動してください。
      上記のコマンドは、Rの内部に保存されている変数を一度クリアにするコマンドです。

      再起動の後、もう一度、read.table()関数でデータを読み込みしなおしてください。
      この時、コピペの順番に注意してください。先に、read.table()関数を貼り付け、
      「実行せずに」x,yのデータをコピーし、Rのコンソールでread.table()を実行してください。

      あとは、可能性として「"(ダブルクォーてション)」の付ける位置の間違いや、
      「,(カンマ)」の位置の打ち間違いという可能性もあります。
      一度、上記の方法を試してみてください。

      削除
  2. 「慎重」→「身長」

    返信削除