読者です 読者をやめる 読者になる 読者になる

sonoshouのまじめなブログ

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

図でわかる 因子分析

因子分析について勉強しました。
読み手を意識したのですが、
記事の質が上がらず、結局自分用メモ記事&本の紹介ですね……。

因子分析の理論はひとまず置いて、考え方だけでも抑えましょう!   本当は自分で試したかったのですが、修論ちゃんが(言い訳)

ネタ元は以下の本。
題名にもある通り、非常にさらっと読めました。

マンガでわかる統計学 因子分析編

マンガでわかる統計学 因子分析編

因子分析の目的

因子分析とは、データの背後に潜む説明変数を見つけ出す手法。
仮説を立ててから適用する手法。

主成分分析と因子分析の違い

主成分分析と対応付けして覚えるとわかりやすい。

目的変数と説明変数は良いですかね?
目的変数が説明変数によってどれだけ説明できるかが重要でしたね。

主成分分析

f:id:sonoshou:20131130172438p:plain

主成分分析は、いくつかの説明変数から(説明変数の数より少ない)目的変数を求める分析手法でした。
モデルを表す変数が減るので、主成分分析は次元削減ができるというわけですね。
このとき、説明変数が与えられたデータで定義される変数で、
目的変数が主成分分析で求める変数であることに注意して下さい。

因子分析

f:id:sonoshou:20131130172505p:plain

一方、因子分析は、目的変数から説明変数を求める分析手法です。
主成分分析とは異なり、
目的変数が与えられたデータで定義される変数で、
説明変数が因子分析で求める変数です。
すなわち、因子分析は、与えられたデータから原因となった(と考えられる)変数を求める分析手法です。

因子分析の例

国語、数学、英語、理科、社会の5教科のテストについて考えましょう。
各々の教科で国語○○点、数学○○点、…と与えられているので、
変数が5つ、5次元のデータとなります。

これらのデータを観察し、
文系能力と理系能力があると仮定したとしましょう。
(この仮定はデータを観察して考えます。
 ただし、もちろん因子がない場合もあるので注意しましょう!)

このようなデータがあった場合、
因子分析の図は以下のようになります。

f:id:sonoshou:20131130172543p:plain

アンケート調査の注意点

アンケートを作成する上で気をつけるべき点

何かしらの実態を調査する上で、もしくは、研究をする上で、
アンケートを行うことがあると思います。
このとき、最低限気をつけるべき点をまとめました。

ネタ元は以下の本。
題名にもある通り、非常にさらっと読めました。

マンガでわかる統計学 因子分析編

マンガでわかる統計学 因子分析編

アンケートの順序

アンケートの順序は軽視しがちですが、
より多くのアンケートを集めるために工夫すべき点がいくつかあります。
(被験者実験等、必ずアンケートを集められる場合には気にしなくても良いかも?)

1. 「実態」を訊く
 ~をやったことはあるか・~を持っているかなど。
 いつ買ったかどこで買ったかなど。

2. 「意識」を訊く
 満足or不満な点、満足or不満な理由
 その他、価値観など

3. 「属性」を訊く
 性別・年齢・未婚既婚・収入
 最終学歴・家族構成など

いきなりアンケート者の「属性」を聞くと、
どうしても相手が身構えてしまう……。
そこで、先に「実態」や「意識」を聞いた後に、
「属性」を持ってくると、
せっかくだからと最後まで書いてくれる人が多くなる。

アンケートの悪い質問・チェック事項

  • かなり個人的なことを具体的に訊く。(年収を自由記述など)
  • 表現があいまいである。
  • 2つ以上の意味を有している。
  • 順位をつけさせる。
  • 回答を誘導している質問
  • 段階が多すぎる質問
  • 点数をつけさせる質問(0点や10点をどう解釈すべきか迷う。)
  • 自由回答を募る質問

順位をつけさせる&自由回答を募る質問

特にやってしまう(と思われる。主に自分が。)
2つについてさらに詳しく記述します。

順位をつけさせる質問

なぜ、「順位をつけさせてはいけないのか」の説明から始めます。

Q.好きな料理は何ですか?次の選択肢から順位をつけて下さい。
A.「ハンバーグ」「カレーライス」「牛丼」「うどん」「焼きそばパン」

というアンケートを作成したとします。

