しんさんのブログ

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

機械学習基礎の基礎: 非線形fitting

前回の線形fittingでは、身長が低いところでfittingのずれが大きくなっていましたので、今回は2次関数でfittingすることにします。
同時に、入力データやパラメータをmatrixで扱うことでコードをシンプルにしています。
前回との差分は、fitting関数を
y = theta0 + theta1 * x + theta2 * x^2
に変更したことです。

具体的なコードは以下のようになります。
matrixを使ったことでコードがシンプルになりました。

###############
# 多項式回帰の実装
###############

import numpy as np
import matplotlib.pyplot as plt

### (1) データ読み込み ###
trainData = np.loadtxt('kodomoShinchouTaijyu.txt', delimiter=',', skiprows=0)

trainDataX = trainData[:, 0]
trainDataY = trainData[:, 1]

#plt.plot(trainDataX, trainDataY, 'o')
#plt.show()

### (2) データの標準化
mu = trainDataX.mean() # 平均
sigma = trainDataX.std() # 標準偏差

def standaradize(x):
	return (x - mu)/sigma

trainDataXSTD = standaradize(trainDataX)

# fitting 関数を2次関数にする
# y = theta0 + theta1 * x + theta2 * x^2

# 学習データをマトリクスとしてまとめる
# 2次関数でfittingするので2次まで
def toMatrix(x):
	return np.vstack([np.ones(x.shape[0]), x, x**2]).T

X = toMatrix(trainDataXSTD)
#print(X)
# パラメータの初期値
theta = np.random.rand(3)

### 線形fitting ###
# fitting関数 (線形回帰)
def f(x):
	return np.dot(x, theta)

# MSE関数(最小2乗の損失関数)
def E(x, y):
	return 0.5 * np.sum( (y - f(x)) ** 2)

### 学習 ###
ncount = 0 # 更新回数
eta = 1e-2 #学習率
diff = 1 # 誤差

# 学習する
error = E(X, trainDataY)
while diff > 1e-3: # 損失関数の変化が小さくなるまでループする
	# 勾配降下法の実行
	theta = theta - eta * np.dot(f(X) - trainDataY, X)[f:id:wshinya:20180325151001p:plain]
	# 1つ前のステップの誤差との差分
	currentError = E(X, trainDataY)
	diff = error - currentError
	error = currentError
	# 途中経過を出力
	ncount += 1
	#log = '{}: t0 = {:.3f} t1 = {:.3f}, diff={:.4f}'
	#print(log.format(ncount, t0, t1, diff) )


### 結果をグラフにする
x = np.linspace(-2, 2, 100)
plt.plot(trainDataXSTD, trainDataY, 'o')
plt.plot(x, f(toMatrix(x)))
plt.show()

実行結果は以下のようなグラフになりました。

f:id:wshinya:20180325151001p:plain
2次関数でfittingした結果
直線で近似した時よりもxが小さいところでよくfitしていることがわかります。