フィッシャーの線形判別(2)の続きです。
先回の記事のまとめ
2クラスのデータを次元圧縮する方向は、次の式で求められることがわかりました。
次元圧縮の実験
実際に式(1)を使って、2次元のデータを1次元に射影してみます。早速結果です。
左が元のデータで、右が射影した後の分布。左の図の黒い矢印は、求めたでの射影方向です。*1 ちゃんと分離できていそうですね。
データの傾向を変えてみても同じく分離できました。
今回のコードです。行列やベクトルを、なるべく数式に合わせて書こうとしたら、妙に煩雑になってしまった。多分もっとスマートな書き方があるんだと思うのですが、、、。reshape(D, 1)
とかなんかかっこ悪いですよね。列ベクトルを行ベクトルにするのに転置のT
だとうまくいかないみたいで。
フィッシャーの線形判別(4):フィッシャーの線形判別の解の別の求め方
フィッシャーの線形判別(5)多クラス:多クラスの場合のフィッシャーの線形判別
# フィッシャーの線形判別 import matplotlib.pyplot as plt import numpy as np # 各クラスのデータ数 N = 300 # 入力次元数 D = 2 # クラス数 K = 2 # ランダムシードを固定 np.random.seed(0) # 2クラス分のデータを作成 mean1 = np.array([0, 2]) mean2 = np.array([0, -2]) cov = [[1.0, -0.7], [-0.7, 1.0]] x1 = np.random.multivariate_normal(mean1, cov, N).T x2 = np.random.multivariate_normal(mean2, cov, N).T # 各クラスの平均ベクトルを求める m1 = np.array([np.average(x1[0, :]), np.average(x1[1, :])]).reshape(D, 1) m2 = np.array([np.average(x2[0, :]), np.average(x2[1, :])]).reshape(D, 1) # クラス内共分散行列を求める Sw = np.zeros([D, D]) for i in range(N): Sw = np.dot((x1[:, i].reshape(D, 1)-m1), (x1[:, i].reshape(D, 1)-m1).T) + \ np.dot((x2[:, i].reshape(D, 1)-m2), (x2[:, i].reshape(D, 1)-m2).T) + Sw # wを求め、グラフ表示用に長さを調整 w = np.dot(np.linalg.inv(Sw), (m2-m1)) w = w/np.linalg.norm(w) plt.scatter(x1[0, :], x1[1, :], color="blue", alpha=0.5) plt.scatter(x2[0, :], x2[1, :], color="red", alpha=0.5) # 射影の方向は直線wに対して垂直方向 plt.quiver(0, 0, w[1, 0], -w[0, 0], angles="xy", units="xy", color="black", scale=0.5) plt.show() y1 = np.dot(w.T, x1) y2 = np.dot(w.T, x2) plt.hist(y1[0], bins=30, color="blue", alpha=0.5) plt.hist(y2[0], bins=30, color="red", alpha=0.5) plt.show()
*1:と内積をとったときに射影する方向であり、の方向そのものを図示しているわけではありません。