sonoshouのまじめなブログ

情報系大学生からのウェブ見習い人生の記録

自己組織化写像をprocessingで実装する。 part.1

はじめに

研究室の勉強会でこのたび自己組織化写像を実装することになった。
というわけで、自己組織化写像の実装過程をブログに書こうかなーっと。
久しぶりの更新で気合が入りますね!

自己組織化写像とprocessing

今回は実装にprocessingを選ぶことにしました。
自己組織化写像は教師なし学習の機械学習の一種です。
自己組織化写像は、自己組織化マップSOMと呼ばれることも多いですので、
こちらも合わせて覚えておきましょう。
機械学習は普段ならRかpythonで実装するのだけど、今回はビジュアル重視ということで、グラフィック機能に特化した言語であるprocessingを採用してみました。
wikipedia:自己組織化写像
wikipedia:processing
自己組織化写像ここでの限定的な意味として簡単に申し上げますと、
高次元のデータを(人間が見やすいように)2次元にビジュアライズする手法です。
……と言ってもイメージしづらいと思いますので、以下のページをご参照下さい。
次回以降のエントリーでも同様の問題を扱い実装していく予定です。
勝手に整理整頓:http://gaya.jp/spiking_neuron/som.htm

バッチ型学習SOM

自己組織化写像にはたくさんのバリエーションがあります。
これについては上述の自己組織化写像Wikipediaページが詳しいです。
自己組織化写像ののバリエーションを大きく分けると、
1. 逐次型学習SOM
2. バッチ型学習SOM
の2種類があります。
本来ならば、データのビジュアライズを目的とする場合、
バッチ型学習SOMを採用すべきなのですが、
今回は簡単のため、逐次型の自己組織化写像を実装することにします。

その他、自己組織化写像については以下のページが詳しいです。
“データマイニング用SOM”,マインドウエア総研:
http://www.mindware-jp.com/basic/faq2.html

processing

processingについてはあまり触れませんが、簡単さだけはお伝えしたいなと思いまして。 processingはグラフィックに特化された言語だと上述しましたが、
どの程度楽なのか、一つ例を出そうと思います。

int i = 0;

void setup()
{
  size(200,200);
}

void draw()
{
  rect(0,0,100+i,100+i);
  i++;
}

f:id:sonoshou:20130618195021p:plain

これは200✕200のウィンドウの中に、
左上から右下へ四角形を(重ねながら)大きくしていくアニメーションプログラムです。

setup()はプログラムが始まって1回だけ実行され、
その後はdraw()が絶え間なく実行されます。

これにより、左上から少しずつ大きくなる四角形を描写することが可能です。
ただし、前の四角形を消すプログラムを書いていないので、
どんどん四角形を重ねていることになります。

このように、processingは簡単にグラフィック、アニメーション処理のプログラムを書くことが可能です。

さっそく書いてみる

processingのインストールは簡単なので省略っと……。
今回は1マスが六角形の自己組織化写像を実装する予定です。

まずは、ハニカム構造を書いてみることにしました。

void setup()
{
size(800, 800);

  for (int i = 0; i < 28; i++)
  {
    for (int j = 0; j < 25; j++)
    {
      if (i % 2 == 0)
      {
        hexagon(j * 34.64102, i * 30, 20, color(255,255,255), color(0, 0, 0));
      } else {
        hexagon(j * 34.64102 - 17.32051 , i * 30, 20, color(255,255,255), color(0, 0, 0));
      }

    }      
  } 
}

void draw()
{

}

// hexagon
void hexagon(float centerX, float centerY, float size, color fillColor, color strokeColor)
{
  final float COS[] = {0, -0.8660254, -0.8660254, 0, 0.86602524, 0.86602524};
  final float SIN[] = {1, 0.5,  -0.5, -1, -0.5, 0.5};

  final float RADIUS = size;

  // color
  fill(fillColor);
  stroke(strokeColor);

  beginShape();
  for(int i = 0; i < 6; i++)
  {
    float tx = COS[i] * RADIUS + centerX;
    float ty = SIN[i] * RADIUS + centerY;
    vertex(tx, ty);
  }
endShape(CLOSE);
}

以上がプログラムの全貌です。
実行結果は以下の通りになります。

f:id:sonoshou:20130618195151p:plain

draw()関数の中身について簡単に補足します。
……といっても特に特殊なことはしていませんね。

if (i % 2 == 0)

実行結果をご覧頂けると理解が早いのですが、
ハニカム構造は奇数行と偶数行(縦)で互い違いになっていることがわかります。
従って、偶数回目のループかどうかを判定して、処理を分けています。

hexagon(j * 34.64102, i * 30, 40);
hexagon(j * 34.64102 - 17.32051 , i * 30, 40);

以上が六角形を書くプログラムです。
hexagon()は、X座標とY座標と一辺の長さ、塗りつぶす色、枠線の色を与えると、
任意の場所に指定した六角形を書くことができる関数です。
こちらのページを参考にしました。
Processingで五角形・六角形・ハート形を描く:http://blog.p5info.com/?p=28

34.64102は20ルート3、17.32056は10ルート3にあたります。
二重ループを使ってうまーく六角形を書く場所を調整すると、このようになります。

次回に続きます。
続き書きました!
自己組織化写像をprocessingで実装する。 part.2