LoginSignup
0

More than 3 years have passed since last update.

Kaggle House Prices ② ~ モデル作成 ~

Last updated at Posted at 2020-10-07

以下で作成した特徴量を使用してモデルを作成します。
Kaggle House Prices ① ~ 特徴量エンジニアリング ~

ライブラリの読み込み

import numpy as np
import pandas as pd
import lightgbm as lgb
from sklearn.model_selection import KFold
from sklearn.metrics import mean_squared_error
from sklearn.externals import joblib

データの読み込み

def load_x_train() -> pd.DataFrame:
    """事前に作成した学習データの特徴量を読み込む

    :return: 学習データの特徴量
    """
    return joblib.load('train_x.pkl')

def load_y_train() -> pd.Series:
    """事前に作成した学習データの目的変数を読み込む

    :return: 学習データの目的変数
    """
    # 目的変数の読込を行う
    train_y = joblib.load('train_y.pkl')
    # 目的変数を対数変換
    train_y = np.log1p(train_y)
    return train_y

クロスバリデーション

def load_index_fold(i_fold: int) -> np.array:
    """クロスバリデーションでのfoldを指定して対応するレコードのインデックスを返す

    :param i_fold: foldの番号
    :return: foldに対応するレコードのインデックス
    """
    # 学習データ・バリデーションデータを分けるインデックスを返す
    # ここでは乱数を固定して毎回作成しているが、ファイルに保存する方法もある
    train_y = load_y_train()
    kf = KFold(n_splits=4, random_state=6, shuffle=True)
    return list(kf.split(train_y))[i_fold]

def train_fold(i_fold):
    """クロスバリデーションでのfoldを指定して学習・評価を行う

    他のメソッドから呼び出すほか、単体でも確認やパラメータ調整に用いる

    :param i_fold: foldの番号
    :return: (モデルのインスタンス、レコードのインデックス、予測値、評価によるスコア)のタプル
    """
    # 学習データの読込
    train_x = load_x_train()
    print(train_x.shape)
    train_y = load_y_train()

    # 学習データ・バリデーションデータをセットする
    tr_idx, va_idx = load_index_fold(i_fold)
    print(tr_idx.shape)
    print(va_idx.shape)
    tr_x, tr_y = train_x.iloc[tr_idx], train_y.iloc[tr_idx]
    va_x, va_y = train_x.iloc[va_idx], train_y.iloc[va_idx]

    # 学習を行う
    params_lgbm = {
        "boosting_type": "gbdt",
        "objective": "regression",
        "metric": "rmse",
        "learning_rate": 0.05,
        "max_depth": 4,
        "colsample_bytree": 0.9,
        "subsample": 0.9,
        "reg_alpha": 0.1,
        "reg_lambda": 0.0,
        "min_child_weight": 1,
        "num_leaves": 31
    }
    lgb_train = lgb.Dataset(tr_x, tr_y)
    lgb_eval = lgb.Dataset(va_x, va_y, reference=lgb_train)

    model = lgb.train(
        params_lgbm, lgb_train,
        # モデルの評価用データを渡す
        valid_sets=lgb_eval,
        # 最大で 1000 ラウンドまで学習する
        num_boost_round=1000,
        # 10 ラウンド経過しても性能が向上しないときは学習を打ち切る
        early_stopping_rounds=10
    )

    # バリデーションデータへの予測・評価を行う
    va_pred = model.predict(va_x)
    score = np.sqrt(mean_squared_error(va_y, va_pred))

    # モデル、インデックス、予測値、評価を返す
    return model, va_idx, va_pred, score

学習とモデル作成を実行

# クロスバリデーションでの学習・評価を行う
scores = []
va_idxes = []
preds = []
n_fold = 4

# 各foldで学習を行う
for i_fold in range(n_fold):
    # 学習を行う
    print(f'fold {i_fold} - start training')
    model, va_idx, va_pred, score = train_fold(i_fold)
    print(f'fold {i_fold} - end training - score {score}')

    # モデルを保存する
    # model.save_model()
    joblib.dump(model, f'model-{i_fold}.pkl')

    # 結果を保持する
    va_idxes.append(va_idx)
    scores.append(score)
    preds.append(va_pred)

# 各foldの結果をまとめる
va_idxes = np.concatenate(va_idxes)
order = np.argsort(va_idxes)
preds = np.concatenate(preds, axis=0)
preds = preds[order]

print(f'end training cv - score {np.mean(scores)}')

# 予測結果の保存
joblib.dump(preds, 'pred-train.pkl')

# 評価結果
print('result_scores', scores)

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
0