多項式回帰(polynomial regression)

重回帰分析の式と似ているが、よく見ると異なる。

 

以下が多項式回帰の式である。

 

y = b0 + b1*x1 + b2*x1^2 + .... + bn*x1^n

 

重回帰分析では、係数がb0、b1、、、、となるたびに独立変数も増えていったが、

多項式回帰では、その代わりに、power(指数)の数が増えていき、独立変数は1つだけである。

 

じゃあ多項式回帰を使うのはいつ??

f:id:minmin_std:20191231130213p:plain

上記のようなデータ分布の場合、線形単回帰でうまく予測できるが、以下のようなデータ分布の場合うまく予想できない。

f:id:minmin_std:20191231130333p:plain

そう言った場合に多項式回帰を使うと、指数の項が入っているため、うまく放物線を近侍できる。

f:id:minmin_std:20191231130446p:plain

実際は、線形単回帰や重回帰を使ってうまくいかなかった時、このようなデータになっていることがあり、その時に多項式回帰を使うとうまくいく。

 

例えば、病気がどのように広がり、パンデミックが領土全域にどのように広がっていくかを説明するために使われる。

 

ちなみに多項式回帰は線形かと言われるとそうである場合とそうでない場合がある。

線形非線形の理解はこちらのURLを見るとわかりやすい。

https://oshiete.goo.ne.jp/qa/2113039.html

 

結論を言うと多項式回帰になるのは、重回帰分析の特別なケースである。

 

つまり多項式回帰は新しいタイプの回帰ではなく、重回帰分析の1つのバージョンである。

 

ここで1つの疑問があるかもしれない。

 

回帰では独立変数同士が互いに高い相関があるとうまく分析できなかった。

多項式回帰の式をもう一度見てみると

y = b0 + b1*x1 + b2*x1^2 + .... + bn*x1^n

そもそも同じ独立変数を使っており、非常に高い相関があるのでは?と思う。

 

 

^^^^^^^^^^^^^^^^^^^^^^^^^^^

 

今回の予測

使うデータは以下のものである。

Position

Level

Salary

Business Analyst

1

45000

Junior Consultant

2

50000

Senior Consultant

3

60000

Manager

4

80000

Country Manager

5

110000

Region Manager

6

150000

Partner

7

200000

Senior Partner

8

300000

C-level

9

500000

CEO

10

1000000

levelを使ってSalaryを予測する。

 

なので特徴行列にはlevelの列を、目的ベクトルにはSalaryの列を使う。

 

ここで注意したいのが、

X = dataset.iloc[:, 1].valuesと記述すると、python側がXをベクトルとして認識してしまうことだ。

そのため

X = dataset.iloc[:, 1:2].valuesこのように記述する。こうするとpythonはXを行列として認識してくれる。

 

また今回はトレーニングセットとデータセットに分割することはしない。と言うのも、データ数が少ないし、また正確性を高めたいから、少しでも多くのデータを使いたいからである。

 

そしてFeature Scalingも行わない。なぜなら独立変数が1つしかなく、スケールをおなじにする必要がないからである。

 

Linear Regression modelとPolynomial Regression modelを作る

なぜ2つのモデルを作るかと言うと、2つを比較させたいからである。

linear regressionの方は今までやってきた方法と同じである。

from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X,y)

 

一方、polynomial regressionは新しいライブラリを使う。

from sklearn.preprocessing import PolynomialFeatures

poly_reg = PolynomialFeatures(degree = 2)

 

さて、ここでPolynomialFeaturesクラスについて見ていく。

  • degree

 多項式の次数。今回は二次の項まで考慮。

  • interaction_only

 Trueにすると交互作用項だけ出力します。交互作用項というのは、つまりX[:,0]*X[:,1]のようなものです。よくわからない笑

  • include_bias

 デフォルトではTrueで、バイアス項(=すべて1の列)を入れてくれます。sklearnの他のモデルで切片を推定してくれないものは少ないので、ほとんどのケースではFalseにしても差し支えないでしょう。

