【Rによるデータサイエンス】多次元尺度法(つづき) 非軽量MDS

【Rによるデータサイエンス】多次元尺度法」の続き。

前回は、多次元尺度法とは何かから初めて、計量MDSまで練習した。
今回は、計量MDSについてメモする。

非計量MDSは、距離の性質を満たさない類似性データも視野に入れ、計量MDSを発展させたもの
非計量MDSでは、個体間の類似度あるいは距離をもとに配置すべくk次元における距離を推測する。

なんとなく言っていることは分かるけど、じゃあ「類似度」って何?「距離」って何?と思うわけ。何をもって、2つのものが類似していると見なすのか。

ネットで調べたら良い資料があった!同じ本を読んでいる。このシリーズ、かなり( ・∀・)イイ!!

いい資料があるから、ここで同じことをやっても仕方ないといえば仕方ないのはわかっているけど、同じことでもやった感を出して自分のモチベーションを高めることが1つの目的なので実際にやってみるw。

【非計量的MDSのケーススタディ
◎isoMDS関数を使う
入力は距離行列と次元とする。
出力は、座標値($points)と最終のストレス($stress)。

使う前に距離の求め方の確認。
例えば、
\begin{pmatrix}1 & 3 \\5 & 12 \end{pmatrix}
という2次の正方行列を考える。
これに対してdist関数を使用すると、各行ベクトルのユークリッド距離を求めることができる。

> tmp
[1]  1  3  5 12
> mat<-matrix(tmp, nrow=2,ncol=2,byrow=TRUE)
> mat
     [,1] [,2]
[1,]    1    3
[2,]    5   12
>  distMat<-dist(mat)
> distMat
         1
2 9.848858

dist実行結果として、9.848858という値が求められたが、これは行ベクトル(1,3)と(5,12)のユークリッド距離に等しい。

> sqrt((5-1)^2+(12-3)^2)
[1] 9.848858

ちなみに、dist関数のオプションを指定して、行列で表示すると次のようになる。

> distMat<-dist(mat,diag=FALSE,upper=TRUE)
> distMat
         1        2
1          9.848858
2 9.848858         
> distMat<-dist(mat,diag=TRUE,upper=TRUE)
> distMat
         1        2
1 0.000000 9.848858
2 9.848858 0.000000

さて、このデータでisoMDSを使ってみる。意味は無いけど。。。

> isoMDS(distMat,k=2)
 以下にエラー cmdscale(d, k) : 'k' must be in {1, 2, ..  n - 1}
> isoMDS(distMat,k=1)
initial  value 0.000000 
final  value 0.000000 
converged
$points
          [,1]
[1,] -4.924429
[2,]  4.924429

$stress
[1] 0

この結果の$pointsは座標値で、これはdistの2分の1の値。
で?そういった考察はもう少し慣れるまで、とりあえず据え置き。。。

◎sammon関数を使う
sammon関数はisoMDS関数と使い方は基本的に同じ。
ストレス($stress)は百分率ではない
isoMDSもsammonも、初期に与えた座標を初期として、用いたストレス統計量が最小になるように計算を繰り返す。sammonでは100、isoMDSでは50が繰り返し数のデフォルト値となっているらしい。

> sammon(distMat, k=1)
Initial stress        : 0.00000
stress after  10 iters: 0.00000, magic = 0.500
$points
          [,1]
[1,] -4.924429
[2,]  4.924429

$stress
[1] 0

$call
sammon(d = distMat, k = 1)

◎metaMDS関数を使う
パッケージmlbenchの中の関数mlbench.cornersを用いて、複数クラスの多次元(d)ガウシアン球面形の人工データを生成する。

> install.packages("mlbench")
> library(mlbench)
> install.packages("e1071")
> set.seed(100)
> p<-mlbench.corners(n=160)
> lab=as.numeric(p$classes)
> x.dist<-dist(p$x)
> library(MASS)
> par(mar=c(4.5,4.5,1,1), mfrow=c(2,2))
> plot(cmdscale(x.dist),pch=lab,col=lab)
> plot(sammon(x.dist)$points,pch=lab,col=lab)
Initial stress        : 0.09075
stress after  10 iters: 0.07876, magic = 0.092
stress after  20 iters: 0.06195, magic = 0.500
stress after  30 iters: 0.06164, magic = 0.014
stress after  40 iters: 0.06157, magic = 0.500
> plot(isoMDS(x.dist)$points,pch=lab,col=lab)
initial  value 25.145154 
iter   5 value 23.437529
iter   5 value 23.421336
iter   5 value 23.421336
final  value 23.421336 
converged

> install.packages("vegan")
> x.dist2<-as.matrix(x.dist)
> plot(metaMDS(x.dist)$points,pch=lab,col=lab)
> install.packages("vegan")
> library(vegan)
 要求されたパッケージ permute をロード中です 
 要求されたパッケージ lattice をロード中です 
This is vegan 2.0-10
> plot(metaMDS(x.dist2)$points,pch=lab,col=lab)
Run 0 stress 0.2339668 
Run 1 stress 0.4154951 
Run 2 stress 0.242835 
Run 3 stress 0.2465906 
Run 4 stress 0.2406426 
Run 5 stress 0.239285 
Run 6 stress 0.239285 
Run 7 stress 0.239285 
Run 8 stress 0.236982 
Run 9 stress 0.2339668 
... New best solution
... procrustes: rmse 1.280621e-05  max resid 6.089163e-05 
*** Solution reached