【ラビットチャレンジ】 機械学習 第2章 非線形回帰モデル


#非線形回帰モデル
- 複雑な非線形構造を内在する現象に対して，非線形回帰モデリングを実施．
- 回帰関数として，基底関数($\phi$)と呼ばれる既知の非線形関数とパラメータベクトルの線形結合を考える．
<br>
→ 未知パラメータを線形回帰モデルと同様に最小二乗法や最尤法により推定できる．$$y_i=w_0+\sum_{i=1}^mw_j\phi_j(\boldsymbol{x})+\epsilon_i$$
- よく使われる基底関数
 - 多項式関数
 - ガウス型基底関数
 - スプライン関数/Bスプライン関数

## 基底展開法
**線形回帰と同じ枠組みで推定可能**
-説明変数$$\boldsymbol{x}_i=(x\_{i1},x\_{i1},\cdots,x\_{im})\in\mathbb{R}^m$$

-非線形関数ベクトル$$\boldsymbol{\phi}(\boldsymbol{x}\_i) = (\phi\_1(\boldsymbol{x}\_i),\phi\_2(\boldsymbol{x}\_i),\cdots,\phi\_k(\boldsymbol{x}\_i))^T\in\mathbb{R}^k$$
-非線形関数の計画行列$$\Phi^{(train)}=(\boldsymbol{\phi}(\boldsymbol{x}\_1),\boldsymbol{\phi}(\boldsymbol{x}\_2),\cdots,\boldsymbol{\phi}(\boldsymbol{x}\_n))^T\in\mathbb{R}^{n\times k}$$
-最尤法による予測値$$\hat{\boldsymbol{y}}=\Phi(\Phi^{(train)T}\Phi^{(train)})^{-1}\Phi^{(train)T}\boldsymbol{y}^{(train)}$$

#正則化法
- モデルの複雑さ
 - チューニングパラメータ（基底関数の数やバンド幅）によりモデルの複雑さが変化
 - 適切な複雑さを持つモデルを適用しないと過学習や未学習の問題が発生
 - 未学習：学習データに対して十分小さな誤差が得られないモデル
 - 過学習：小さな誤差は得られたが，テスト集合誤差との差が大きいモデル

- モデルの複雑さに伴って，その値が大きくなる**正則化項（罰則項）$R$** を課した関数の最小化を行う．
- 正則化項（罰則項）$R$
 - 形状によっていくつもの種類があり，それぞれ推定量の性質が異なる
 - 正則化項なし → 最小２乗推定
 - L2ノルムを利用 → Ridge推定量 縮小推定
 - L1ノルムを利用 → Lasso推定量 スパース推定
- 正則化（平滑化）パラメータ $\gamma\hspace{6pt} (>0)$
 - モデルの曲線の滑らかさを調節する．→適切に決める必要あり．
$$S_{\gamma}=(\boldsymbol{y}-\boldsymbol{\Phi w})^T(\boldsymbol{y}-\boldsymbol{\Phi w})+\gamma R(\boldsymbol{w})$$

# モデルの汎化性能測定
## 汎化性能
- 学習に使用した入力ではなく，新たな入力に対する予測性能
 - （学習誤差ではなく）汎化性能（テスト誤差）が小さいものが良い性能を持ったモデル．

## モデルの評価
- ホールドアウト法
 - 有限のデータを学習用とテスト用の２つに分割する．
 - 学習用データとテスト用データの比率の調整が難しい．
 - つまり，手元にデータが大量にある場合を除いて，良い性能評価を得られない．

- クロスバリデーション法（交差検証）
 - データを$N$個に分割し，その一つを検証データ，残りを学習データとして各モデルの精度を$N$回計測する．
 - その精度の平均をCV（クロスバリデーション）値と呼ぶ．


# ハンズオン

```python:skl_nonlinear_regression.ipynb
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns #matplotlibのラッパー

%matplotlib inline
```

```python:skl_nonlinear_regression.ipynb
#seaborn設定
sns.set() #設定をクリアしてデフォルトに
#背景変更
sns.set_style("darkgrid", {'grid.linestyle': '--'})
#大きさ(スケール変更)
sns.set_context("paper")
```

```python:skl_nonlinear_regression.ipynb
n=100

def true_func(x):
 z = 1-48*x+218*x**2-315*x**3+145*x**4
 return z

def linear_func(x):
 z = x
 return z
```


