import csv
import random
from matplotlib import pyplot as plt
%matplotlib inline
from pybrain.tools.shortcuts import buildNetwork
from pybrain.datasets import SupervisedDataSet
from pybrain.supervised import BackpropTrainer
モジュールのインポート。
reader = csv.reader(open('data.csv', 'r'))
next(reader)
data = [r for r in reader]
n = len(data)
min1 = min([float(d[1]) for d in data])
max1 = max([float(d[1]) for d in data])
min2 = min([float(d[2]) for d in data])
max2 = max([float(d[2]) for d in data])
output_data = []
input_data = []
for i in xrange(n):
x = (float(data[i][1]) - min1)/(max1 - min1)
y = (float(data[i][2]) - min2)/(max2 - min2)
input_data.append((x, y))
output_data.append(float(data[i][0]))
データの用意。
def get_data():
ds = SupervisedDataSet(2, 1)
m = 10
index0 = [i for i in xrange(n) if output_data[i] == 0]
index1 = [i for i in xrange(n) if output_data[i] == 1]
index0 = random.sample(index0, m/2)
index1 = random.sample(index1, m/2)
input_sample = [input_data[i] for i in index0] + [input_data[i] for i in index1]
output_sample = [output_data[i] for i in index0] + [output_data[i] for i in index1]
for i in xrange(m):
ds.addSample(input_sample[i], output_sample[i])
return ds
学習させるデータの設定。学習には時間がかかるので、全データではなく、乱数でデータを選択する。上では結果が 0 になるものと 1 になるものからそれぞれ同じ数だけの点を選択して設定してる。今回は、学習途中に教師データを入れ替えるため、データの設定を関数にしている。
import numpy as np
from tqdm import tqdm
def init_weights(n, rang):
np.random.seed(1)
return np.random.rand(n)*rang*2. - rang
nn = buildNetwork(2, 3, 1)
nn.params[:] = init_weights(len(nn.params), 1.)
random.seed(1)
errors = []
for i in tqdm(xrange(10)):
ds = get_data()
trainer = BackpropTrainer(nn, ds, learningrate=0.01, momentum=0.)
error = trainer.train()
errors.append(error)
if i == 0:
error0 = error
for j in xrange(1, 100):
error = trainer.train()
relerror = error/error0
errors.append(error)
if error < 1e-4 or relerror < 1e-8:
break
print('%5d %e %e' % (i, error, relerror))
学習。
plt.yscale('log')
plt.plot(errors);
エラーの減少具合のプロット。
result = [nn.activate(input_data[i]) for i in xrange(n)]
予測データの取得。
count = 0
for i in xrange(n):
if result[i] >= 0.5:
v = 1
else:
v = 0
if output_data[i] == v:
count += 1
print 'n = ', n, 'right = ', count, '(%.2f %%)' % (100.*count/n)
成績。そこそこの予測精度で、時間もそれほどかからない。
data0_a = [input_data[i][0]*(max1 - min1) + min1 for i in xrange(n) if result[i] < 0.5]
data0_b = [input_data[i][1]*(max2 - min2) + min2 for i in xrange(n) if result[i] < 0.5]
data1_a = [input_data[i][0]*(max1 - min1) + min1 for i in xrange(n) if result[i] >= 0.5]
data1_b = [input_data[i][1]*(max2 - min2) + min2 for i in xrange(n) if result[i] >= 0.5]
plt.plot(data0_a, data0_b, '+')
plt.plot(data1_a, data1_b, 'r+');
学習結果。
random.seed(2)
data0_a = []
data0_b = []
data1_a = []
data1_b = []
for i in xrange(n):
a = random.random()
b = random.random()
r = nn.activate((a, b))
if r < 0.5:
data0_a.append(a*(max1 - min1) + min1)
data0_b.append(b*(max2 - min2) + min2)
else:
data1_a.append(a*(max1 - min1) + min1)
data1_b.append(b*(max2 - min2) + min2)
plt.plot(data0_a, data0_b, '+')
plt.plot(data1_a, data1_b, 'r+');
ランダムに選んだ点による予測結果。