最急降下法を用いた多項式回帰と次数について

# はじめに
複数の点が与えられている場合、それらを滑らかに結ぶ多項式近似曲線を作成することを考える。その場合、点群と多項式近似曲線の距離の差の2乗から定義される2乗誤差の和である損失関数を最適化させることで、多項式近似曲線を最適化させる。このとき、多項式の次数を変化させた場合、近似曲線にどのような影響が表れるのかを考察する。
ただし、最適化手法は、最小2乗法などが考えられるが、今回は最急降下法を用いる。

今回の記事は、以下に示す大きい次数を採用する場合の過学習について言及した。

![4次回帰予測.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/882f8370-07bc-4be4-85de-a20b43d44691.png)


# アルゴリズム
## 損失関数
以下の記事を参考にし、$M$次多項式の場合の近似曲線を作成するプログラムを作成する。

https://qiita.com/arairuca/items/0589d67af42878d6dcc6

まず、近似曲線を以下のように定義する。

```math
f(x)=\sum^{M}_{k=0}a_k x^k
```

次に、以下のような損失関数を考える。

``` math
Error(a,b)=\frac{1}{m}\Sigma^{m}_{i=1} err(i)=\frac{1}{m}\Sigma^{m}_{i=1}(y_i-f(x_i))^2
```


ここで、損失関数を最適化（最小化）させるときの$a_k$を最急降下法で探索する。

## 最急降下法
単純化のため、2次元で考える。
解空間の最小値を取る極値が一つ解空間の谷が一つの場合に有効な最小値の推定手法である。$(a,b)$に初期値を与え、以下のような式を用いて$(a,b)$を更新していく。つまり、$(a_k,b_k)$を算出する。


``` math
a_{k+1}=a_{k}-\alpha(\frac{\delta }{\delta a_{i}}Error(a_{k},b_{k}))
```

``` math
b_{k+1}=b_{k}-\beta(\frac{\delta }{\delta b_{k}}Error(a_k,b_k))
```
ただし$\alpha,\beta$は$(a,b)$の学習率である。

これは、ボールが坂に下り落ちる様に似ている。偏微分係数は各方向の坂の傾きと捉えることができる。

ただし、今回は学習率を共通の定数$\alpha$とした。

# プログラム

```python line_guess.py
import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
import math

L=2
num=10
x=np.linspace(-L,L,num)
y=(2*x+2)+np.random.normal(0,1,num)

# 微分に用いる微小変化分
h=1.0*10**-5

## Mは予測回帰の次数
# M=1のときは単回帰、M=2のときは二次回帰、M=3のときは三次回帰
M=1
M_ary=5*np.ones(M+1)

def error(M_ary):
  err=0
  for i in range(num):
    X=0
    for p in range(M+1):
        X=X+M_ary[p]*x[i]**p
    err=err+(1/num)*(y[i]-X)**2
  return err

# 積算回数
iterations=100
# 学習率
alpha=0.01
# 損失関数
error_pre=[]

for i in range(iterations):
  for p in range(0,M+1):
    M_ary2=np.copy(M_ary)
    M_ary2[p]=M_ary[p]+h
    d_err_M=(error(M_ary2)-error(M_ary))/h
    M_ary[p]=M_ary[p]-alpha*d_err_M
#予測データ描写用  
Num=100
xx_ary=np.linspace(-L,L,Num)
yy_ary=np.zeros(Num)
for k in range(Num):
  yyy=0
  for p in range(M+1):
      yyy+= M_ary[p] * xx_ary[k]**p
  yy_ary[k]=yyy

title=str(M)+"次回帰予測"
plt.title(title)
plt.scatter(x,y,label="データ",color="blue")
plt.plot(xx_ary,yy_ary,label="単回帰予測",color="red")
plt.legend()
plt.xlabel("x")
plt.ylabel("y")
plt.savefig(title+".png")
plt.show()
```

# 結果
上記のプログラムを$M$の値を変更して実行すると以下のようになる。（実際は、1次関数にランダム性を加えた点群をサンプルとしている）


## 1次

![1次回帰予測.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/7090f6e9-878c-44c7-8339-5aee8ad7fae3.png)

当然上手くフィッティングできている。

## 2次

![2次回帰予測.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/9ea8fdb9-3544-48b2-8560-42c0b4aa3944.png)

少し、外れてしまう点もあるが、おおむねフィッティングできている。

## 3次

![3次回帰予測.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/3df48965-59ff-45d6-8a3d-61edaaf63958.png)

少し、細部の学習をし過ぎている。

## 4次


![4次回帰予測.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/882f8370-07bc-4be4-85de-a20b43d44691.png)

細部の影響を受けすぎている。


## 5次

![5次回帰予測.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/a3e1fff5-cb4e-489a-a63d-feb19ece43f1.png)

途中で値が急激に変化してしまった。

そこで、学習率$\alpha=0.001$と10分の1に小さくして、計算回数を10倍にしたときのグラフを以下に示す。



![5次回帰予測_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/73839330-c9e9-425c-bf17-0967167b5bd6.png)

このように、次数が増えると細部の微細な点の挙動に反応してしまい、複雑なフィッティングになってしまい、”近似”曲線の醍醐味である”単純な”関数で近似するという意味がなくなってしまう。

## 6次

学習率$\alpha=0.001$のときのグラフを以下に示す。

![6次回帰予測_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/d6af07e9-3ff6-483b-a306-4caa4706b721.png)



# まとめ
今回は、最急降下法を用いた多項式回帰について次数を変化させるとどのような影響がでるのかを調査した。単に、次数は大きくすれば精度が上がるという訳ではなく、細部に影響を受けてしまう過学習の影響も考慮する必要性がある。したがって、多項式近似を行う場合は、その現象の性質や背景を考え、最適な次数を予め予想しておくことが大切である。（それが出来れば苦労はしないが、、）