この場合、アンケート者は、
「ハンバーグと牛丼が好きだけど、他の3つはどうでも良いな……。」
と、特定の順位はつけられるけど、他の選択肢については順位をつけづらいという場合があるかもしれません。
また、順位をつけるという作業は大変なので、アンケート者に大きな負担を与えます。

こういったアンケートを作る時は、

Q.好きな料理は何ですか?好きな料理を選択して下さい。
A.□「ハンバーグ」 □「カレーライス」 □「牛丼」 □「うどん」 □「焼きそばパン」

というアンケートを作成しましょう。

これらのアンケートを集計すれば、どの料理がどれだけ選ばれたかで
順位付けをすることができます。

自由回答を募る質問

自由回答は、被験者に大きな負担を与えます。
何も書いてもらえないという場合が増えてしまうでしょう。

そこで、本番の調査で自由回答を募る前に、
出来る限り予備調査で自由回答を募り、
予備調査の回答のトップ5を選択肢化して、
本番の調査に臨みましょう。

サポートベクターマシンを勾配法で解く。

最も代表的な教師あり分類手法の一つであるサポートベクターマシン
訓練サンプルから、各データ点との距離が最大となるマージン最大化超平面を求めるという明確な分類基準がある、かつ、一見求めづらそうなこの超平面を一意に求められるということから
数学的に美しい分類手法と言えるでしょう。
サポートベクターマシンの詳しい説明はこちらになります。
サポートベクターマシン - Wikipedia

さて、上のWikipediaの記述にもある通り、
マージン最大化超平面は最適化問題の凸二次計画問題となります。
今回は、この凸二次計画問題を勾配法で解くことで、
ハードマージンのサポートベクターマシンを実装しました。

使用したデータ

線形分離可能なデータです。

f:id:sonoshou:20131113113715p:plain

また、こちらの座標関係をテキストデータにしたものがこちらです。 各行がデータを表しており、スペースで区切られています。
左から、X座標、Y座標、クラス(1or-1)となります。

1 2 1
0 1 1
-1 2 1
2 1 1
3 5 1
0 -1 -1
-1 -2 -1
-2 0 -1
-4 0 -1
-3 -3 -1
(data/svm_hard_data.txtの中身。プログラム中で使用。)

実装したコード

本記事のプログラムは
線形SVM - 人工知能に関する断創録
を大いに参考にしました。
言語はpythonです。

作成したプログラム

#coding:utf-8

import numpy as np
from pylab import *

LR = 0.05    # 学習率
C = sys.maxint    # Cを無限大に設定
CountMax = 1000   # 1000回更新

def f(x1, w, b):
    return - (w[0] / w[1]) * x1 - (b / w[1])

def kernel(x, y):
    return np.dot(x, y)  # 線形カーネル

def dL(i):
    ans = 0
    for j in range(0,N):
        ans += L[j] * t[i] * t[j] * kernel(X[i], X[j])
    return (1 - ans)

if __name__ == "__main__":
    data = np.loadtxt("data/svm_hard_data.txt")
    N = data.size / 3                   # 教師データ数
    X = np.delete(data,2,1)             # 入力の座標
    X = np.c_[X,np.ones(X.shape[0])]    # 入力の空間を1次元拡張
    t = np.array(data[:,2])             # 入力のラベル
    L = np.zeros((N,1))                 # データの個数分のラグランジュ乗数

    count = 0
    while (count < CountMax):
        for i in range(N):
            L[i] = L[i] + LR * dL(i)    # ラグランジュ乗数の更新
            if (L[i] < 0):
                L[i] = 0
            elif (L[i] > C):
                L[i] = C
        count += 1

    for i in range(N):
        print L[i]

    # サポートベクトルのインデックスを抽出
    S = []
    for i in range(len(L)):
        if L[i] < 0.00001: continue
        S.append(i)

    # wを計算
    w = np.zeros(3)
    for n in S:
        w += L[n] * t[n] * X[n]

    # wの3次元目は拡張次元のbとなる。
    b = w[2]
    np.delete(w, 2, 0)

    # 訓練データを描画
    for i in range(0,N):
        if(t[i] > 0):
            plot(X[i][0],X[i][1], 'rx')
        else:
            plot(X[i][0],X[i][1], 'bx')

    # サポートベクトルを描画
    for n in S:
        scatter(X[n,0], X[n,1], s=80, c='y', marker='o')

    # 識別境界を描画
    x1 = np.linspace(-6, 6, 1000)
    x2 = [f(x, w, b) for x in x1]
    plot(x1, x2, 'g-')

    xlim(-6, 6)
    ylim(-6, 6)
    show()

