In [10]:
# Font
import os.path
import matplotlib
import matplotlib.pyplot as plt
import pylab
font = {'family': 'IPAexGothic'}
matplotlib.rc('font', **font)
markerSize = 12
fontSize = 22
figureSize = (12, 9)
bboxPos = (0.5, -0.1)
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn import preprocessing
from sklearn import utils
In [11]:
# PNGとEPSファイルを書き出す
def writePNGandEPS(name):
plt.savefig("%s/%s.png" % ('./images/', name))
plt.savefig("%s/%s.eps" % ('./images/', name))
In [12]:
useCache = False
if (useCache):
learnX = np.load('./cache/sm_learnX.npy')
learnY = np.load('./cache/sm_learnY.npy')
learnLabel = np.load('./cache/sm_learnLabel.npy')
testX = np.load('./cache/sm_testX.npy')
testY = np.load('./cache/sm_testY.npy')
testLabel = np.load('./cache/sm_testLabel.npy')
x = np.load('./cache/sm_x.npy')
y = np.load('./cache/sm_y.npy')
label = np.load('./cache/sm_l.npy')
else:
dataCount = 100;
# 0~24の間でランダムにx座標の値を生成する.(時刻データ)
x = np.sort(np.random.random(size=dataCount) * 24).reshape(-1, 1)
yWithoutNoise = np.sin(x*np.pi/12);
# xに対するsin関数の値に,正規分布に従うノイズを足し合わせ,ベースの数値を作る.
y = yWithoutNoise + 0.1 * np.random.randn(dataCount).reshape(-1, 1)
# ラベルを切り分ける閾値
threshold1 = 0.6
threshold2 = -0.6
# ラベルデータを閾値から作る
label = np.ones([dataCount,1])
label[np.where(y > threshold1)] = 2;
label[np.where(y < threshold2)] = 0;
label = label.astype(np.int)
# ここまでがデータの生成.データを教師データとテストデータに,ランダムで切り分ける.
# テストデータは,学習に使ってはならない.
learnIndex = np.random.permutation(dataCount)[0:dataCount/2]
testIndex = np.random.permutation(dataCount)[dataCount/2:dataCount]
# 3次の多項式の基底を考えて,xの値を拡張する
X = np.c_[x, x * x, x * x * x]
# データを実際に切り分ける
learnX = X[learnIndex]
learnY = y[learnIndex]
learnLabel = label[learnIndex]
testX = X[testIndex]
testY = y[testIndex]
testLabel = label[testIndex]
np.save('./cache/sm_learnX.npy', learnX)
np.save('./cache/sm_learnY.npy', learnY)
np.save('./cache/sm_learnLabel.npy', learnLabel)
np.save('./cache/sm_testX.npy', testX)
np.save('./cache/sm_testY.npy', testY)
np.save('./cache/sm_testLabel.npy', testLabel)
np.save('./cache/sm_x.npy', x)
np.save('./cache/sm_y.npy', y)
np.save('./cache/sm_l.npy', label)
In [13]:
# 書籍用のテキストの書き出し
t = x[10:25,0]
l = label[10:25,0]
for var in range(0, 10):
print '|%f|%d|' % (t[var], l[var])
for var in range(0, 10):
if l[var]==0:
print '|%d:%02d|%s|' % (np.floor(t[var]), (t[var] - np.floor(t[var])) * 60, u'メニュー1')
if l[var]==1:
print '|%d:%02d|%s|' % (np.floor(t[var]), (t[var] - np.floor(t[var])) * 60, u'メニュー2')
if l[var]==2:
print '|%d:%02d|%s|' % (np.floor(t[var]), (t[var] - np.floor(t[var])) * 60, u'メニュー3')
In [14]:
# 学習
log_model = LogisticRegression()
log_model.fit(learnX, learnLabel)
# 性能評価
print(u'学習性能 = %f' % log_model.score(learnX, learnLabel))
print(u'汎化性能 = %f' % log_model.score(testX, testLabel))
# 自前のコードで推論
f = np.dot(log_model.coef_, testX.transpose()) + np.matlib.repmat(log_model.intercept_, 50, 1).transpose()
numerator = np.exp(f)
denominator = np.sum(numerator, axis=0)
p = numerator / denominator
predict = p.transpose().argmax(axis=1)-1
# scikit-learnで推論
predictByScikit = log_model.predict(testX)
In [15]:
# 描画
index = np.where(label == 0);
pylab.figure(figsize=figureSize)
plt.plot(x[index[0]], np.zeros(index[0].shape), 'rx', label=u'メニュー1', markersize=markerSize)
index = np.where(label == 1);
plt.plot(x[index[0]], np.ones(index[0].shape), 'go', label=u'メニュー2', markersize=markerSize)
index = np.where(label == 2);
plt.plot(x[index[0]], np.ones(index[0].shape)*2, 'bv', label=u'メニュー3', markersize=markerSize)
plt.legend()
plt.ylabel(u'選んだメニューの項目')
plt.xlabel(u'時刻')
plt.xlim(0,24)
plt.rcParams["font.size"] = fontSize
writePNGandEPS('logistic01')
plt.show()
In [16]:
# 過学習のテスト
def testOverfitting(k):
# 4次の多項式の基底を考えて,xの値を拡張する
X = np.c_[x]
for i in range(0, k):
X = np.c_[X, np.power(x, i+1)]
# データを実際に切り分ける
learnX = X[learnIndex]
learnY = y[learnIndex]
learnLabel = label[learnIndex]
testX = X[testIndex]
testY = y[testIndex]
testLabel = label[testIndex]
# 学習
log_model = LogisticRegression()
log_model.fit(learnX, learnLabel)
# 性能評価
print(u'%d次の多項式を使った場合' % k)
print(u' ->学習性能 = %f' % log_model.score(learnX, learnLabel))
print(u' ->汎化性能 = %f' % log_model.score(testX, testLabel))
testOverfitting(1)
testOverfitting(2)
testOverfitting(3)
testOverfitting(4)
testOverfitting(5)
testOverfitting(6)
testOverfitting(7)
testOverfitting(8)
testOverfitting(9)
testOverfitting(16)
In [17]:
# ソフトマックス関数のレンダリング
k = 3
X = np.c_[x]
for i in range(0, k-1):
X = np.c_[X, np.power(x, i+1)]
# データを実際に切り分ける
learnX = X[learnIndex]
learnY = y[learnIndex]
learnLabel = label[learnIndex]
testX = X[testIndex]
testY = y[testIndex]
testLabel = label[testIndex]
# 学習
log_model = LogisticRegression()
log_model.fit(learnX, learnLabel)
# 性能評価
print(u' ->学習性能 = %f' % log_model.score(learnX, learnLabel))
print(u' ->汎化性能 = %f' % log_model.score(testX, testLabel))
# 学習したパラメータ
print(log_model.intercept_)
print(log_model.coef_)
# 自前のコードで推論
f = np.dot(log_model.coef_, X.transpose()) + np.matlib.repmat(log_model.intercept_, 100, 1).transpose()
numerator = np.exp(f)
denominator = np.sum(numerator, axis=0)
p = numerator / denominator
predict = p.transpose().argmax(axis=1)-1
# scikit-learnで推論
predictByScikit = log_model.predict(X)
pylab.figure(figsize=figureSize)
plt.plot(x, p[0,:], 'r:', markersize=markerSize, label=u'$p_1$(メニュー1)')
plt.plot(x, p[1,:], 'g--', markersize=markerSize, label=u'$p_2$(メニュー2)')
plt.plot(x, p[2,:], 'b-', markersize=markerSize, label=u'$p_3$(メニュー3)')
plt.legend()
plt.xlabel(u'時刻')
plt.ylabel(u'ソフトマックス関数の出力')
plt.xlim(0,24)
plt.rcParams["font.size"] = fontSize
writePNGandEPS('softmaxResults')
plt.show()
In [18]:
##### CoreML用にモデルとパラメータを書き出す
from coremltools.converters import sklearn
coreml_model = sklearn.convert(log_model, ["x1", "x2", "x3"], "label")
coreml_model.author = 'Yuichi Yoshida'
coreml_model.license = 'MIT'
coreml_model.short_description = '時刻からよく選ばれるメニューの項目を推定します.'
coreml_model.input_description['x1'] = u'1次の入力値.推定したい値を入力してください.'
coreml_model.input_description['x2'] = u'2次の入力値.推定したい値の2乗を入力してください.'
coreml_model.input_description['x3'] = u'3次の入力値.推定したい値を3乗を入力してください.'
# coreml_model.input_description['x4'] = u'4次の入力値.推定したい値を4乗を入力してください.'
# coreml_model.input_description['x5'] = u'5次の入力値.推定したい値を5乗を入力してください.'
coreml_model.output_description['label'] = u'推定した結果'
coreml_model.save('./MenuPrediction.mlmodel')