```python:skl_nonlinear_regression.ipynb
# 真の関数からノイズを伴うデータを生成

# 真の関数からデータ生成
data = np.random.rand(n).astype(np.float32) # random.rand(n): 0-1の乱数をn作る．
data = np.sort(data)
target = true_func(data)

# 　ノイズを加える
noise = 0.5 * np.random.randn(n) # random.randn(n): 平均0, 標準偏差1の正規分布．つまり，-１~1の値を出力．
target = target + noise

# ノイズ付きデータを描画

plt.scatter(data, target, label='data')

plt.title('NonLinear Regression')
plt.legend(loc=2)
```

![output_3_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375106/5f7ec16d-a682-e85a-0d2f-75fde96117aa.png)



```python:skl_nonlinear_regression.ipynb

# 線形回帰を行う
from sklearn.linear_model import LinearRegression

clf = LinearRegression()
data = data.reshape(-1,1) # 次元0に-1を指定すると，縦ベクトルとなる．
target = target.reshape(-1,1) # 次元0に-1を指定すると，縦ベクトルとなる．
clf.fit(data, target)

p_lin = clf.predict(data)

plt.scatter(data, target, label='data')
plt.plot(data, p_lin, color='darkorange', marker='', linestyle='-', linewidth=1, markersize=6, label='linear regression')
plt.legend()
print(clf.score(data, target)) # 決定係数を出力
```

 0.41320782764293906


![output_4_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375106/612fe77d-cba2-b55b-af10-e2fcddc1eeeb.png)

```python:skl_nonlinear_regression.ipynb
# KernelRidgeによるガウスカーネルモデル．L2制約付き最小二乗学習
from sklearn.kernel_ridge import KernelRidge

clf = KernelRidge(alpha=0.0002, kernel='rbf')
# Parameters
# alpha : ペナルティの大きさ
# kernel : RBFカーネル(Radial basis function kernel)

clf.fit(data, target)

p_kridge = clf.predict(data)

# グラフ出力
plt.scatter(data, target, color='blue', label='data')

plt.plot(data, p_kridge, color='orange', linestyle='-', linewidth=3, markersize=6, label='kernel ridge')
plt.legend() # 凡例
#plt.plot(data, p, color='orange', marker='o', linestyle='-', linewidth=1, markersize=6)

print(clf.score(data, target))
```

 0.8810414281073834

![output_5_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375106/c534324f-167c-f3e3-7ae1-3595c7fb69b5.png)


```python:skl_nonlinear_regression.ipynb

#Ridge

from sklearn.metrics.pairwise import rbf_kernel
from sklearn.linear_model import Ridge

kx = rbf_kernel(X=data, Y=data, gamma=50) # 放射基底関数カーネルを計算する
#KX = rbf_kernel(X, x)

#clf = LinearRegression()
clf = Ridge(alpha=30)
clf.fit(kx, target)

p_ridge = clf.predict(kx)

plt.scatter(data, target,label='data')
for i in range(len(kx)):
 plt.plot(data, kx[i], color='black', linestyle='-', linewidth=1, markersize=3, label='rbf', alpha=0.2)

#plt.plot(data, p, color='green', marker='o', linestyle='-', linewidth=0.1, markersize=3)
plt.plot(data, p_ridge, color='green', linestyle='-', linewidth=1, markersize=3,label='ridge regression')
#plt.legend()

print(clf.score(kx, target))
```

 0.8584537190867131

![output_6_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375106/b43aea0a-e462-7ad9-8722-55d37dde8da1.png)


```python:skl_nonlinear_regression.ipynb
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
```


```python:skl_nonlinear_regression.ipynb
#PolynomialFeatures(degree=1)

plt.scatter(data, target)
# 多項式基底を作成する．

deg = [1,2,3,4,5,6,7,8,9,10]
for d in deg:
 regr = Pipeline([
 ('poly', PolynomialFeatures(degree=d)),
 ('linear', LinearRegression())
 ])
 regr.fit(data, target)
 # make predictions
 p_poly = regr.predict(data)
 # plot regression result
 plt.plot(data, p_poly, label='polynomial of degree %d' % (d))
 plt.legend(loc=2)
 print('{0:02d} {1:.15f}'.format(d, regr.score(data, target)))
```

 01 0.413207829272240
 02 0.518749151434800
 03 0.628357884957680
 04 0.887010123781958
 05 0.887044166055853
 06 0.887053035036568
 07 0.889536170289383
 08 0.889801333789919
 09 0.890876035316865
 10 0.890760870143186