出力結果

f:id:sonoshou:20131113114959p:plain

黄色の○で囲まれている座標がサポートベクトルです。 また、このときのラグランジュ乗数は以下になります。

[ 0.]
[ 0.625]
[ 0.]
[ 0.]
[ 0.]
[ 0.375]
[ 0.]
[ 0.25]
[ 0.]
[ 0.]

このように、サポートベクトル以外のラグランジュ乗数が0になっていることが確認できます。

理解に必要な数学

  • 勾配法
  • ラグランジュ乗数
  • クーン・タッカー条件
  • 特徴空間を1次元拡張(バイアスを固定)

以上です。
これらが理解できていれば、今回のコードの理解もできるでしょう。

ただ、余談ですが、これらの数学的理論についてのわかりやすい説明が身近にないように感じています。
どれも幾何学的に説明すれば、理解が容易だと思うのですが……。
が、図を書くのって正直面倒ですよね、わかります。
本当はこれら3つの数学的理論についても説明したいのですが、
私も泣く泣く割愛致します。

勾配法によるSVM

まずは、参考文献を掲載します。

サポートベクターマシン入門

サポートベクターマシン入門

こちらの本に勾配法よるSVMの実装の詳細が書かれています。

大枠はこちらの本による説明に任せるとして、
今回は勾配法によるSVMの肝となる処理であるたった1行だけを軽く触れます。

L[i] = L[i] + LR * dL(i)    # ラグランジュ乗数の更新

となっています。

参考までに、式を載せておきます。

f:id:sonoshou:20131113125208p:plain

あとはこの式に従って、ひたすら(サンプルだと1000回)回すだけで、
マージンが最大化となる超平面を求めることができます。

数学的に美しいですよね。素晴らしいです。

流山市WEBアプリコンテスト

ぐるっと流山 WEBアプリコンテスト|流山市
に参加してきました!
千葉県流山市のオープンデータを題材にした
WEBアプリコンテストです。

このコンテストは、WEBアプリのアイデアのみを競う部門と
プログラミングをしてWEBアプリを作成する部門の2つがあります。

私は残念ながら、入賞することはできませんでしたが、
地元の流山を題材にしたアプリの作成は楽しく、
また、(敗北したこともあり、)私に取って非常に勉強になったコンテストでした。
出場して本当に良かったです。

ただ、次回も参加したいかというと疑問です。(後述)

オープンデータのWEBアプリを作成した感想

多くの方は本コンテストを通してオープンデータの可能性が見えたのかもしれませんが、
私は見えませんでした。(少なくとも今回のコンテストでは。)
むしろ、「このままで良いのか!?」と言いたいです。

プログラミング部門の感想から述べていきます。

今回WEBアプリコンテストを出場するにあたり、
流山市のオープンデータを食い入るように見ては、
WEBアプリのアイデアを膨らませようとしたのですが、
独創的かつ有用なアイデアを出すというのは、非常に難しかったです……。

私のアイデアを出す能力が貧困だと言われれば、それまでなのですが。(笑)

私のオープンデータWEBアプリに対する評価軸

私は、独創性と有用性という2軸で各々作品を評価していました。

後者は言わずもがな、役に立たないアプリなど誰も求めていません。
一方の前者。
独創性こそ、オープンデータの神髄であると考えています。

極端な話、エンジニアならオープンデータを見て、
ある程度有用性が高いアプリは誰でも作れるでしょう。

しかし、そこに複数のオープンデータやアイデアが掛け合わせることにより、
「こんなこともできるんだ!」「これは面白い!」 というオープンデータならではの発見が生まれてくるのではないでしょうか。

本コンテストの趣旨を見ても、
独創性と有用性という2軸は大きくはずれていないように思います。

流山市WEBアプリの入賞作品を見て

私は、独創性と有用性がトレードオフの関係になっているように思いました。
すなわち、役立つアプリを作ろうとすると、独創性が減る。
逆に、独創性に偏りすぎると誰も使わないアプリになってしまう。

