しんさんのブログ

科学や技術のこと読書のことなど

機械学習基礎の基礎: パーセプトロンで線形分離を実装してみる

今度は、パーセプトロンを使って線形分離をしてみます。
適当に線形分離できそうなデータを以下のように作ってみました。
データは2次元平面上の点の座標(x, y)とそれぞれの正解ラベル1 or -1をつけています。
10, 20, 1
11, 30, 1
15, 30, 1
17, 35, 1
5, 25, 1
25, 35, 1
50, 40, 1
44, 38, 1
33, 30, 1
35, 35, 1
15, 8, -1
20, 2, -1
23, 11, -1
31, 22, -1
40, 35, -1
42, 29, -1
45, 39, -1
47, 37, -1
50, 39, -1
35, 20, -1
これを、テキストファイルとして読み込んで教師データとしています。
r = (x, y), 正解 t = 1or -1として、2入力、1出力のパーセプトロンをつくります。
重みw = (w0, w1)に対して、
出力層への入力は u = dot(w, r)となります。
識別関数fは
f = 1 ( if u >= 0)
f = -1 ( if u< 0)
とします。
教師データと出力が一致しない場合は
w := w + r* t
として重みw を更新します。
コードは以下のようになりました。
学習は120エポックとしました。

###############
# パーセプトロンの実装
###############
import numpy as np
import matplotlib.pyplot as plt

### (1) データ読み込み ###
trainData = np.loadtxt('linerSeparateData.txt', delimiter=',', skiprows=0)
trainDataX = trainData[:, 0:2] # (x, y)
trainDataY = trainData[:, 2] # 正解ラベル

# 重みwの初期化
w = np.random.rand(2)

# activation function
def f(x):
	if np.dot(w, x) >= 0:
		return 1
	else:
		return -1

num_epoch = 120 #エポック数
countNum = 0 #カウンター

### 学習 ###
for _ in range(num_epoch):
	for x, y in zip(trainDataX, trainDataY):
		if f(x) != y: # 予想が間違えたとき
			w = w + y*x # 重みを更新
		# print result
	countNum+=1
	print('{}: w = {}' .format(countNum, w))

# 結果の表示
x0 = np.arange(0, 50)

plt.plot(trainDataX[trainDataY == 1, 0], trainDataX[trainDataY == 1, 1], 'o')
plt.plot(trainDataX[trainDataY == -1, 0], trainDataX[trainDataY == -1, 1], 'x')
plt.plot(x0, -w[0]/w[1] * x0)
plt.show()

見た感じはうまく分離できているように見えます。
f:id:wshinya:20180325221236p:plain