![output_8_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375106/1755f380-744a-b278-13c8-c52168f25a09.png)


```python:skl_nonlinear_regression.ipynb
#Lasso

from sklearn.metrics.pairwise import rbf_kernel
from sklearn.linear_model import Lasso

kx = rbf_kernel(X=data, Y=data, gamma=5)
#KX = rbf_kernel(X, x)

# alphaを減らしてiterを増やした
lasso_clf = Lasso(alpha=0.001, max_iter=100000)
lasso_clf.fit(kx, target)

p_lasso = lasso_clf.predict(kx)

plt.scatter(data, target)

#plt.plot(data, p, color='green', marker='o', linestyle='-', linewidth=0.1, markersize=3)
plt.plot(data, p_lasso, color='green', linestyle='-', linewidth=3, markersize=3)

print(lasso_clf.score(kx, target))
```

 0.8798552752769152

![output_9_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375106/4b7d8027-145b-329f-07b8-ffbd520cc835.png)


```python:skl_nonlinear_regression.ipynb
#from sklearn import cross_validation, preprocessing, linear_model, svm
from sklearn import model_selection, preprocessing, linear_model, svm
# model_selectionに変更．

# SVR-rbf
clf_svr = svm.SVR(kernel='rbf', C=1e3, gamma=0.1, epsilon=0.1)
target1=np.reshape(target,(-1))
clf_svr.fit(data, target1)
y_rbf = clf_svr.predict(data)

# plot
plt.scatter(data, target, color='darkorange', label='data')
plt.plot(data, y_rbf, color='red', label='Support Vector Regression (RBF)')
plt.legend()
plt.show()
```
![output_10_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375106/be3afc9b-f40f-1fa2-6a0d-670f0c1c7616.png)


```python:skl_nonlinear_regression.ipynb
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.1, random_state=0)
```


```python:skl_nonlinear_regression.ipynb
from keras.callbacks import EarlyStopping, TensorBoard, ModelCheckpoint

# cb_cp = ModelCheckpoint('./out/checkpoints/weights.{epoch:02d}-{val_loss:.2f}.hdf5', verbose=1, save_weights_only=True)
cb_cp = ModelCheckpoint('./weights.{epoch:02d}-{val_loss:.2f}.hdf5', verbose=1, save_weights_only=True) # ディレクトリの変更

cb_tf = TensorBoard(log_dir='./out/tensorBoard', histogram_freq=0)
```

 Using TensorFlow backend.