個人的な意見ですが、
優秀賞の「ごみ分別・処分方法検索アプリ」は有用性が高いが、独創性は低い。
一方、最優秀賞の「流山百歌」は独創性が高く完成度は高い。(完成度の高さに驚きました。)
しかし、流行るか(有用性があるか)と言われると疑問なアプリでした。
多くの市民には、優秀賞の「ごみ分別・処分方法検索アプリ」の方が役立ちそうです。

それでは、どちらも兼ね備えたアプリは?
と言われると、アイデア部門で入賞した「ながれやまホカサポ(保活サポート)」が
バランスの良い素晴らしいアプリ案であると感じます。
ただし、こちらはまだ流山市が公開していないデータを含んでいます。

今回のコンテストの作品群を見ると、現在公開されているオープンデータだけでは、
独創性と有用性を両立することは難しいと言えるでしょう。
どちらの質も保証するためには、新たにアイデアをベースとしたオープンデータ
必要であると、私は感じています。
例えば、「ながれやまホカサポ(保活サポート)」で言えば、
保育園・保育所の入居可能人数や入居待ち人数のオープンデータ
がアイデアをベースとしたオープンデータです。

アイデアありきでオープンデータを公開した方が、
利便性が高いアプリが誕生しやすいことは明らかでしょう。

逆に言えば、アイデアなしで、ただデータをオープンにするだけでは、
データに使い道がない可能性が高いです。
鯖江市がオープンデータで成功しているのは、
jig.jpの福野泰介さんが市長にアプリのアイデアを提言し、
そのアイデアに基づいてデータをオープンにしているからではないでしょうか。

単にデータを公開するだけで良いのか

行政がデータをオープンにするのは良い試みです。
しかし、ただ公開していくだけでは使いづらいデータだけが溜まり、
結局誰にも使われないままオープンデータだけが残るという結末になってしまう……。

それではどうすれば良いのでしょうか。

公開するデータを選定する

関係者の方には失礼であることを承知でキツく言うと、 今のオープンデータは単に公開できそうなデータを順次公開しているようにしか見えません。
(特に、市議会のオープンデータ)
そうではなくて、「データをオープンにすることで市民の利便性を向上させるんだ!」という考え
を念頭にオープンデータを公開して欲しいです。

また、アイデアを持っている人や制作意欲のある人に対して、
「こういうオープンデータを作ってくれ!」という要望を聞くフォームを作るのも良いでしょう。

魅力的なデータが増えれば増えるほど、
コンテストに参加する人も増え、有用性の高い素晴らしいアプリも増えるのではないでしょうか。
それらが叶えば、私も次回のコンテストに参加したいです><b

最後に

行政のオープンデータの動きが、ビッグデータの動きに似ていると思いました。
ビッグデータを解析すれば何かわかるのではないかと同様に、
データをオープンにすれば何かすごいアプリができるのではないか。
という具合です。

ぐるっと流山 WEBアプリコンテスト|流山市
の最後に市長の講評があるのですが、
オープンデータの数ではなく質で勝負していくのは如何でしょうか。

オープンデータの質は比較しにくく、逆にオープンデータの数は定量的なため、
オープンデータがどの程度公開されているかで、
行政の力関係が決まってしまう側面もあるのかもしれません。
地域資源の情報をオープンデータとして共有していくためのデータベースサイト | CityData

しかしながら、オープンデータでの評価を向上させることが目的ではなく、 市民の利便性を向上させることが目的であることを忘れないで欲しいです。

以上、長い長い負け惜しみでした(笑)

KVSとそのKVSを開発した企業まとめ

データサイエンティスト養成読本

ビッグデータ時代のビジネスを支えるデータ分析力が身につく!
という触れ込みに惹かれ、読んでみた。
全体としては、現在ビジネスに携わっている人向けに書かれており、
網羅的に全体像を把握することができるような印章を受けた。
(私が学生なのでピンと来ない部分は多くあったが、現在ビジネスをしている人にとっては、特に即戦力になる本だと思う。)

さらりと読んだ結果、NoSQLについて気になったので、
この部分だけをまとめようと思う。復習がてら。

データサイエンティスト養成読本 [ビッグデータ時代のビジネスを支えるデータ分析力が身につく! ] (Software Design plus)

まとめと感想

