Kaggle(21) - 分割交差検証での学習・推論(LightGBM)

前回試したホールドアウト法は、簡単にモデルの性能評価ができるので使いやすいのですがvalidセットを学習に使えていないという欠点があります。

精度が必要な場合には、この問題を解決したk分割交差検証を使うのが一般的です。

データの読み込みと前処理

前回と同様に、タイタニックのデータセットを読み込み、前処理(不要列の削除・欠損値処理・カテゴリ変数の変換)を行っておきます。

[ソース]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
import seaborn as sns
titanic = sns.load_dataset('titanic')

# 不要な列の削除
titanic.drop(['class', 'who', 'adult_male', 'deck', 'embark_town', 'alive', 'alone'], axis=1, inplace=True)

# 欠損値処理
#titanic.isnull().sum()
titanic['age'] = titanic['age'].fillna(titanic['age'].median())
titanic['embarked'] = titanic['embarked'].fillna('S')

# カテゴリ変数の変換
titanic = pd.get_dummies(titanic, columns=['sex', 'embarked'])

x_titanic = titanic.drop(['survived'], axis=1)
y_titanic = titanic['survived']

x_titanic

[出力結果]

分割交差検証

k分割交差検証のk=3の場合の3分割交差検証を行います。

fold1、fold2、fold3の合計3回の学習・検証を行います。

3分割したデータはtrainセット(訓練用)に2回、validセット(検証用)に1回ずつ使われます。

学習を3回行うので学習済みモデルも3つできます。3つの予測結果ができますので、最後にそれらを1つにまとめています。

[ソース]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import lightgbm as lgb
import numpy as np
from sklearn.metrics import accuracy_score
from sklearn.model_selection import KFold

# 3分割交差検証を指定しインスタンス化する
kf = KFold(n_splits=3, shuffle=True)

# スコアとモデルを格納するリスト
score_list = []
models = []

for fold_, (train_index, valid_index) in enumerate(kf.split(x_titanic, y_titanic)):
print(f'fold{fold_ + 1}start')
train_x = x_titanic.iloc[train_index]
valid_x = x_titanic.iloc[valid_index]
trains_y = y_titanic.iloc[train_index]
valid_y = y_titanic.iloc[valid_index]

# lab.Datasetを使って、trainとvalidを作っておく
lgb_train = lgb.Dataset(train_x, train_y)
lgb_valid = lgb.Dataset(valid_x, valid_y)

# パラメータを定義
lgbm_params = {'objective': 'binary'}

# lgb.trainで学習
evals_result = {}
gbm = lgb.train(params=lgbm_params,
train_set=lgb_train,
valid_sets=[lgb_train, lgb_valid],
early_stopping_rounds=20,
evals_result=evals_result,
verbose_eval=-1) # 学習の状態を表示しない
# valid_xについて推論
oof = (gbm.predict(valid_x) > 0.5).astype(int)
score_list.append(round(accuracy_score(valid_y, oof) * 100, 2))
# 学習が終わったモデルをリストに入れておく
models.append(gbm)
print(f'fold_{fold_ + 1} end\n')

print(score_list, '平均score', round(np.mean(score_list), 2))

[出力結果]

正解率は90.35%となりました。

なかなかの好成績になったのではないでしょうか。

(実行環境としてGoogleさんのColaboratoryを使用ています。)