[連載] フリーソフトによるデータ解析・マイニング 第30回

Rと自己組織化マップ

1.自己組織化マップとは

  自己組織化マップ (SOM: Self-Organizing Map) は、コホネン (T. Kohonen) [1]により提案された教師なしのニューラルネットワークアルゴリズムで、高次元データを2次元平面上へ非線形写像するデータ解析方法である。
  自己組織化マップは、入力層と出力層により構成された2層のニューラルネットワークである。出力層は競合層とも呼ばれている。
  今、入力層には分析対象となる個体j の特徴ベクトルをx j ( x j1 , x j2 , … , x jp )、出力層には 個のユニットがあるとする。図1の (a) で示すように、出力層における任意の1つのユニットは、入力層における特徴ベクトルのすべての変数とリンクしている。初期段階では乱数により各変数との間に図1の (b) に示すように重みm i ( m i1 , m i2 , … , m ip ) が付けられている。

自己組織化マップの基本構造

図1 自己組織化マップの基本構造

  SOMのアルゴリズム:

  (1) 入力 と出力層におけるすべてのユニットの中から、最も類似しているユニットmc を探し出し、そのユニットを勝者とする。

SOMのアルゴリズムの式

  (2) 勝者のユニットおよびその近傍のユニットの重みベクトルmi を更新する。更新は下記の式によって行う。

SOMのアルゴリズムの更新の式

SOMのアルゴリズムの更新の式2

式の中のhci(t ) は近傍関数で、ユニット c とその近傍のユニット i の近さによって x j の影響を調整する。式hci (t ) の中のα(t ) は学習率係数で、rcr i はユニットci の2次元上の座標ベクトルである。σ2(t ) はユニット c とニュニッと i の範囲を減少させる関数である。α(t ) は学習回数 (あるいは時間) を変数とする単調減少関数であり、σ2(t ) 座標の分散である。学習回数を変数とする最も簡単な単調減少関数は 単調減少関数 である。この t は学習回数(あるいは時間、1、2、3、…、 T )、T は事前に設定した学習の総回数である。
  (3) すべての入力特徴ベクトル( j = 1 , 2 , … , m ) に対して (1) 〜 (2) を繰り返す。

  SOM は上記のアルゴリズムにより、多次元の空間上の分類対象を2次元平面に射影する。SOM の結果は、出力層の画面に図示される。個体の出力画面のユニットは、格子状 (正方形)、蜂の巣状 (六辺形) などが提案されているが、蜂の巣状が多く用いられている。蜂の巣状というのは、文字どおり蜂の巣のように、正六角形のユニットを並べ、出力層の画面を構成する。出力層の画面は、上述のアルゴリズムにより、似ているもの同士を同じユニット、あるいはその近辺のユニットに配置する。各ユニットの特徴の図示は、星図、エラーバー付きの折れ線、色彩濃淡などソフトによって異なる。

2.パッケージ class

(1) 関数SOM

  パッケージ class の中には自己組織化マップ関数 SOM がある。関数の書き式を次に示す。

SOM(data, grid = somgrid(), rlen = 10000, alpha, radii, init)

  引数 data は解析対象となるデータセットで、ユークリッド距離の計算が可能なデータマトリクスあるいはデータフレームである。
  引数 grid では、関数 somgrid の書き式に従って出力層の指定を行う。関数 somgrid を用いて事前に出力層の構造を設定した場合は、関数 SOM で重複設定する必要はない。
  初心者としては、必ずしも指定しなくてもよい引数 rlen、alpha、radii、init がある。引数 rlen は学習回数で、デフォルトは10000回になっている。引数 alpha は学習率係数で、学習回数に依存する単調減少関数である。引数 radii は学習回数に依存し、近傍領域の半径の更新をコントロールする。引数 init では初期の参考ベクトルを指定するが、指定しない場合はデータセットからランダムに用られる。
  関数 SOM が返す主な結果は、somgrid で設定した出力層のユニットの座標 ($pts)、各ユニットに配置されるデータの特徴ベクトル ($codes) である。
  SOMを実行する前に出力層の設定を行う関数 somgrid の書き式を次に示す。

somgrid(xdim = 8, ydim = 6, topo = c("rectangular", "hexagonal"))

  関数 somgrid では、ユニットの配置方法と出力層のサイズとなる列数 (xdim) と行数 (ydim) を指定する。ユニットの配置方法は引数 topo に "rectangular"、 "hexagonal"の中から1つ選択して指定する。"rectangular"は矩形 (ユニットを格子状に並る)、"hexagonal"は六辺形 (偶数行のユニットを、ユニットの半分のサイズ分ずつ右にずらして並べる) に適した配置方法である。
  SOM の結果の要約は関数 summary、結果の図示は関数 plot を用いる。関数 plot を用いて作成したグラフは、各ユニットに配属される個体の特徴ベクトルの星図である。

