ラビットチャレンジレポート #7非線形回帰

# 非線形回帰
### 非線形とは
* 線形でないもの
* 2次関数や3次関数

* データの構造は必ず線形で捉えられるわけではない！
* つまり、線形で捉えられないときは非線形で捉えられる仕組みが必要！

### 線形回帰のおさらい
* 単回帰の場合（変数が1つ）
    * $y=w_0+w_1x_1$
* 重回帰の場合（変数が2つ以上）
    * $y=w_0+w_1x_1+w_2x_2+・・・・+w_nx_n$

### 非線形な回帰
* 非線形なので直線、つまり1次関数でない式を考える
* 例えば、
    * $y=w_0+w_1x_1+w_2x^2+w_3x^3$
    * $y=w_0+w_1sinx_1+w_2cosx_2$

* 線形回帰の式と似ている
* 違いは
    * $x$の代わりに$x^2$
    * $x$の代わりに$sinx$
となっている

* xの代わりに$\phi(x)$を用いれば線形回帰の式と同じ感じになる！
    * $\phi(x)$はxの関数
    * $\phi(x)=x^2$や$\phi(x)=sinx$

* つまり先ほどの2つの式は下記のようにかける

```math
y = w_0 + w_1 \phi(x_1)+ w_2 \phi(x_2)+ ・・・・+ w_n \phi(x_n)
```

* xを$\phi(x)$に代えても$w$については線形（1次関数のまま）
    * $wx^2$はxについては2次関数であるが、wについては1次関数のまま
    * つまり何を変数に見るかでその式が1次関数か、2次関数か決まる

* 予測modelは下記の式であるは重み$w$について線形であると言える

```math
\hat{y}=w_0+w_1\phi(x_1)+w_2\phi(x_2)+・・・+w_n\phi(x_n)
```

* 線形モデルによる非線形回帰と言える
* 線形モデルを **基底展開法**に適用することで非線形回帰分析ができる！

### 基底展開法
* 非線形回帰は$y=w\phi(x)+\varepsilon$という風に表すことができるとわかった（正確には下記）

```math
y=w_0+w_1\phi(x_1)+w_2\phi(x_2)+・・・+w_n\phi(x_n)+\varepsilon
```

* 上記の式をかっこよく書くと

```math
y=w_0+ \sum_{j=1}^m w_j\phi_i(x_i)+\varepsilon_i
```

* 上記の式は線形回帰と似ていることから同じように推定できそう！
* 上記の式の${\phi}_i(x_i)$を **基底関数**という

* 具体的にどんな基底関数が使われるのか？よく使われるのが下記
    * 多項式関数
    * ガウス型基底関数
    * スプライン関数/Bスプライン関数

##### 多項式関数

```math
\phi_j=x^j
```

* 上の多項式関数を適用してみたのが下記になる（$\phi$に多項式を置換した）

```math
\hat{y} = w_0+w_1x_1^1+w_2x_i^2+・・・+w_9x_i^9
```

##### ガウス型基底関数

```math
\phi_j(x)=exp\Biggl(\frac{(x-\lambda_j)^2}{2h_j}\Biggr)
```

### 未学習と過学習
*  **未学習**：学習データに対して十分小さな誤差が得られないモデル
    *  つまり・・
        *  学習するためのデータに対してまだ改善の余地がある状態
        *  工夫次第で誤差を小さくできる
    *  対策
        *  モデルの表現力が低いため、表現力の高いモデルを使用する
*   **過学習**:小さな誤差は得られたけど、テスト集合誤差との差が大きいモデル
    *   つまり・・
        *   学習するためのデータにfitしすぎてテストデータでは誤差が大きくなってしまうこと
        *   学習データに対しては誤差がほぼなくなる代わりに、学習データによりすぎて他のデータに対してはうまく機能しない
    * 対策
        * 1.学習データの数を増やす
        * 2.不要な基底関数（変数）を削除指定表現力を抑止
            * 既定関数の数、位置やバンド幅によりモデルの複雑さが変化
            * 解きたい問題に対して多くの基底関数を用意してしまうと過学習の問題がおこるため適切な既定関数を用意
        * 3.正則化法を利用して表現力を抑止
            * 正則化項を課した関数を最小化
            * 正則化項：形状によっていくつもの種類があり、それぞれ推定量の性質が異なる
            * 正則化パラメータ：モデルの曲線の滑らかさを調節。適切に決める必要がある

```math
S_{\gamma} = (y-\phi w)^T(y-\phi w)+ \gamma R(w)
```