いきなり(一部の)まとめと感想を述べてみる。
KVSとそのKVSを開発した企業まとめ。

  • Google:HBase
  • Amazon:Dynamo
  • Facebook:Casandra
  • 10gen:MongoDB
  • LinkedIn:Voldemort

そうそうたる企業の数々。
ついでに、Twitter社は独自のストリーム処理技術であるStormがある。

なぜ日本発の世界標準が一つもないのか……。

日本発の技術が少ない点について、IT Proの読者からはあまり反論がないと思う。 マイクロプロセサ、オペレーティング・システム、データベース、開発ツール、開発言語といった基盤となる部分で、世界で使われている日本発の技術や製品はほとんどない。 業務用アプリケーションの分野を見ても同様である。サーバー製品を見ても、日本製品の存在感はまるでない。

---なぜ日本で独自技術は生まれないのか(上)より引用。--- http://itpro.nikkeibp.co.jp/free/ITPro/OPINION/20030610/1/

ほら、IT Proの記事にもなってる。

……実はこの記事、2003年の記事である。
今は2013年。10年間、まるで成長していない……。なぜなのか。

といってもこれはそっくりそのままヨーロッパにも言えるわけで。
アメリカの1強というのが正しい認識なのかもしれない。

「ビッグデータインフラ」入門

RDBMS

SQLをおもなデータベース言語とするデータベース。
SQLは最も基本的であり、40年間の間利用され続けたことによって、
高度に鍛えられている。

NoSQL

NoSQLとは"Nott only SQL"の略。 すなわち、データベース言語としてSQLを用いないデータベース。
代表的なデータベースとして、KVS(key value store)がある。

RDBMSとNoSQL

RDBはデータをテーブル形式で保持するが、 KVSはキーとバリューという目印をデータに与えて扱う。

Hadoopがもたらしたもの

近年のビッグデータ解析を支える重要な技術として、
分散処理フレームワークHadoopがある。
Haddopの要素技術であるKVSフレームワークMapReduce
分散ファイルシステムHDFSをさして、狭義のHadoopと言う。
また、講義では、ソフトウェアを含む開発プロジェクト全体をHadoopと言う。
元々Hadoopの要素技術はGoogleが自社のサービスで活用するために開発された技術だったが、Hadoopが公開されたことによって、様々な高度なデータ施策が容易にできるようになった。

データベースの種類

Hadoop

Hadoopプロジェクトの中で、データベースの役割を担うものに、
NoSQLデータベースのHBaseがある。
HBaseを利用する利点としてはRDBの強みであるテーブル間の演算操作を犠牲にして得た、強力なスケーラビリティが挙げられます。

Dynamo

Amazonが自社のサービスのために開発したKVS。
応答についての信頼性や高速性が追求されている。 DynamoDBはAmazon Web Servicesとして展開されている。
特徴を列挙する。

  • ユーザの管理を最小限にしたフルマネージドサービス。
  • データ容量は、無制限に拡張可能。
  • スループット性能は任意の値を指定可能。
  • ハードウェアはSSDを利用し、アクセス速度を担保。
  • 3箇所以上の異なる物理拠点にデータをレプリケーションし、可用性を担保。

Casandra

Facebookが自社のサービスのために開発したKVS。
HadoopのHBaseの源流であるBigtableとDynamoという2つのKVSを研究し、
両者の長所を取り入れたハイブリッドKVSとして登場。
データモデルについてはBigtableを、ストレージシステムについてはDynamoに類似させている。
これにより、Bigtableのストレージシステムに孕むSPOF(Single Point of Failture)を防ぐことができる。
HBaseと同じくオープンソース・ソフトウェアとしてApacheプロジェクトで開発が進められている。

MongoDB

アメリカの10gen社が開発したKVS。
RDBMSのリプレースを狙って開発されたオープンソースプロジェクト。
特徴を列挙する。

  • JSON形式のドキュメントで保存する「ドキュメント志向」により、データ構造の拡張が簡単。
  • インデックスの設定が可能。
  • JavaScriptによるMapReduceやHadoopを利用可能。
  • 蓄積データが増えるとコード変更なしで自動でスケールアウト可能。

スケーラビリティと高機能の両立を目指している。

VoltDB

