1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Kaggle】LightGBMでTitanicコンペ【acc: 0.765】

Last updated at Posted at 2024-11-08

はじめに

 Kaggleの復習もやることにした。まずは定番のタイタニックから。

できたこと

  • 機械学習モデル: LightGBM
  • 交差検証: Stratified K-Fold
  • CVスコア(logloss): 0.418
  • パブリックスコア: 0.765

スクリーンショット 2024-11-08 155559.png

ライブラリをインポート

# 関連ライブラリをインポート
import lightgbm as lgb
import numpy as np
#import os
import pandas as pd
import random
#import torch

# scikit-learn関連をインポート
from sklearn.model_selection import StratifiedKFold
from sklearn.metrics import accuracy_score

# warningを非表示
import warnings
warnings.filterwarnings('ignore')

乱数を固定する。

# 参考: 乱数固定
def seed_everything(seed=1234):
    random.seed(seed)
    np.random.seed(seed)
    #os.environ['PYTHONHASHSEED'] = str(seed)
    # torch.manual_seed(seed)
    # torch.cuda.manual_seed(seed)
    # torch.backends.cudnn.daterministic = True
seed_everything(1234)

データ読み込み

コンペサイトからあらかじめデータをダウンロードし、読み込ませる。

# データ読み込み
train = pd.read_csv('../input/titanic/train.csv')
test = pd.read_csv('../input/titanic/test.csv')
gender_submission = pd.read_csv('../input/titanic/gender_submission.csv')

前処理・特徴量エンジニアリング

前処理と特徴量エンジニアリングを施す。

# データを連結(前処理効率化のため)
data = pd.concat([train, test], sort=False)

# 前処理
data['Sex'].replace(['male', 'female'], [0, 1], inplace=True)
data['Embarked'].fillna(('S'), inplace=True)
data['Embarked'] = data['Embarked'].map({'S': 0, 'C': 1, 'Q': 2}).astype(int)
data['Fare'].fillna(np.mean(data['Fare']), inplace=True)
data['Age'].fillna(data['Age'].median(), inplace=True)
data['FamilySize'] = data['Parch'] + data['SibSp'] + 1
data['IsAlone'] = 0
data.loc[data['FamilySize'] == 1, 'IsAlone'] = 1

# 使用しない列を削除
delete_columns = ['Name', 'PassengerId', 'Ticket', 'Cabin']
data.drop(delete_columns, axis=1, inplace=True)

# 訓練データとテストデータに戻す
train = data[:len(train)]
test = data[len(train):]

# 目的変数と説明変数に分割
y_train = train['Survived']
X_train = train.drop('Survived', axis=1)
X_test = test.drop('Survived', axis=1)

# 表示
print(f"X_train: {X_train.shape}")
display(X_train.head())
print(f"y_train: {y_train.shape}")
display(y_train.head())
print(f"X_test: {X_test.shape}")
display(X_test.head())

出力は以下のような感じになるはず(データフレームの表示は割愛)。

X_train: (891, 9)
y_train: (891,)
X_test: (418, 9)

交差検証の準備

交差検証を行うための準備を行う。Stratified K-Foldを行うためにインスタンスを生成。目的変数が均等に分割できているか確認。

cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=0)

# 目的変数が均等に分割できているか確認
for fold_id, (train_index, valid_index) in enumerate(cv.split(X_train, y_train)):
    X_tr = X_train.loc[train_index, :]
    X_val = X_train.loc[valid_index, :]
    y_tr = y_train[train_index]
    y_val = y_train[valid_index]

    print(f'fold_id: {fold_id}')
    print(f'y_tr y==1 rate: {sum(y_tr)/len(y_tr)}')
    print(f'y_val y==1 rate: {sum(y_val)/len(y_val)}')
    print("--------------------------------")

出力は以下の通り。ちゃんと均等になっている。

fold_id: 0
y_tr y==1 rate: 0.38342696629213485
y_val y==1 rate: 0.3854748603351955
--------------------------------
fold_id: 1
y_tr y==1 rate: 0.38429172510518933
y_val y==1 rate: 0.38202247191011235
--------------------------------
fold_id: 2
y_tr y==1 rate: 0.38429172510518933
y_val y==1 rate: 0.38202247191011235
--------------------------------
fold_id: 3
y_tr y==1 rate: 0.38429172510518933
y_val y==1 rate: 0.38202247191011235
--------------------------------
fold_id: 4
y_tr y==1 rate: 0.38288920056100983
y_val y==1 rate: 0.38764044943820225
--------------------------------

メインループ

訓練を行う。

