実体と情報のはざま

何事にも囚われず。

入力データを近似するSOM

 前回は、自己組織化マップで色分けをやってみた。今回は、「マップ」の方ではなく入力ベクトルと参照ベクトル(プログラム中の行列Mでどんどん変わる)の「ベクトル空間」を可視化してみたいと思う。色分けは、入力ベクトルよりも参照ベクトルの方がずっと多いのだが、今回は入力ベクトルの方が多い。この場合、参照ベクトルは入力ベクトルを近似するというか寄り添うように分布することになる。
時々エラー。でも一応できた!
プログラムはこんな感じ。入力は円。
開発環境:Spyder(Python 3.6)

import numpy as np
import matplotlib.pyplot as plt
########################パラメータの設定
n,f=50,2#入力ベクトル数,#入力ベクトルの要素数
sgm0=0.01#誤差に関するパラメータ
T=100#繰り返し回数
a=5#時定数
cx,cy=3,2#マップのx,y方向の数
###########################行列の設定
X=np.zeros((n,f))#入力行列
for i in range(0,n):
    X[i,0]=np.cos(2*np.pi*i/(n-1))
    X[i,1]=np.sin(2*np.pi*i/(n-1))
fig1=plt.figure(1)
plt.scatter(X[:,0],X[:,1],color='b',s=20)
M=np.random.random((cx*cy,f))*0.3-0.15#マップ中の各サイトの値が入った行列
plt.scatter(M[:,0],M[:,1],color='m',s=500,alpha=0.2)
R=np.zeros((cx*cy,2))#マップ中のサイトの位置が入った行列
for y in range(0,cy):
    for x in range(0,cx):
        k=x+(cx*y)
        R[k,0]=x
        R[k,1]=y
Ita=np.zeros((n,cx*cy))#更新に使う係数
###########################繰り返しの実行
for t in range(0,T):
    sgm=sgm0*np.exp(-t/a)
    for i in range(0,n):
        min=1
        for j in range(0,cx*cy):
            d=np.linalg.norm(X[i,:]-M[j,:])
            if d<min:
                min=d
                cj=j
        for j in range(0,cx*cy):
            D=np.linalg.norm(R[j,:]-R[cj,:])
            Ita[i,j]=np.exp(-((D/sgm)**2)/2)
    s=np.sum(Ita,axis=0)#列方向に和をとる(axis=1なら行方向)
    for j in range(0,cx*cy):
        p=np.zeros((f))
        for i in range(0,n):
            p=p+(Ita[i,j]*X[i,:])
        M[j,:]=p/s[j]
plt.scatter(M[:,0],M[:,1],color='r',s=500,alpha=0.5 )

 結果がこれ。うまくいったケースのもの。入力ベクトルが形作る円を少数の参照ベクトルが近似している様子が見られる。円の中心付近のマゼンタ色で散らばっている点が初期の参照ベクトルで、繰り返し計算の末が赤い点である。プログラムの未解決課題は時々「ゼロで割る」ことによるエラーが出てしまうこと。。前回色分けの時に収束させる関数を変えたんだけどあんまり関係なかったみたい。
f:id:myuteru:20170521000210p:plain
 次回は何かしらを”分類”してみたいな~。SOMからいったん離れて”分類”手法の古典から学びたいな。
今日はここまで!