PostgreSQLなどに携わっていたMichael Stonebrakerによって開発されたRDBMS
これまでのRDBMSと比べた時のメリットとしてオンメモリRDBMSであることが挙げられる。そのため、RDBMSでありながらKVSのような高速性を実現できる。

Voldemort

LinkdInの技術者が開発したKVS。 Dynamoをモデルとして作られており、オープンソース・ソフトウェアとしてApacheプロジェクトで開発が進められている。

こちらのSlideShareが参考になる。
http://www.slideshare.net/JoongjinBae/voldemort-dynamo

Sublime Text 導入

本記事は私の備忘録です。
Sublime Textのインストール方法は特筆することはありません。
公式HPに行き、ダウンロードするだけですので……。

Sublime TextのVi化方法

Sublime TextをVim化 -- blog.makitasako.com
こちらの記事から引用します。

Preference -> Settings -> User

// Vim モード
"ignored_packages": [],
// Vim のキーバインドを使用
"vintage_ctrl_keys": true,
// 新規ファイルを開いたらノーマルモード
"vintage_start_in_command_mode": true

emacs風のカーソル移動キーバインド設定

Ctrl+nやctrl+pで上下に上下にカーソルを動かしたい人向け。

Preference -> Key Bindings -> User

[
    { "keys": ["ctrl+f"], "command": "move", "args": {"by": "characters", "forward": true } },
    { "keys": ["ctrl+b"], "command": "move", "args": {"by": "characters", "forward": false } },
    { "keys": ["ctrl+p"], "command": "move", "args": {"by": "lines", "forward": false } },
    { "keys": ["ctrl+n"], "command": "move", "args": {"by": "lines", "forward": true } },
    { "keys": ["ctrl+h"], "command": "left_delete" },
    { "keys": ["ctrl+d"], "command": "right_delete" },
    { "keys": ["ctrl+a"], "command": "move_to", "args": {"to": "bol", "extend": false} },
    { "keys": ["ctrl+e"], "command": "move_to", "args": {"to": "eol", "extend": false} }
]

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

お詫び

長らく更新が滞ってしまいました。
プログラム自体は随分前に書き終えていたのですが、
ブログの記事にするまでに時間がかかってしまいました。

……それだけなら良いのですが……。
当初自己組織化写像は簡単に実装できると考え、
コードを書きながらブログを更新していたのですが、
甘かったです。複雑になってしまいました><;
(力量不足。っていうのと丁寧なブログ記事にするのは割りと時間取られてしまう。)

つまり、説明が面倒になってしまいました。

結果

結果から先に示します!
10×10のマップで作った色の自己組織化写像です!
グラデーションになっていることが確認出来ればOKですよー!

f:id:sonoshou:20130713070450p:plain

コード

完成したコードを掲載します。
簡単のために、 Wikipedia:自己組織化写像の算法のステップにおける
4.重みベクトルを入力ベクトルに近づける処理を行う際、
最近傍のユニットのみ重みベクトルを更新しています。

final int MAP_WIDTH = 10;
final int MAP_HEIGHT = 10;
final int DIM = 3;
final int RAD = 20;
final float LEARNING_RATE = 0.001;
final float END_CONDITION = 0.05;

int[][][] unitArray;
int t;

void setup()
{
  size(int((RAD * sqrt(3) * (MAP_WIDTH-1)) + (10 * sqrt(3))), int((RAD * 3 * ((MAP_HEIGHT/2)-1)) + (RAD * 1.5)));

  unitArray = new int[MAP_HEIGHT][MAP_WIDTH][DIM];

  //1. set random vectors
  for (int i = 0; i < MAP_HEIGHT; i++)
  {
    for (int j = 0; j < MAP_WIDTH; j++)
    {
      // change
      for(int k = 0; k < DIM; k++)
      {
        unitArray[i][j][k] = int(random(256));
      }

      drawHexagon(i, j, color(unitArray[i][j][0], unitArray[i][j][1],unitArray[i][j][2]), color(0, 0, 0));

    }      
  }
}