2.2 データと解析

  使い慣れたデータ iris のクラス情報を取り除いて用いることにする。関数SOMを用いるためには、まず関数 somgrid を用いて出力層のユニットを設定する。

> gr<- somgrid(topo = "hexagonal", xdim=5, ydim=4)
> out.som<- SOM(iris[,1:4], gr)
> out.som

 $grid
 $pts
x y
[1,]
1.5 0.8660254
[2,]
2.5 0.8660254
[3,]
3.5 0.8660254
[4,]
4.5 0.8660254
[5,]
5.5 0.8660254
[6,]
1.0 1.7320508
[7,]
2.0 1.7320508
[8,]
3.0 1.7320508
[9,]
4.0 1.7320508
[10,]
5.0 1.7320508
[11,]
1.5 2.5980762
[12,]
2.5 2.5980762
[13,]
3.5 2.5980762
[14,]
4.5 2.5980762
[15,]
5.5 2.5980762
[16,]
1.0 3.4641016
[17,]
2.0 3.4641016
[18,]
3.0 3.4641016
[19,]
4.0 3.4641016
[20,]
5.0 3.4641016

$xdim
[1] 5
$ydim
[1] 4
$topo [1] "hexagonal"
attr(,"class")
[1] "somgrid"
$codes

Sepal.Length Sepal.Width Petal.Length Petal.Width
[1,]
5.823119 3.063487 3.720296 1.186965
[2,]
5.823119 3.063487 3.720296 1.186965
[3,]
5.819713 3.094098 3.656770 1.175272
[4,]
6.094287 2.980721 4.343549 1.434295
[5,]
6.755000 3.190000 5.860000 2.275000
[6,]
5.823119 3.063487 3.720296 1.186965
[7,]
5.823119 3.063487 3.720296 1.186965
[8,]
5.863613 3.051739 3.794006 1.194039
[9,]
5.929346 3.071256 3.981252 1.277491
[10,]
5.978135 2.975819 3.993758 1.229022
[11,]
5.863613 3.051739 3.794006 1.194039
[12,]
5.819713 3.094098 3.656770 1.175272
[13,]
5.929346 3.071256 3.981252 1.277491
[14,]
5.743745 3.164111 3.406078 1.033076
[15,]
4.800000 3.400000 1.900000 0.200000
[16,]
5.929346 3.071256 3.981252 1.277491
[17,]
5.929346 3.071256 3.981252 1.277491
[18,]
6.094287 2.980721 4.343549 1.434295
[19,]
5.978135 2.975819 3.993758 1.229022
[20,]
4.900000 3.100000 1.500000 0.100000

attr(,"class")
[1] "SOM"

  このように結果は $pts、$xdim、$ydim、$topo、$codes の項目に分かれている。$pts には指定した20 ( xdim = 5、 ydim = 4 ) の出力層の各ユニットの中心座標値、$xdim、 $ydim、$topo には somgrid で指定した情報、$codes には各ユニットに配属される個体の特徴となるコード情報が格納される。この SOM の結果を関数 plot で図を作成することができる。

> plot(out.som)

irisデータのSOM図1

図2 iris データの SOM 図1

  この図2は、out.som$pts の座標に作成した out.som$codes の星グラフ (stars) である。この図では、各ユニットに配属される個体の特徴の情報が読み取れる。それぞれの星図は、最下段の左から右の方向に out.som$codes の行のデータを昇順に配置したものである。この星図の4つの軸(横右、縦上、横左、縦下)は反時計回りに、それぞれ iris の4つの変数、ガク弁の長さ (Sepal.Length)、 ガク弁の幅 (Sepal.Width)、 花弁の長さ (Petal.Length)、花弁の幅 (Petal.Width) に対応している。
  個体を見やすく、SOM の出力画面に配置させるためには若干の手間が必要である。次のように関数 symbols を用いて、各ユニットを円で図示し (六辺形の代わり)、個体を配置することもできる。

> symbols(out.som$grid$pts[,1:2],circles=c(rep(0.5, 20)),inches = FALSE,add = TRUE)

  個体がどのユニットに配置されるかは、解析したSOMのコードを基準とし判別分析を行わなければならない。ここでは関数 knn を用いて判別を行うことにする。

