MENU

scikit-learnでの重回帰式分析手法の選定とサンプルコード

以下の方向けの記事になります
  • Pythonライブラリ「scikit-learn」にて重回帰式を計算したい方
  • scikit-learnのコードの書き方を参考にしたい方
目次

何故scikit-learnを使用するのか

みんな大好きExcelさんでも分析ツールを用いることで回帰分析は行えます。

しかしながら、Excelでは「説明変数16以下」という制限があるためデータによっては使用できません。

このことから、Pythonの機械学習ライブラリscikit-learnを使用しました。

sklearnの使い方

アルゴリズムの選定

sklearnは様々なアルゴリズムが用意されており、理解がないとアルゴリズムの選定に困ります。

そんな方向けにチートシートが用意されているので使ってみましょう。

重回帰分析なので「regression」になるはずなのでやってみましょう。

STEP
データ数50以上あるか

YES

STEP
カテゴリーの判別が目的か

No

STEP
数値計算が目的か

YES

STEP
サンプルデータは10万以下か

3万程度なのでYES

STEP
いくつかのパラメータが重要な因子となっているか(?)

何を持って重要と見なすのかわからない…。

けど、下記の記事を見る限り「RidgeRegression」、若しくは「SVR Linner」で良さそう。

Qiita
【機械学習初心者向け】scikit-learn「アルゴリズム・チートシート」の全手法を実装・解説してみた - Qiita scikit-learnのアルゴリズム・チートシートで紹介されている手法を全て実装し、解説してみました。 概要 scikit-learn アルゴリズム・チートシート 【対象者】機械学...

けどよくわからんので、Lasso、RidgeRegression、SVR Linner、3つのアルゴリズムにて計算してみます。

アルゴリズムの比較とコード

以下のコードにて、重回帰分析の比較を行ってみました。

import numpy as np

import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import Lasso
from sklearn.linear_model import Ridge
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import ShuffleSplit, cross_val_score


def csv_data_formatting(file_name, file_path):
    """scv data formatting

    Args:
        file_name ([String]): csv file name
        file_path ([String]): csv file path
    """
    csv_file_name = file_name
    csv_file_path = file_path
    data = np.loadtxt(r"{}\{}.csv".format(
        csv_file_path, csv_file_name), delimiter=',', dtype=float)
    # 目的変数取得
    labels = data[:, 0:1]
    # 説明変数取得
    params = data[:, 1:]
    return labels, params


def sklearn_calc(labels, params):
    """LassoModel,RidgeModel,LinRegModelで重回帰分析を実施

    Args:
        labels ([List]): 目的変数
        params ([List]): 説明変数
    """
    # トレーニングデータとテストデータに分割
    x_train, x_test, y_train, y_test = train_test_split(
        params, labels.ravel(), test_size=0.2)

    # Lasso
    LassoModel = Lasso(alpha=1.0, random_state=0)
    LassoModel.fit(x_train, y_train)

    # Rideg
    RidgeModel = Ridge(alpha=1.0, random_state=0)
    RidgeModel.fit(x_train, y_train)

    # LinReg
    LinRegModel = LinearRegression()
    LinRegModel.fit(x_train, y_train)

    # 各モデルによる回帰の評価(決定係数の表示)
    print("R-squared_Lasso : ", LassoModel.score(x_test, y_test))
    print("R-squared_Ridge : ", RidgeModel.score(x_test, y_test))
    print("R-squared_LinReg : ", LinRegModel.score(x_test, y_test))

    # データセットをランダムに5分割するための変数cvを定義
    cv = ShuffleSplit(n_splits=5, test_size=0.2, random_state=0)
    print('###################################################')
    scores = cross_val_score(LassoModel, x_train, y_train, cv=cv)
    print(scores)
    print("R-squared_Average_Lasso : {0:.2f}".format(scores.mean()))
    print('###################################################')
    scores = cross_val_score(RidgeModel, x_train, y_train, cv=cv)
    print(scores)
    print("R-squared_Average_Ridge : {0:.2f}".format(scores.mean()))
    print('###################################################')
    scores = cross_val_score(LinRegModel, x_train, y_train, cv=cv)
    print(scores)
    print("R-squared_Average_LinReg : {0:.2f}".format(scores.mean()))

    # matplotでグラフ化
    min_label = labels.ravel().min()
    max_label = labels.ravel().max()
    Lasso_predicted = LassoModel.predict(params)
    Ridge_predicted = RidgeModel.predict(params)
    LinReg_predicted = LinRegModel.predict(params)

    fig, ax = plt.subplots()
    ax.scatter(labels.ravel(), Lasso_predicted, edgecolors=(0, 0, 0))
    ax.scatter(labels.ravel(), Ridge_predicted, edgecolors=(0, 0, 0))
    ax.scatter(labels.ravel(), LinReg_predicted, edgecolors=(0, 0, 0))
    ax.plot([min_label, max_label],
            [min_label, max_label], 'k--', lw=4)
    ax.set_xlabel('Measured')
    ax.set_ylabel('Predicted')
    plt.show()


