はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Python】機械学習の基本「単回帰分析」を実装してみる

はじめに

単回帰分析は機械学習でおそらく一番シンプルなアルゴリズムです。

実は以前C#で実装をしていたのですが、Pythonの勉強も兼ねてPythonでもやっていきたいと思います。
www.hanachiru-blog.com

また理論的なところは爆速でいくので、もし細かい証明などをみたい方は自分で調べてみてください。

では早速みていきましょう。

環境

GoogleColab

アルゴリズム

今回使うアルゴリズム「単回帰分析」で必要な式を一気に列挙します。

損失関数
  •  L(w_0, w_1) = \frac{1}{2M} \sum_{m=0}^{M-1} (yp^{(m)} - yt^{(m)})^2
  •  yp^{(m)} = w_0x_0^{(m)} + w_1x_1^{(m)}
損失関数の偏微分
  •  \frac{\partial L(w_0, w_1)}{\partial w_i} = \frac{1}{M} \sum_{m=0}^{M-1} yd^{(m)}・x_i^{(m)}  (i = 0, 1,…,n)
  •  yd^{(m)} = yp^{(m)} - yt^{(m)}
繰り返しのアルゴリズム
  •  yp^{(k)(m)} = \boldsymbol{w}^{(k)}・\boldsymbol{x}^{(m)}   (1)
  •  yd^{(k)(m)} = yp^{(k)(m)} - yt^{(m)}  (2)
  •  w_i^{(k+1)}  = w_i^{(k)} - \frac{α}{M} \sum_{m=0}^{M-1} yd^{(m)}・x_i^{(m)}  (i = 0, 1,…,n)  (3)

データの用意

今回はUC バークレー大学の UCI Machine Leaning Repository にて公開されている赤ワインのデータセットを利用させていただきます。

UCI Machine Learning Repository: Wine Quality Data Set

昨日GoogleColabでcsvを読み込む方法という記事を書いたので、データの読み込みはそちらを参照してみてください。
www.hanachiru-blog.com

コード

from google.colab import drive
import pandas as pd
import numpy as np

# GoogleDriveのマウントとデータ読み込み
drive.mount('/content/drive')
data = pd.read_csv('drive/My Drive/Colab Notebooks/datasets/winequality-red.csv')

# データをnumpy.ndarray型に変換して格納
ph = data['pH'].values.reshape(-1, 1)
x_list = []
for item in ph:
  x_list.append([1, item])
x = np.asarray(x_list)
yt = data['alcohol'].values

# 入力データ(x0(=1), x1)と重みwから予測値ypを計算する,行列xとベクトwルの内積
def pred(x, w):
  return (x @ w)

# データ系列総数(今回はデータの数が1599コ)
M = x.shape[0]

#入力データ次元数(ダミー変数x0を含む)
D = x.shape[1]

# 繰り返し回数
iters = 50000

# 学習率
alpha = 0.01

# 重みベクトルの初期値(すべての値を1にする)
w = np.ones(D)

# 評価結果記録用(損失関数値のみ記録)
history = np.zeros((0, 2))

for k in range(iters):
  # 予測値ypの計算
  yp = pred(x, w)

  # 誤差の計算
  yd = yp - yt

  #勾配降下法の実装
  w = w - alpha * (x.T @ yd) / M

  # 学習の損失関数を記録
  if k % 100 == 0:
    # 損失関数の計算
    loss = np.mean(yd ** 2) / 2
    history = np.vstack((history, np.array([k, loss])))

print(f'損失関数初期値 : {history[0, 1]}')
print(f'損失関数最終値 : {history[-1, 1]}')
print(f'回帰直線 : y = {w[0]} + {w[1]}x')
損失関数初期値 : [19.22304522]
損失関数最終値 : [0.55220057]
回帰直線 : y = [2.89141805] + [2.27293257]x

入力データと回帰直線を照らし合わせてみるとこんな感じ。

f:id:hanaaaaaachiru:20200525182753p:plain

良い感じに直線を引いてくれていますね。

さいごに

Pythonはかなり初心者なのでデータの入力箇所などがあんまり綺麗にかけませんでした。

また機械学習をするにあたって、行列の知識が本当に大切だなと実感しました。

特に途中で転置行列を使っている箇所がありますが、行列の形を想像しながらみてみるとなぜしているか分かるはずです。

もしかしたら重回帰分析なども行うかもしれないので、良かったらそちらもお付き合いください。

ではまた。