【Scikit-learn】糖尿病患者のデータセットで複数の機械学習モデルで特徴量の全ての組み合わせを検討(再チャレンジ)[Python]

  • URLをコピーしました!
目次

機械学習ライブラリScikit-learn

前回、機械学習ライブラリScikit-learnで複数の機械学習モデルで特徴量全ての組み合わせを試すためのプログラムに円グラフで表示する機能を追加しました。

今回はそのプログラムを使って、新しい指標を使い、複数の機械学習モデルで特徴量全ての組み合わせを試した場合、使われやすい機械学習モデルはどれなのか、検討してみたいと思います。

ということでおさらいから。

<セル1>

from sklearn.datasets import load_diabetes
import pandas as pd

diabetes = load_diabetes()

df = pd.DataFrame(diabetes.data, columns=diabetes.feature_names)

df["target"] = diabetes.target

df

実行結果
<セル2>

import itertools
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Lasso
from sklearn.linear_model import ElasticNet
from sklearn.linear_model import Ridge
from sklearn.svm import SVR
from sklearn.metrics import r2_score
import numpy as np

models = ["LinearRegression", "Lasso", "ElasticNet", "RidgeRegression", "SVR"]

trial=10

score_list = []; combination_list = []; model_list = []
std_list = []; max_list = []; min_list = []; score_std_list = []

for i in range(1, len(diabetes.feature_names)+1):
    print(i)
    for comb in itertools.combinations(diabetes.feature_names, i):
#         print(comb)
        
        x = df.loc[:, comb]
        y = df.loc[:, "target"]
        
#         print(x)
        
        for mod in models:
            pred_score = []
        
            for t in range(trial):
        
                x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, train_size=0.8)
            
                if mod == "LinearRegression":
                    model = LinearRegression()
                elif mod == "Lasso":
                    model = Lasso()
                elif mod == "ElasticNet":
                    model = ElasticNet()
                elif mod == "RidgeRegression":
                    model = Ridge()
                elif mod == "SVR":
                    model = SVR()

                model.fit(x_train, y_train)
                pred = model.predict(x_test)
                pred_score.append(r2_score(y_test, pred))
#                 print(mod, r2_score(y_test, pred))

            combination_list.append(comb)
            score_list.append(np.average(np.array(pred_score)))
            std_list.append(np.std(np.array(pred_score)))
            max_list.append(np.max(np.array(pred_score)))
            min_list.append(np.min(np.array(pred_score)))
            model_list.append(mod)
                
results = pd.DataFrame()
results["Model_name"] = model_list
results["Combination"] = combination_list
results["Score"] = score_list
results["Max"] = max_list
results["Min"] = min_list
results["STD"] = std_list
results["Score/STD"] = results["Score"]/results["STD"]
results = results.sort_values("Score/STD", ascending=False)

results.head(10)

実行結果
<セル3>

ranking = 100

lr_count = results["Model_name"][:ranking][results["Model_name"] == "LinearRegression"].count()
lasso_count = results["Model_name"][:ranking][results["Model_name"] == "Lasso"].count()
en_count = results["Model_name"][:ranking][results["Model_name"] == "ElasticNet"].count()
rd_count = results["Model_name"][:ranking][results["Model_name"] == "RidgeRegression"].count()
svr_count = results["Model_name"][:ranking][results["Model_name"] == "SVR"].count()

model_count_list = [lr_count, lasso_count, en_count, rd_count, svr_count]

print(model_count_list)

実行結果
[8, 46, 0, 44, 2]
<セル4>

from matplotlib import pyplot as plt
%matplotlib inline

fig = plt.figure(figsize=(8,6))
plt.clf()

plt.pie(model_count_list, labels=models)

実行結果
([<matplotlib.patches.Wedge at 0x7fca3a5a6510>,
  <matplotlib.patches.Wedge at 0x7fca3a5a6990>,
  <matplotlib.patches.Wedge at 0x7fca3a5a6950>,
  <matplotlib.patches.Wedge at 0x7fca3a5b8050>,
  <matplotlib.patches.Wedge at 0x7fca3a5b8e90>],
 [Text(1.0654414787782402, 0.27355886989611045, 'LinearRegression'),
  Text(-0.4049370232742901, 1.0227541284110062, 'Lasso'),
  Text(-1.0654414659720242, -0.2735589197730251, 'ElasticNet'),
  Text(0.06906960848527893, -1.0978293989430645, 'RidgeRegression'),
  Text(1.0978294029847897, -0.06906954424390042, 'SVR')])