> haizoku<-as.numeric(knn(out.som$codes,iris[,1:4], 1:20))

  上記のコマンドで得られてる結果 haizoku には、150個の個体がそれぞれどのユニットに配属されるかに関して knn 分類法を用いて判別した結果が格納されている。このデータを直接ユニットに配置すればよいが、値がユニットの番号になっているので、同じユニットに配属される点がすべて重なってしまう。そこで各点の座標値に小さい正規乱数を加え、同じユニットに配属される個体が重ならないように調整する。

> ransu<- cbind(rnorm(nrow(iris),0, 0.15), rnorm(nrow(iris),0, 0.15))
> out.new<-out.som$grid$pts[haizoku,] +ransu
> points(out.new)

  上記の操作で、図3 (a)が作成される。 次のように個体が所属するクラス情報を用いると図3 (b) のように SOM の出力結果の理解と解釈を助ける。クラス情報がない場合は個体の番号を用いることもできる

> points(out.new,col=c(2:4)[unclass(iris[,5])],pch=c(1:3)[unclass(iris[,5])])

irisデータのSOM図2   irisデータのSOM図3

(a) クラス情報を用いていない                  (b) クラス情報を用いている

図3 iris データのSOM 図2

3.パッケージ som

3.1 関数 som

  パッケージ som は、自己組織化マップの専用パッケージで、CRAN ミラーサイトからダウンロードできる。自己組織化マップのメイン関数は som である。その書き式を次に示す。この som は小文字である。

som(data, xdim, ydim,…)

  関数 som には幾つかの引数が用意されているが、ここでは必ず指定しなければならない引数のみを示している。引数dataは、解析の対象となるデータセットである。データによっては、パッケージに用意されている標準化関数 normalize を用いて標準化した方がよい。引数 xdim、ydim は出力画面のユニットの列数と行数である。

 3.2 データと解析

  前節と同じくデータ iris を用いた関数 som の使用例を示す。

> library(som)
> iris.n <- normalize(iris[,1:4])
> iris.som<- som(iris.n, xdim=5, ydim=4)
> plot(iris.som)

  関数 plot のグラフは、エラーバー付きの折れ線でユニットの特徴ベクトルを図示する。各個体をユニットへプロットするためには、前節と類似の手順を踏む。ただし、関数 som は、各個体が属するユニット番号を $visual に記録しているので、前節のように個体の所属を判別するために判別関数を用いる必要がない。実行コマンドおよびその結果を次に示す (図4)。

> ransu<- cbind(rnorm(nrow(iris),0, 0.13),rnorm(nrow(iris), 0, 0.13))
> out.new<- iris.som$visual[,1:2]+0.5+ransu
> points(out.new[,1:2],col=c(2:4)[unclass(iris [,5])],pch=c(1:3)[unclass(iris[,5])])

関数somによる図示

図4 関数 som による図示

  次のように out.new[,1:2] データを用いてユニットの特徴を表示しない散布図を作成することもできる。

> plot (out.new[,1:2],col=c(2:4)[unclass(iris [,5])],pch=c(1:3)[unclass(iris[,5])])

irisのsom散布図(xdim=5、 ydim=4)

図5 iris の som 散布図 (xdim=5、 ydim=4)

  出力層のユニットの数は、結果を大きく左右する。次に iris データについてユニット数を1000個 ( xdim = 100、 ydim = 100) にした結果を示す。

> iris.som2<- som(iris.n, xdim=100, ydim=100)
> out.new2<- iris.som2$visual[,1:2]+0.5+ransu
> plot(out.new2[,1:2],pch=c(1:3)[unclass(iris[,5])],col=c(2:4)[unclass(iris[,5])])

irisのsom散布図(xdim=100, ydim=100)

図6 iris の som 散布図 (xdim=100, ydim=100)

  図5と図6を比較すると、図6における個体がより明確に3種類ごとに分類されていることが分かる。

4.パッケージ kohonen

  パッケージ kohonen のは自己組織化マップの専用パッケージである。このパッケージには教師データありの方法と教師データなしの自己組織化マップに関する関数が用意されている。教師データなしの自己組織化マップの関数は som である。関数の書き式を次に示す。

som(data, grid=somgrid(), rlen = 100,…)

  ここでは指定が必要であるもっとも基本的な引数のみを示している。引数 data は解析対象となるデータセットで、ユークリッド距離の計算が可能なデータマトリクスあるいはデータフレームである。引数 grid では出力層の構造を指定するが、関数 somgrid を用いる。関数 somgrid の書き式を次に示す。