void draw()
{
  //2. set a random input vector
  int[] inputArray = {int(random(256)),int(random(256)),int(random(256))};   

  //3. find Best Maching Unit
  int BMUi = 0, BMUj = 0;  
  float tempDistance;
  float minDistance = Float.MAX_VALUE;

  for (int i = 0; i < MAP_HEIGHT; i++)
  {
    for (int j = 0; j < MAP_WIDTH; j++)
    {
      tempDistance = calculateDistance(unitArray[i][j], inputArray);

      if(minDistance > tempDistance)
      {
        minDistance = tempDistance;
        BMUi = i;
        BMUj = j;
      }
    }
  }

  //4. update units around BMU
  updateUnits(BMUi, BMUj, inputArray);

  //5. noloop() if t reach at end condition
  if(calculateLearningRate(t) < END_CONDITION)
  {
    println("finish : t = " + t);
    noLoop();
  }

  t++;
}

//draw hexagon
void drawHexagon(int i, int j, color fillColor, color strokeColor)
{
    if (i % 2 == 0)
    {
      hexagon(j * RAD * sqrt(3), i * RAD * 1.5, RAD, color(unitArray[i][j][0],unitArray[i][j][1],unitArray[i][j][2]), color(0, 0, 0));
      } else {
      hexagon(j * RAD * sqrt(3) + (RAD/2) * sqrt(3) , i * RAD * 1.5, RAD,  color(unitArray[i][j][0],unitArray[i][j][1],unitArray[i][j][2]), color(0, 0, 0));
    }
}

// hexagon
void hexagon(float centerX, float centerY, float rad, 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};


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

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

// culcate distance
float calculateDistance(int[] unitArray1, int[] unitArray2)
{
  float distance;

  distance = sqrt(
             sq(unitArray1[0] - unitArray2[0]) + 
             sq(unitArray1[1] - unitArray2[1]) +
             sq(unitArray1[2] - unitArray2[2]));

  return distance;
}

// update unit
void updateUnits(int i, int j, int[] inputArray)
{
  int[][] dx = {{-1, -1,  0, 1, 0, -1}, {-1,  0,  1, 1, 1, 0}};
  int[][] dy = {{ 0, -1, -1, 0, 1,  1}, { 0, -1, -1, 0, 1, 1}};
  int ti, tj;

  // update weight vector
    for(int k = 0; k < 6; k++)
  {
    ti = i + dy[i%2][k];
    tj = j + dx[i%2][k];
    if(unitExists(ti, tj))
    {
      for(int l = 0; l < DIM; l++)
      {
        unitArray[ti][tj][l] = int(unitArray[ti][tj][l] + calculateLearningRate(t) * (inputArray[l] - unitArray[ti][tj][l]));
      }  
      drawHexagon(ti, tj, color(unitArray[ti][tj][0], unitArray[ti][tj][1],unitArray[ti][tj][2]), color(0, 0, 0));    
    }
  }
}

// Unit Exists
Boolean unitExists (int ti, int tj)
{
  return ti >= 0 && tj >= 0 && ti < MAP_HEIGHT && tj < MAP_WIDTH;
}

float calculateLearningRate(int t)
{
  return exp(-1 * LEARNING_RATE * t);
}

長くなってしまいました。
いろいろと変更しました。 コピペすれば動くはずなので、いろいろと試してみて下さい。

定数の説明

定数だけ説明します。
定数を説明すれば、いろいろと試せると思って。

コードの一番上の方に書かれているのが定数群です。

final int MAP_WIDTH = 10;
final int MAP_HEIGHT = 10;
final int DIM = 3;
final int RAD = 20;
final float LEARNING_RATE = 0.001;
final float END_CONDITION = 0.05;

MAP_WIDTHとMAP_HEIGHTはマップの個数を表しています。 DIMはDimension(次元数)です。
色が3次元なので、今回は3次元固定で大丈夫です。 RADはRadiusで、一つのマップ(六角形)の半径を表します。
LEARNING_RATEは学習係数を表します。
END_CONDITIONは学習率(学習係数と繰り返し回数から計算される)が一定以下の値になったかどうかを確かめるために用います。

以上が説明になります。

問題点

できた!と思いたいのですが、以下の図を見て下さい。
今回は20×20です。

f:id:sonoshou:20130713070659p:plain

汚いですよね。
同じような色が離れてしまっています。
これは、4.重みベクトルを入力ベクトルに近づける処理を行う際、
最近傍のユニットのみ重みベクトルを更新しているからです。
本来ならば、BMUの距離に応じて重みベクトルを更新しなければなりません。

この実装が大変だったので、
僕はコードの説明を諦めてしまうのでした。
続く。