y_preds = [] # 予測値を格納するリスト
models = [] # モデルを格納するリスト
oof_train = np.zeros((len(X_train),)) # 各分割でのoof(訓練に使用されなかったfold)に対する予測値
categorical_features = ['Embarked', 'Pclass', 'Sex'] # カテゴリ変数

# ハイパーパラメータ
params = {
    'objective': 'binary',
    'max_bin': 300,
    'learning_rate': 0.05,
    'num_leaves': 40
}

少し用語をメモ。Out-of-fold(oof)は、各foldで訓練に使われなかったfoldのこと(多分)。oof_trainは、各foldでoof(訓練に使用されなかったfold)に対する「予測値」のこと(多分)。

# メインループ
for fold_id, (train_index, valid_index) in enumerate(cv.split(X_train, y_train)):
    # 表示
    print('-------------------')
    print(f'Fold: {fold_id}')


    # 訓練データと検証データに分割
    X_tr = X_train.loc[train_index, :]
    X_val = X_train.loc[valid_index, :]
    y_tr = y_train[train_index]
    y_val = y_train[valid_index]

    # データセットを生成
    lgb_train = lgb.Dataset(X_tr, y_tr, categorical_feature=categorical_features)
    lgb_eval = lgb.Dataset(X_val, y_val, reference=lgb_train, categorical_feature=categorical_features)

    # 訓練
    model = lgb.train(params, lgb_train,
                      valid_sets=[lgb_train, lgb_eval],
                      num_boost_round=1000,
                      callbacks=[lgb.early_stopping(stopping_rounds=10,
                                                    verbose=True),
                                 lgb.log_evaluation(10)])

    # 検証データでの予測
    oof_train[valid_index] = model.predict(X_val, num_iteration=model.best_iteration)
    y_pred = model.predict(X_test, num_iteration=model.best_iteration)

    # 予測値と学習済みモデルを格納
    y_preds.append(y_pred)
    models.append(model)

評価

oof_train(訓練に使用されなかったfoldに対する予測値)をcsvで保存し、表示させる。

# oof_train(訓練に使用されなかったfoldに対する予測値)を保存・表示
pd.DataFrame(oof_train).to_csv('oof_train_skfold.csv', index=False)
print(oof_train[:10])
[0.10743915 0.9336148  0.24343427 0.97174844 0.23722008 0.05967737
 0.10523416 0.27028808 0.37330822 0.9413475 ]

次に各foldの検証データに対するスコアをscores変数に代入し、printする。

# 各foldの検証データに対するスコア(logloss)を格納・表示
scores = [m.best_score['valid_1']['binary_logloss'] for m in models]
print(scores)
[0.38009408187107163, 0.37924619589793596, 0.40508420679400237, 0.4450699329180633, 0.4825556025529494]

スコア(logloss)は0.38~0.48となった。ばらつきがある。スコアを平均して、最終的なスコア(Cross Validationスコア)を計算する。

# 各foldの検証データに対する予測値を平均して、最終的なスコアを生成
score = sum(scores) / len(scores)
print('===CV scores===')
print(score)
===CV scores===
0.41841000400680456

次に、oof_train(訓練に使用されなかったfoldに対する予測値)を閾値0.5で二値化する。その値と、訓練データの目的変数を使って、正解率を計算する。

# oof_train(訓練に使用されなかったfoldに対する予測値)を0.5で二値化
y_pred_oof = (oof_train > 0.5).astype(int)
print(accuracy_score(y_train, y_pred_oof)) # 精度を計算
0.8294051627384961

正解率は82%となった。

Submit

提出するためにデータを作成する。今回は、各foldでの「テストデータに対する予測値」の平均をとる。

# 各foldでの「テストデータに対する予測値」の平均をとる
y_sub = sum(y_preds) / len(y_preds)
y_sub = (y_sub > 0.5).astype(int) # 閾値0.5で二値化
y_sub[:10]
array([0, 0, 0, 0, 0, 0, 1, 0, 1, 0])

提出用ファイルを作成する。サンプル用のデータ(gender_submission.csv)を読み込み、計算した予測値を代入する。

# 提出用ファイルを作成
sub = pd.read_csv('../input/titanic/gender_submission.csv')
sub['Survived'] = y_sub
sub.to_csv('submission_lightgbm_skfold.csv', index=False)

sub.head()

image.png

結果確認

出力したcsvファイル(submission_lightgbm_skfold.csv)を提出する。パブリックスコアは76%だった。
スクリーンショット 2024-11-08 155559.png

おわりに

今回は、タイタニックコンペにデータを提出してみた。

  • 機械学習モデル: LightGBM
  • 前処理,特徴量エンジニアリング: 適当に…
  • 交差検証: Stratiried K-Fold (5 Fold)
  • CVスコア: 82%
  • パブリックスコア: 76%

出典

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?