5回実行してみる

今回も5回実行していきますが、出現回数をカウントするのは100位までと1,000位までの2種類を試してみましょう。

1回目

モデル名100位までの出現回数1,000位までの出現回数
LinearRegression10157
Lasso51413
ElasticNet00
RidgeRegression39395
SVR035

TOP10のデータ

100位までの円グラフ

1,000位までの円グラフ

1回目の結果として、多いのは「Lasso」と「RidgeRegression」。

「LinearRegression」と「SVR」は100位まででは出現回数は少ないが、1,000位までになると増加傾向にある。

2回目

モデル名100位までの出現回数1,000位までの出現回数
LinearRegression5165
0Lasso61414
ElasticNet00
RidgeRegression34401
SVR020

TOP10のデータ

100位までの円グラフ

1,000位までの円グラフ

100位までだと1回目よりも「Lasso」の比率が高くなっていますが、1,000位までだと1回目と同じ傾向のグラフになりました。

3回目

モデル名100位までの出現回数1,000位までの出現回数
LinearRegression5137
Lasso53432
ElasticNet00
RidgeRegression40397
SVR234

TOP10のデータ

100位までの円グラフ

1,000位までの円グラフ

3回目は1回目と傾向は同じで、「Lasso」と「RidgeRegression」が多く、「LinearRegression」と「SVR」は1,000位までに増やすと出現回数が増加しています。

4回目

モデル名100位までの出現回数1,000位までの出現回数
LinearRegression7139
Lasso59424
ElasticNet00
RidgeRegression34413
SVR024

TOP10のデータ

100位までの円グラフ

1,000位までの円グラフ

これも大体傾向は変わらずですね。

5回目

モデル名100位までの出現回数1,000位までの出現回数
LinearRegression3149
Lasso50438
ElasticNet00
RidgeRegression47379
SVR034

TOP10のデータ

100位までの円グラフ

1,000位までの円グラフ

これも傾向は変わらず。

今回の結果としては、「Lasso」か「RidgeRegression」が他の機械学習モデルと比較して選ばれやすいということが分かりました。

しかし本当に「Lasso」と「RidgeRegression」が糖尿病患者のデータセットに対して”良い”機械学習モデルなのでしょうか?

スコアをちゃんと見直してみましょう。

スコアと標準偏差の平均値を比べてみる

ということで5回目のデータでTOP100以内の「Lasso」と「RidgeRegression」のスコアと標準偏差の平均値を表示させてみましょう。

<セル5>

ranking = 100

lasso_score_ave = results["Score"][:ranking][results["Model_name"] == "Lasso"].mean()
lasso_std_ave = results["STD"][:ranking][results["Model_name"] == "Lasso"].mean()
rd_score_ave = results["Score"][:ranking][results["Model_name"] == "RidgeRegression"].mean()
rd_std_ave = results["STD"][:ranking][results["Model_name"] == "RidgeRegression"].mean()

print(lasso_ave, lasso_std_ave)
print(rd_score_ave, rd_std_ave)

実行結果
0.2920837830657702 0.0183727782298612
0.3654750225200919 0.021773240517050107

results[“Score”]で”Score”の列のデータを取得し、[:ranking]で変数rankingの数値までの個数のデータを取得、[results[“Model_name”] == “Lasso”]で”Model_name”が”Lasso” に一致するものを取得し、「.mean()」で平均値を計算しています。

実行結果を見てみるとよく分かります。

ちなみに100位までの出現回数はLassoが50回、RidgeRegressionは47回なので、ここに大きな差はありません。

Lassoの場合は平均スコアが0.29208で、平均標準偏差が0.18373。

RidgeRegressionでは平均スコアが0.36548、平均標準偏差が0.21773。

ということはLassoがスコアの上位を占めているのは、標準偏差が小さいからということになります。

さらに平均スコアと標準偏差の小ささからみると「RidgeRegression」が良いという結論に至ります。

こうなってくるとこのプログラムで上位に入るような特徴量の組み合わせはどういったものなのか気になってきます。

ということで次回、さらにプログラムを追加して、特徴量のカウントをできるようにして検討してみましょう。

ではでは今回はこんな感じで。

よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

目次