喫茶's CAFE

心にうつりゆくよしなしコードをそこはかとなく

Visual Studio CodeのgitでincludeIfがうまくいかなかった話

今まではMacで開発することが多かったのですが、良いマシンを買ったので開発環境をWindowsに作りました。 githubだけでなくgitbucketを使うこともあるので、それぞれのプロジェクトでgitの設定を変えて使っています。 ただ各レポジトリの.gitconfigを編集するのはとても面倒くさい。

そこでMacのときはグローバルの.gitconfigをgithub用の設定に、gitbucket用の設定は対象のディレクトリ以下のレポジトリに対する設定をincludeIfで読み込むようにしていました。 以下のファイルのような設定をすると~/work以下のレポジトリには.gitconfig-work の設定が適用されます。 Visual Studio Code上でgitを操作していても期待したとおりの動きをしてくれていました。

~/.gitconfig

[user] 
    user = user_example
    email = hoge@example.jp

 [includeIf "gitdir:~/work/"] 
    path = ~/.gitconfig-work 

~/.gitconfig-work

[user] 
    user = user_work 
    email = hoge@work.com 

ところがwindowsで同じことをしたところ、なぜかVisual Studio Code上でgitを操作したときだけ.gitconfig-workの設定を読んでくれませんでした。 さすがWindowsすんなりと通してはくれません。ただ割とすぐに解決方法は見つかりました。

Git integration does not correctly support `includeIf` directive · Issue #40354 · microsoft/vscode · GitHub

さきほどの.gitconfigでincludeIfの部分を以下の用に変えるだけです。 Visual Studio Codeでgitを操作しているときにパスの大文字小文字の区別がなくなり、対象のディレクトリパスをちゃんと読んでくれなかったみたいです。 gitdir/iにするとその後ろの対象ディレクトリを大文字、小文字の区別なく認識してくれるとのこと。

~/.gitconfig

[user] 
    user = user_example 
    email = hoge@example.jp 

[includeIf "gitdir/i:~/work/"] 
    path = ~/.gitconfig-work 

とりあえずGridSearchCVを使ってみたい

最初にLGBMを使って回帰モデルを作る

まずは簡単に回帰モデルを作ってみます。使うデータはscikit-leanの中にあるBostonデータセットになります。これは米国ボストン市郊外における地域別のデータで、実際にどんなデータか見てみます。

import numpy as np
from sklearn.datasets import load_boston
import pandas as pd

boston = load_boston()
train_df = pd.DataFrame(boston.data, columns = boston.feature_names)
train_df['HousePriceMedian'] = boston.target
train_df.head()
CRIM ZN INDUS CHAS NOX ・・・ HousePriceMedian
0 0.00632 18.0 2.31 0.0 0.538 ・・・ 24.0
1 0.02731 0.0 7.07 0.0 0.469 ・・・ 21.6
2 0.02729 0.0 7.07 0.0 0.469 ・・・ 34.7
3 0.03237 0.0 2.18 0.0 0.458 ・・・ 33.4
4 0.06905 0.0 2.18 0.0 0.458 ・・・ 36.2

左から13列のデータ(地域のいろいろな特徴)を使って一番右のデータ(住宅価格の中央値)を予測するのが今回のミッションです。

その前に後々検証に使うのでtrain_test_split()を用いてデータを分割します。train_dfを訓練用データ,val_dfをモデルの評価用データとして使います。

from sklearn.model_selection import train_test_split
train_df, val_df = train_test_split(train_df, test_size=.10, random_state=1)

本当であればデータの欠損値を埋めたり、目的変数の分布や外れ値をどうするかなどの前処理をしないといけないのですが、今回はそれなりに前処理されているようなのでそのままモデルの構築に進みます。回帰するにあたってはkaggleでも人気の高いLightGBMを使います。誤差にはRoot Mean Square Errorを指定!

import lightgbm as lgb

target = 'HousePriceMedian' #目的変数
predictors =['CRIM','ZN','INDUS','CHAS','NOX','RM','AGE','DIS','RAD','TAX','PTRATIO','B','LSTAT'] #説明変数

#モデルの作成、各種ハイパラメータの指定
bst = lgb.LGBMRegressor(
                        num_leaves = 31,
                        learning_rate=0.01,
                        min_child_samples=10,
                        n_estimators=1000,
                        max_depth=-1,
                        )

#トレーニング開始
bst.fit(
        train_df[predictors], 
        train_df[target],
        eval_names=['train'],
        eval_set=[(train_df[predictors].values,train_df[target].values)],
        eval_metric='rmse',
        early_stopping_rounds=10,
        verbose = 0
       )

from sklearn.metrics import mean_squared_error
pred1 = bst.predict(val_df[predictors])
RMSE1 = np.sqrt(mean_squared_error(pred1, val_df[target]))
print('default RMSE:{}'.format(RMSE1))
default RMSE:3.216731430057823

ものすごく悪い値が出た!?まあ何も前処理してないしそんなものかなあ、、、、、 交差検証をするだけならcross_val_score()を使うと良いみたいです。cvにはただの整数を入れれば良いのですが、それだと前から順番に分割されるので分割の際にシャッフルしたい時はcvにKFold()のshuffle=Trueにして渡してやります。cros_val_scoreはscoringで指定した誤差の値を返すのですが何故か負のMean Square Errorを返すので符号を反転します。

from sklearn.model_selection import cross_val_score,KFold

scores = -cross_val_score(bst, train_df[predictors], 
                          train_df[target],
                          scoring = 'neg_mean_squared_error',
                          cv = KFold(n_splits=3, shuffle=True)
                         )
scores = np.sqrt(scores)
# 各分割におけるスコア
print('Cross-Validation scores: {}'.format(scores))
# スコアの平均値
print('Average score: {}'.format(np.mean(scores)))
Cross-Validation scores: [3.4143698  4.64896828 3.61283182]
Average score: 3.892056630769702

スコアに関してはもう何も考えない、、、、、、、、

ここからが本番

ようやくGridSearchCV()を使って見ます。GridSearchCV()には以下のようにハイパラメータの試したい値をリストにして、さらにそれらを辞書にして渡してやります。

grid_param ={'n_estimators':[1000,2000],'max_depth':[4,8,16],'num_leaves':[31,15,7,3],'learning_rate':[0.1,0.05,0.01]}

またearly_stoppingを使いたいので以下のような辞書をモデルを訓練する際に渡してやります。

fit_params={'early_stopping_rounds':10, 
            'eval_metric' : 'rmse', 
            'eval_set' : [(train_df[predictors], train_df[target])]
           }

では実際にGridSearchCV()を使って見ましょう。

from sklearn.model_selection import GridSearchCV



bst_gs_cv = GridSearchCV(
            bst, # 識別器
            grid_param, # 最適化したいパラメータセット 
            cv = KFold(n_splits=3, shuffle=True), # 交差検定の回数
            scoring = 'neg_mean_squared_error',
            verbose = 0
            )

bst_gs_cv.fit(
            train_df[predictors], 
            train_df[target],
            **fit_params,
            verbose = 0
            )

best_param = bst_gs_cv.best_params_
print('Best parameter: {}'.format(best_param))

pred2 = bst_gs_cv.predict(val_df[predictors])
RMSE2 = np.sqrt(mean_squared_error(pred2, val_df[target]))
print('GridSearchCV RMSE:{}'.format(RMSE2))
Best parameter: {'max_depth': 4, 'n_estimators': 1000, 'num_leaves': 7, 'learning_rate': 0.05}
GridSearchCV RMSE:2.938220045864752

誤差減ったからよしとしよう

反省

もうちょっと内容しぼってブログ書きます。