somgrid(xdim = 8, ydim = 6, topo = c("rectangular", "hexagonal"))

  関数 somgrid では、出力層のサイズとなる列数 (xdim) と行数 (ydim)、ユニットの配列の方法(topo)を指定する。ユニットの配置方法は引数 topo に "rectangular"、 と"hexagonal"の中の1つを用いる。"rectangular"はユニットを格子状に並べ、"hexagonal"は蜂の巣状(六辺形)にユニットを並べる。
  som の結果のリストは関数 summary、結果の図示は関数 plot を用いる。関数 plot にはグラフ種類を指定する引数がある。
  ここでは使い慣れたデータ iris のクラス情報をのぞいて用いることにする。関数 som を用いるためには、まず関数 somgrid を用いて出力層のユニットを設定することが必要である。ここでは10列7行の hexagonal 配置法を用いることにする。

> gr<- somgrid(topo="hexagonal",xdim=10,ydim=7)
> iris.som<- som(as.matrix(iris[,1:4]),gr,rlen=200)
> summary(iris.som)
 som map of size 10x7 with a hexagonal topology.
 Training data included;dimension is 150 by 4
 Mean distance to the closest unit in the map:0.04425241

  関数 som の実行結果 iris.som には、somgrid で設定した10×7個のユニットの座標値および出力画面の設定に関する情報が $grid に、ユニットの座標値は $grid$pts に格納されている。各ユニットに配置される個体の特徴となるコードは $codes に、用いたデータのそれぞれの個体がどのユニットに配属されるかに関する情報は $classif に格納される。
  自己組織化マップの主な目的は、高次元のデータを2次元平面上に非線形的に射影し、データのパターン分類を行うことである。パッケージ kohonen では、関数 plot を用いて関数 som の結果を図示することができる。次に関数 plot の書き式を示す。

plot.kohonen(x, type = "",labels=NULL, pchs=NULL, ...)

  引数 type には、いくつかの図示種類が用意されているが、ここでは2種類 (codes, mapping) について紹介する。引数 type = "codes" にすると、用いたデータについて設定した出力画面のユニット特徴の星グラフを表示し、type = "mapping" にするとそれぞれの個体がユニットにプロットされる。次にコマンドの例と結果を図13.2に示す。コードマップと個体のマップを対照することでパターンの特徴を分析することができる。

> plot(iris.som, type="codes")  #コードマップ
> lab.cod<- as.numeric(iris[,5])
> plot(iris.som, type="mapping",labels=lab.cod, col=lab.cod)

irisの変数のsomのマップ

(a)

irisの個体のsomマップ

(b)

図7 SOMのコードと個体のマップ

  コードマップは、各ユニットに配属される個体の特徴の星グラフである。図7 (a) の各ユニットの星グラフの4つの軸は反時計回り方向(横右、縦上、横左、縦下)に iris の4つの変数、ガク弁の長さ (Sepal.Length)、ガク弁の幅 (Sepal.Widt)、花弁の長さ (Petal.Length)、花弁の幅 (Petal.Width) に対応する。

5.その他

  パッケージ klaR の中の作図関数 shardsplot を用いると次のような図が作成される。

> library(klaR)
> iris.som3<-som(iris[,1:4],,xdim=14,ydim=6)
> opar<- par(xpd = NA)
> shardsplot(iris.som3, data.or = iris,label = TRUE)
> legend(3.5,14.3, col = rainbow(3), xjust = 0.5, yjust = 0,legend = levels(iris[, 5]), pch = 16, horiz = TRUE)
> par(opar)

関数shardsplotのSOM図

図7 関数 shardsplot の SOM 図

  SOM は学習データを持たないニューラルネットワークのデータ解析方法である。近年 SOM を扱う本も増えている。初心者には [2]、[3]、より深く追求したい方には[1]、応用に関しては[4]が参考になるであろう。参考文献[4]では、事業戦略管理・マーケティング、経済分析、建設分野、日本語意味マップ、顔画像認証、データベース/情報検索分野、健康診断などの分野での SOM の応用事例が紹介されている。芥川龍之介、菊池寛、夏目漱石、島崎藤村の作品における助詞を用いた SOM による文体分析の研究事例としては[5]がある。

 参考文献:
 [1] T.コホネン著, 徳高 平蔵・その他共訳(2005):自己組織化マップ、シュプリンガー・フェアラーク東京
 [2] 豊田 秀樹(2000):金鉱を掘り当てる統計学―データマイニング入門、講談社
 [3] 山口 和範、高橋 淳一、竹内 光悦(2004):図解入門 よくわかる多変量解析の基本と仕組み―巨大データベースの分析手法入門,秀和システム
 [4] 徳高 平蔵、山川 烈、藤村 喜久郎(2002): 自己組織化マップ応用事例集―SOMによる可視化情報処理、海文堂出版
 [5] 金明哲(2003):自己組織化マップと助詞分布を用いた書き手の同定及びその特徴分析、計量国語学、23巻8号、369-386.