AI学習者・実務家の「疑問」を解消したい

外資系IT企業で、主に火力発電所のAI最適化に従事 →2019年6月: 米国SAS社が主催する ”SaS Analytics Hackathon”で優勝

Numpyで"線形回帰with勾配降下法"を実装し、オープンソースと性能を比べてみた

イントロ

Numpyで線形回帰 with 勾配降下法を実装しました。
一応、オープンソースに対抗できるだけの性能は出たので、共有します。

丁寧に書いたので、参考になると思います。

Numpyの線形回帰 with 勾配降下法

# ライブラリーのインポート
import numpy as  np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split

def updater(b_current, m_current, X_vector, y_vector, learning_rate):
     
    # 回帰式
    y_pred = np.dot(X_vector, m_current) + np.array(b_current)
    
    # コストの計算(MSE)
    residual = (y_pred-y_vector)
    mse = np.sum(residual**2) / (2*len(X_vector))

    # 勾配(Gradient)の計算
    gradient_b  = np.sum(residual)/ len(X_vector)
    gradient_m = np.dot(X_vector.T, residual)/len(X_vector)
    
    # mとbのアップデート(係数と切片のアップデート)
    b_current  -= learning_rate*gradient_b
    m_current -= learning_rate*gradient_m
    
    return b_current, m_current, mse

def gradient_decent_runner(X_vector, y_vector, learning_rate, num_iterations, starting_m, starting_b):
    b  =  starting_b
    m = starting_m
    # bとmの更新(ここが学習の中身!!)
    for i in range(num_iterations):
        b, m, mse = updater(b, m, X_vector, y_vector, learning_rate)
    print("After {0} iterations b = {1}, m = {2}, error = {3}".format(num_iterations, b, m, mse))
    return b, m

def main():
    # データの準備(ボストンの不動産価格)
    df = pd.DataFrame(load_boston().data, columns=load_boston().feature_names)[["RM", "LSTAT"]]
    df["target"] = load_boston().target
    m_dimention = df.drop("target", axis=1).shape[1] # 係数の次元の定義
    
    # 学習のためのデータ準備
    X = df.drop("target", axis=1).values
    y = df["target"].ravel()
    
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=100)
    
    # 最急降下法のハイパーパラメーター
    learning_rate    = 0.0001
    num_iterations = 100000
    
    # 回帰式の準備 (y=mx+b)
    initial_m = np.zeros(m_dimention)
    initial_b  = 0
    
    # 最急降下法の実行
    b, m = gradient_decent_runner(X_train, y_train, learning_rate, num_iterations, initial_m, initial_b)
    
    return b, m, X_train, X_test, y_train, y_test

if __name__ == '__main__':
    b, m, X_train, X_test, y_train, y_test = main()

# 性能評価
y_prediction_from_scratch = np.dot(X_test, m) + np.array(b)
print("Numpyで実装した線形回帰 with 勾配降下法")
print("-----------------------------------------------------")
print("R2 Score: {}".format(round(r2_score(y_test, y_prediction_from_scratch), 4)))
print("RMSE: {}".format(round(np.sqrt(mean_squared_error(y_test, y_prediction_from_scratch)), 4)))
print("-----------------------------------------------------")

オープンソースの線形回帰 with 最小二乗法

from sklearn.linear_model import LinearRegression
lr = LinearRegression().fit(X_train, y_train)

print("オープンソースの線形回帰")
print("-----------------------------------------------------")
print("R2 Score: {}".format(round(r2_score(y_test, lr.predict(X_test)), 4)))
print("RMSE: {}".format(round(np.sqrt(mean_squared_error(y_test, lr.predict(X_test))), 4)))
print("-----------------------------------------------------")

結果

オープンソースとほぼ同じ精度が出せた。

オープンソース

  • R2 Score: 0.6631
  • RMSE: 5.7044

Numpy

  • R2 Score: 0.6625
  • RMSE: 5.7095