Python入門トップページ


目次

  1. データを眺める
  2. モデル1:単回帰分析
  3. モデル2:2次式を加える
  4. モデル3:3次式を加える
  5. モデル4:sinカーブを加える
  6. モデル5:cosカーブを加える

線形回帰モデル

モデル5:cosカーブを加える

モデル

前のページでは2次式に sin カーブの項を加えた回帰式を求めた.ここではさらに cos(x) の項も加えた

\begin{equation} y = w_0 + w_1x + w_2 x^2 + w_3 \sin(x) + w_4 \cos(x) \end{equation}
で回帰式を求めてみよう.

目次に戻る

関数を定義する

まず,必要なライブラリを読み込んだ後に回帰式と残差2乗和を取得する関数を定義する.回帰式(15行目)を僅かに変更するだけである.

import numpy as np
import pandas as pd
import scipy.optimize as optimize # 最適化
import matplotlib.pyplot as plt

# 高解像度ディスプレイ用
from IPython.display import set_matplotlib_formats
# from matplotlib_inline.backend_inline import set_matplotlib_formats # バージョンによってはこちらを有効に
set_matplotlib_formats('retina')

"""
関数の定義
"""
def my_func(w, x):
    y = w[0] + w[1] * x + w[2] * x ** 2 + w[3] * np.sin(x) + w[4] * np.cos(x)
    return y

"""
残差2乗和を求める関数
Residual Sum-of-Squares
"""
def get_rss(w, x, y):
    y_pred = my_func(w, x)
    error = (y - y_pred)**2
    return np.sum(error)

目次に戻る

CSVファイルを開いて最適化を行う

推定するパラメータ数は5であるので,初期値の設定を変更する.

# CSV ファイルを読み込む
url = "https://github.com/rinsaka/sample-data-sets/blob/master/lr.csv?raw=true"
df = pd.read_csv(url)

# NumPy 配列に変換する
x_data = df.loc[:, 'x'].values
y_data = df.loc[:, 'y'].values

# ネルダーミード法による最適化を行う
w = np.array([0.1, 0.1, 0.1, 0.1, 0.1]) # 初期値を設定
results_nm = optimize.minimize(get_rss, w, args=(x_data, y_data), method='Nelder-Mead')
print(results_nm)
 final_simplex: (array([[ 6.14213317, -0.16054673, -0.00917598, -3.15365299, -1.22107265],
       [ 6.14218394, -0.16056565, -0.00917504, -3.15367026, -1.22108292],
       [ 6.14210019, -0.1605204 , -0.00917946, -3.15362142, -1.22107644],
       [ 6.14214299, -0.16052485, -0.00917924, -3.15364404, -1.22107284],
       [ 6.14221352, -0.16059761, -0.00917149, -3.15371283, -1.22104053],
       [ 6.14208391, -0.16051741, -0.0091797 , -3.15365333, -1.22109172]]), array([36.53093255, 36.53093256, 36.53093256, 36.53093259, 36.53093259,
       36.5309326 ]))
           fun: 36.53093254743526
       message: 'Optimization terminated successfully.'
          nfev: 870
           nit: 547
        status: 0
       success: True
             x: array([ 6.14213317, -0.16054673, -0.00917598, -3.15365299, -1.22107265])

上の結果を確認すると,目的関数すなわち残差2乗和が 36.53 となり,3次式の 143.93sinカーブを使った 67.71 から大きく減少したことがわかる.最適化での繰り返し回数 nit (Number of iterations performed by the optimizer) は 547 となり,3次式の 453 から増加していることもわかる.

目次に戻る

グラフを描く

最後に回帰式を散布図に重ねて描いてみる.

# 最適解を使って回帰直線のデータを作成する
x_plot = np.linspace(0, 10, 100)
y_pred = my_func(results_nm["x"], x_plot)

# グラフを描く
fig, ax = plt.subplots(1, 1, figsize=(6, 4))
ax.scatter(x_data, y_data, label="data")
ax.plot(x_plot, y_pred, label='model 5')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_xlim(0,10)
ax.set_ylim(0,10)
ax.legend()
# plt.savefig('lr-model5.png', dpi=300, facecolor='white')
plt.show()
lr-model5.png

比較対象として,モデル4(sinカーブ)の結果も示しておきます.

  lr-model4.png

すべてのモデルでの結果を1つのグラフにまとめてみます.

  llr-models

目次に戻る