* 基底関数の数が増加するとパラメータ（$\phi$）は増加し、残差は減少する

#### 正則化項の役割
* 無い：最小二乗推定量
* L2ノルムを利用：Ridge推定量
    * L2ノルム：$\sqrt{x_1^2+x_2^2+・・+x_n^2}$
* L1ノルムを利用：Lasso推定量
    * L1ノルム：$|x_1|+|x_2|+・・+|x_n|$

#### 正則化パラメータの役割
小さく：制約面が大きく
大きく：制約面が小さく

#### 汎化性能
* 学習に使用したデータだけでなく、新しいデータに対しする予測性能
    * 汎化誤差が小さいものがよい性能をもつモデル
    * 汎化誤差は学習データとは別に収集された検証データでの性能を図ることで推定
* つまり汎化性能が低いということは過学習の可能性があると考えられる

#### 未学習か過学習か
    * 学習誤差（学習データを使った際の誤差）とテスト誤差（テストデータを使った際の誤差）もどちらも小さい→汎化しているモデルの可能性
    * 学習誤差は小さいがテスト誤差は大きい→過学習の可能性
    * 学習誤差もテスト誤差もどちらも小さくならない→未学習

### モデルの検証
#### ホールドアウト法
* 有限のデータを学習用とテスト用の2つに分割し、「予測精度」や「誤り率」を推定するために使用
    * 学習用を多くすればテスト用が減り学習制度は良くなるが、性能評価の精度は悪くなる
    * 逆にテスト用を多くすれば学習用は減少するので、学習そのものの精度が悪くなることになる
    * 手元にデータが大量にある場合を除いて、良い性能評価を与えないという欠点がある
* 基底展開法に基づく非線形回帰モデルでは、基底関数の数、位置、バンド幅の値とチューニングパラメータをホールドアウト値を小さくするモデルで決定する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2183979/05fb7fee-2800-3ff7-8e08-5da0f17b1f48.png)


#### クロスバリデーション（交差検証）
* 学習に使うデータを変えていく方法
* 下記図は5分割の例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2183979/d74f4c6d-4fb4-69ac-bfa7-58d2342c990e.png)

* 1~5の各精度を計測し、平均を求める（ **CV値**）

* あるモデルをホールドアウト法で検証したところ70%の精度、交差検証で65%だった場合でも、汎化性能の推定としてはCVを利用するようにする


### グリッドサーチ
* 汎化性能を向上させる方法を探す手法
* すべてのチューニングパラメータの組み合わせで評価値を算出
* 最も良い評価を持つチューニングパラメータを持つ組み合わせを「いいモデルのパラメータ」として採用

## 実装演習
* とりあえず、下記のような使うデータを作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2183979/df08351e-4c63-4c16-01f0-6079271f2c7d.png)

#### 1度線形回帰で予測してみる

```python
# Create object
model = LinearRegression()

data = data.reshape(-1,1)
target = target.reshape(-1,1)
model.fit(data, target)
p_lin = model.predict(data)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2183979/f2a08925-24ba-ac64-271b-cf4916424127.png)

```python
model.score(data, target)
# 0.41304913571708723
```

* 全然、fitしていない
* スコアも50%もいっていない。。。

#### 非線形回帰

```python
from sklearn.kernel_ridge import KernelRidge

model = KernelRidge(alpha=0.0002, kernel='rbf')
model.fit(data, target)

p_kridge = model.predict(data)

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

plt.plot(data, p_kridge, color='orange', linestyle='-', linewidth=3, markersize=6, label='kernel ridge')
plt.legend()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2183979/b9c43d2b-a23b-c4b9-3232-363fec8f6db2.png)

* リッジ正則化とガウス型基底関数を用いて非線形回帰分析を行った
* かなりfitしているし、線形回帰より明らかによさそう

```python
model.score(data,target)
# 0.8959047204793744
```

* 線形回帰の約倍の結果になった

#### 過学習

```python
model = KernelRidge(alpha=0, kernel='rbf')
model.fit(data, target)

p_kridge = model.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()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2183979/993defa2-0f1c-cf51-0719-4ebdfe13f859.png)

```python
model.score(data,target)
# 0.9999999999999956
```

* 結果は1に近く、かなりいいモデル！とはさすがにならない。。
* グラフを見ても明らかに過学習している
* これは正則化なしでガウス基底関数のみを使用した
* 正則化によってうまくこの状態を回避していたんだなぁ