今回はデフォルトなのですべて1の列が最初に入る。

  • order

 出力の列の順番が変わります。普通は意識しなくてもいいでしょう。意識してない。

 

そしてpoly_regで作ったモデルにデータを入れて新しい特徴行列を作る。

X_poly = poly_reg.fit_transform(X)

 

fit_transformを使うかはこれがめっちゃわかりやすい!

https://qiita.com/makopo/items/35c103e2df2e282f839a

 

fitとfit_transformとtransformなどの違いがまとめられている。

 

X_polyの中身を見てみる。

f:id:minmin_std:20191231150049p:plain

1列目にすべて1の列が追加されており、2列目は元の X行列の1列目の値、3列目にはそれを二乗した値が入っている。

 

1列目はbackward eliminationで手動で追加したb0にかけられる項であり、polynomialfeaturesでは自動的に追加される。

 

そしてこの新しくできたX_polyをmultiple linear regressionモデルに適用させる必要がある。

そこで新しいモデルを作る。

lin_reg_2 = LinearRegression()

そしてデータをモデルに入れる。
lin_reg_2.fit(X_poly,y)

 

 

グラフで図示して比較してみる

まずはLinearRegressionで予測したものを図示する。

plt.scatter(X,y,color='red')
plt.plot(X,lin_reg.predict(X),color='blue')
plt.title('Truth or Bluff(Linear Regression)')
plt.xlabel('postion lebel')
plt.ylabel('salary')
plt.show()

f:id:minmin_std:20191231152323p:plain

赤い点が実際の観測点であり、青い線が予測した線である。直線なのはLinear Regressionモデルを使っているからである。

 

次にPolynomial regressionで予測したものだ。

plt.scatter(X, y, color = 'red')
plt.plot(X, lin_reg_2.predict(poly_reg.fit_transform(X)), color = 'blue')

ここでpredictの第一引数がX_polyではないのに注意したい。X_polyは既に定義されているので使わない。????
plt.title('Truth or Bluff (Polynomial Regression)')
plt.xlabel('Position level')
plt.ylabel('Salary')
plt.show()

 

f:id:minmin_std:20191231161743p:plain

きれいに放物線を描けいており、ここから、polynomial regressionモデルは線形回帰モデルでないことがわかる。

 

線形回帰モデルでは直線が得られ、非線形回帰モデルでは曲線であったり、非常に複雑な数学分布が得られる。

 

多項式回帰の式の項(degree)を増やしてみる

先ほどのpolynomial regressionモデルではdegree=2、つまりx^2の項まで考慮していた。

ではx^3の項まで考慮するとどうなるのか。

degree=3にしてもう一度図示してみる。

f:id:minmin_std:20191231163208p:plain

すると結果は、先ほどのモデルの精度より高くなっていることがわかる。

degree=4にしてみる。

f:id:minmin_std:20191231163548p:plain

ほとんど完璧な精度になった。

 

もう少し高度にしてみる

先ほどまでやっていたことは、1~10までの間に1つずつ直線を入れていった処理になっている。これを0.1ずつの間に直線を入れていけば、より精度が上がるし、より曲線に近くなる。

 

新たな行列X_gridを作る。

X_grid = np.arange(min(X),max(X),0.1)
X_grid = X_grid.reshape(len(X_grid),1)

 

そしてそのX_gridに対して予測を行う

plt.scatter(X, y, color = 'red')
plt.plot(X_grid, lin_reg_2.predict(poly_reg.fit_transform(X_grid)), color = 'blue')
plt.title('Truth or Bluff (Polynomial Regression)')
plt.xlabel('Position level')
plt.ylabel('Salary')
plt.show()

f:id:minmin_std:20191231164830p:plain

さっきまでは、滑らかな曲線ではなかったが、今回は滑らかな曲線になっている。