```python:skl_nonlinear_regression.ipynb
from keras.models import Sequential
from keras.layers import Input, Dense, Dropout, BatchNormalization
from keras.wrappers.scikit_learn import KerasRegressor

# 隠れ層の活性化関数をRelu，出力層の活性化関数をSigmoidとしてSequentialモデルを構築する
def relu_model():
 model = Sequential()
 model.add(Dense(10, input_dim=1, activation='relu'))
 model.add(Dense(8, activation='relu'))
 model.add(Dense(5, activation='relu'))
 model.add(Dense(3, activation='sigmoid'))
 model.add(Dense(1))

 model.compile(loss='mean_squared_error', optimizer='adam')
 return model

# use data split and fit to run the model
estimator = KerasRegressor(build_fn=relu_reg_model, epochs=100, batch_size=5, verbose=1)

history = estimator.fit(x_train, y_train, callbacks=[cb_cp, cb_tf], validation_data=(x_test, y_test))
```

 Train on 90 samples, validate on 10 samples
 Epoch 1/100
 90/90 [==============================] - 6s 71ms/step - loss: 1.4577 - val_loss: 6.3816

 Epoch 00001: saving model to ./weights.01-6.38.hdf5
 Epoch 2/100
 90/90 [==============================] - 4s 42ms/step - loss: 1.6469 - val_loss: 1.5418

 Epoch 00002: saving model to ./weights.02-1.54.hdf5
 Epoch 3/100
 90/90 [==============================] - 4s 42ms/step - loss: 0.8780 - val_loss: 1.3294

 Epoch 00003: saving model to ./weights.03-1.33.hdf5
 Epoch 4/100
 90/90 [==============================] - 4s 49ms/step - loss: 0.9645 - val_loss: 1.0802

 Epoch 00004: saving model to ./weights.04-1.08.hdf5
 Epoch 5/100
 90/90 [==============================] - 5s 55ms/step - loss: 0.5584 - val_loss: 1.0554

 Epoch 00005: saving model to ./weights.05-1.06.hdf5
 Epoch 6/100
 90/90 [==============================] - 4s 49ms/step - loss: 0.6439 - val_loss: 0.8581

 Epoch 00006: saving model to ./weights.06-0.86.hdf5
 Epoch 7/100
 90/90 [==============================] - 4s 47ms/step - loss: 0.5219 - val_loss: 0.8335

 Epoch 00007: saving model to ./weights.07-0.83.hdf5
 Epoch 8/100
 90/90 [==============================] - 4s 46ms/step - loss: 0.5783 - val_loss: 0.7498

 Epoch 00008: saving model to ./weights.08-0.75.hdf5
 Epoch 9/100
 90/90 [==============================] - 5s 55ms/step - loss: 1.2041 - val_loss: 2.0974

 Epoch 00009: saving model to ./weights.09-2.10.hdf5
 Epoch 10/100
 90/90 [==============================] - 5s 52ms/step - loss: 1.4860 - val_loss: 0.9596

 Epoch 00010: saving model to ./weights.10-0.96.hdf5
 Epoch 11/100
 90/90 [==============================] - 4s 49ms/step - loss: 0.7680 - val_loss: 0.9596

~~ 中略 ~~
 Epoch 00096: saving model to ./weights.96-0.41.hdf5
 Epoch 97/100
 90/90 [==============================] - 4s 45ms/step - loss: 0.3910 - val_loss: 0.3375

 Epoch 00097: saving model to ./weights.97-0.34.hdf5
 Epoch 98/100
 90/90 [==============================] - 4s 47ms/step - loss: 0.3179 - val_loss: 0.4850

 Epoch 00098: saving model to ./weights.98-0.48.hdf5
 Epoch 99/100
 90/90 [==============================] - 5s 52ms/step - loss: 0.2999 - val_loss: 0.1813

 Epoch 00099: saving model to ./weights.99-0.18.hdf5
 Epoch 100/100
 90/90 [==============================] - 4s 48ms/step - loss: 0.3322 - val_loss: 0.2278

 Epoch 00100: saving model to ./weights.100-0.23.hdf5



```python:skl_nonlinear_regression.ipynb
y_pred = estimator.predict(x_train)
```

 90/90 [==============================] - 0s 4ms/step



```python:skl_nonlinear_regression.ipynb
plt.title('NonLiner Regressions via DL by ReLU')
plt.plot(data, target, 'o')
plt.plot(data, true_func(data), '.')
plt.plot(x_train, y_pred, "o", label='predicted: deep learning')
#plt.legend(loc=2)
```

![output_15_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375106/6e3739e6-9c97-d04d-e758-92762b3985aa.png)


```python:skl_nonlinear_regression.ipynb
print(lasso_clf.coef_)
```

 [ -0. -0. -0. -0. -0. -0.
 -0. -0. -0. -7.960358 -5.6067443 -0.5237518
 -0.4339014 -2.9543405 -0.9058812 -0. -0. -0.
 -0. -0. -0. -0. -0. -0.
 -0. -0. -0. -0. -0. -0.
 -0. -0. -0. -0. -0. -0.
 -0. -0. -0. -0. -0. -0.
 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0.
 0. 0. 0. 0. 0. 0.
 -0. -0. -0. -0. -0. -0.
 -0. -0. -0. -0. -0. -0.
 -0. -0. -0. -0. -0. -0.
 -0. -0. -0. -0. -0. -0.
 -0. -0. -0. -0. -2.4459205 -13.672384
 -0. -0. -0. -0. ]


<br>
<br> 

[DeepLearning ラビットチャレンジ](http://ai999.careers/rabbit/　"ラビットチャレンジリンク")
<img src="http://ai999.careers/tools/wp/wp-content/uploads/2018/12/card.png" width=50%>