def main():
    csv_file_name = r"SiO2"
    csv_file_path = r"C:\MyProgram\python\sklearn"
    labels, params = csv_data_formatting(csv_file_name, csv_file_path)
    sklearn_calc(labels, params)


if __name__ == "__main__":
    main()

重回帰結果

Lassoモデルは中央値から外れるとズレが大きくなる結果となった。

恐らく、特定の説明変数の寄与度が大きくなるようなアルゴリズムだからなのだろう。

青がLassoModel,RidgeとLinnerはほぼ一致
出力結果
 R-squared_Lasso :  0.7856614486801435
 R-squared_Ridge :  0.9671365188891442
 R-squared_LinReg :  0.9671425896464472
 #
 [0.78821495 0.79503195 0.79383899 0.79704074 0.79902765]
 R-squared_Average_Lasso : 0.79
 #
 [0.96693875 0.96767202 0.96823101 0.96763441 0.9692914 ]
 R-squared_Average_Ridge : 0.97
 #
 [0.96694059 0.96767437 0.96823395 0.96763121 0.96929278]
 R-squared_Average_LinReg : 0.97 

重回帰式の出力

RidgeModelとLinnerModel、どちらを使用しても良さそうではあるが、RidgeModelのα値の意味がわからない。

理解不能な値は使用しないが吉なので、LinnerModelを使用して重回帰式を求めることにしました。

以下のコードは、変数と切片をcsvに出力、各R^2の値をtxtに出力するものです。

import csv
import os

import numpy as np
from sklearn.model_selection import ShuffleSplit, cross_val_score
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split


def get_file_name_list(dirPath):
    """Function ファイル一覧のListを取得

    Args:
        dirPath ([String]): ファイル一覧を取得したいディレクトリの絶対パス

    Returns:
        [List]: ファイル一覧
    """
    files = os.listdir(dirPath)
    file_name_list = [f for f in files
                      if os.path.isfile(os.path.join(dirPath, f))]
    return file_name_list


def calc_coef(csvFileName, dataDirPath, coefDirPath):
    """
    sklearnモジュールを用い、LinearRegressionのアルゴリズムにて重回帰式を作成する
    coefDirにcvsファイルを出力、cvsの最終行に切片が出力

    Args:
        csvFileName (String):   'XXXX.csv'の書式
        dataDirPath (String):   回帰式を求めるcsvファイルが入っているディレクトリの絶対パス
                                csvファイルの書式は1列目が値、2列目以降にパラメータを記載する。
                                区切りは,で行うこと。
        coefDirPath (String):   回帰式の係数、切片を出力するディレクトリの絶対パス
    """
    csv_file_name = csvFileName
    csv_file_path = dataDirPath
    save_coef_path = coefDirPath
    data = np.loadtxt(r"{}\{}".format(
        csv_file_path, csv_file_name), delimiter=',', dtype=float)

    # 1行目の分析値を取り出す
    labels = data[:, 0:1]
    # 説明変数を取り出す
    params = data[:, 1:]
    # トレーニングデータとテストデータに分割
    x_train, x_test, y_train, y_test = train_test_split(
        params, labels.ravel(), test_size=0.2)
    # LinReg学習
    LinReg = LinearRegression()
    LinReg.fit(x_train, y_train)
    # R^2
    print("R-squared_LinReg : ", LinReg.score(x_test, y_test))
    # 5分割してスコア確認
    cv = ShuffleSplit(n_splits=5, test_size=0.2, random_state=0)
    scores = cross_val_score(LinReg, x_train, y_train, cv=cv)
    print(scores)

    # 重回帰式、R^2出力
    lig_coef_list = []
    for items in LinReg.coef_:
        lig_coef_list.append(items)

    lig_intercept = LinReg.intercept_
    lig_coef_list.append(lig_intercept)

    with open(r"{}\coef_{}".format(save_coef_path, csv_file_name), 'w')as f:
        writer = csv.writer(f, lineterminator=",")
        writer.writerows(map(lambda x: [x], lig_coef_list))

    with open(r"{}\R2_score.txt".format(save_coef_path), 'a')as f:
        f.write("{}\t:{}\n".format(csv_file_name, scores))


def main():
    """
    dataDirPath (String):   csvファイルのフォルダ
                            csvファイルの書式は1列目が値、2列目以降にパラメータを記載する。
                            区切りは,で行う。
    coefDirPath (String):   回帰式の係数、切片を出力するディレクトリの絶対パス
    """
    dataDirPath = r"c:\MyProgram\python\sklearn_test\data"
    coefDirPath = r"c:\MyProgram\python\sklearn_test\coef"

    fileNameList = get_file_name_list(dataDirPath)
    for fileName in fileNameList:
        calc_coef(fileName, dataDirPath, coefDirPath)


if __name__ == "__main__":
    main()

まとめ

sklearnライブラリにて、重回帰式を求めることができた。

アルゴリズムを理解できなくても、回帰式の妥当性は評価しやすいので使いやすいですね。

シェアしてくださいな
目次
閉じる