~上位を取るためにとりあえず知っておくべき選択肢~
はじめに
コンペティションに初めて参加すると、「どのモデルを使えばいいのか?」という疑問がついて回ります。
テーブルデータに対しては勾配ブースティング木(GBDT)系モデル、つまりXGBoost、LightGBM、CatBoostが最も有力ですが、それ以外にも有力な選択肢が存在します。
ここでは、数理的な詳細には踏み込まずに、上位入賞者によく使われるモデルについて解説します。
1. GBDT系モデル(XGBoost, LightGBM, CatBoost)
基本のモデル群 ~GBDT系モデル~
どのテーブルデータコンペにおいても、まず選択肢に入るのはこのGBDT(勾配ブースティング決定木)系モデルです。これらは非常に強力で、ほぼすべてのテーブルデータにおいて堅実な性能を発揮します。
初めはパラメータ調整が複雑に感じられるかもしれませんが、公開されているコードのパラメータを参考にしながら、気になったパラメータをその都度調べることで、徐々に理解が深まっていきます。
一度に全てを覚えようとせず、まずは「動くコード」を書けるようになることが大事だと思います。
参考) 【初学者向け】XGBoostのパラメータ – ベースライン付きガイド
以下は主要なGBDTモデルの簡単な解説です。
- XGBoost
タスクによってはCatBoostが一歩リードする場合もありますが、注意深く特徴量エンジニアリングを施せば、XGBoostが最も安定して高精度な予測を実現する印象です。
以下は回帰に用いる場合のサンプルコードです。
from xgboost import XGBRegressor
# XGBoost用パラメータの定義
xgb_params = {
'objective': 'reg:squarederror',
'learning_rate': 0.1,
'max_depth': 6,
'n_estimators': 100,
'random_state': 42,
# 'device': 'cuda', # GPUを利用する場合
}
# XGBRegressorモデルの定義と学習
model = XGBRegressor(**xgb_params)
model.fit(X_train, y_train)
# テストデータに対する予測
y_pred = model.predict(X_test)
# モデルの評価(平均二乗誤差)
mse = mean_squared_error(y_test, y_pred)
print("Mean Squared Error:", mse)
- LightGBM
LightGBMは3つのモデルの中で最も処理速度が速いという特徴があります。実際のコンペでも、その高速性から前処理や反復実験で重宝されることが多いです。
同様に、回帰に用いる場合のサンプルコードです。XGBoostと異なり、earlystoppingの指定をcallbacksを用いて行う必要があります。
from lightgbm import LGBMRegressor, early_stopping
# LGBMRegressor用パラメータの定義
lgbm_params = {
'objective': 'regression',
'learning_rate': 0.1,
'max_depth': 6,
'n_estimators': 100,
# 'device': 'gpu', # GPUを利用するための指定
'random_state': 42
}
# LGBMRegressorモデルの定義
model = LGBMRegressor(**lgbm_params)
# モデルの学習(eval_set で検証用データを指定し、callbacks に early_stopping を設定)
model.fit(
X_train,
y_train,
eval_set=[(X_val, y_val)],
eval_metric='rmse',
callbacks=[early_stopping(stopping_rounds=10)],
verbose=True
)
# 検証データに対する予測
y_pred = model.predict(X_val)
# モデルの評価(平均二乗誤差)
mse = mean_squared_error(y_val, y_pred)
print("Mean Squared Error:", mse)
- CatBoost
CatBoostは、特にカテゴリ変数の扱いに優れており、場合によっては他のGBDTモデルよりも高い精度を発揮することがあります。
from catboost import CatBoostRegressor
model = CatBoostRegressor(
iterations=1000,
learning_rate=0.1,
depth=6,
# task_type="GPU",
random_seed=42,
verbose=True
)
# モデルの学習(eval_set に検証用データを指定)
model.fit(
X_train,
y_train,
eval_set=(X_val, y_val)
)
# 検証データに対する予測
y_pred = model.predict(X_val)
# モデルの評価(平均二乗誤差)
mse = mean_squared_error(y_val, y_pred)
print("Mean Squared Error:", mse)
2. TabNet
TabNetは、テーブルデータ専用に開発されたニューラルネットワーク(NN)の一種です。従来、画像認識や自然言語処理の分野では、最先端(state-of-the-art)のNNアーキテクチャが次々に登場しており、その性能は非常に高い評価を受けています。しかし、テーブルデータに関しては、いまだにGBDT(勾配ブースティング決定木)系のモデルが圧倒的な実績を誇っています。現状、テーブルデータに対して最適なニューラルネットワークのアーキテクチャは確立されていないとも言われています。
それでも、TabNetはGBDT単体では捉えきれないデータの複雑な関係性を学習できる可能性を秘めています。そのため、単体で用いるのではなく、他のモデルと組み合わせたアンサンブル手法の一部、例えば2層目のモデル(Stacking)として採用されるケースもたまに目にします。
TabNetは、scikit-learn風のAPIを備えているため、使い始める際のハードルは低いのですが、実装面ではGBDTモデルに比べるとやや高度な知識や設定が求められる印象があります。
# Kaggle Notebookではデフォルトで組み込まれていないので、インストールが必要。
!pip install pytorch-tabnet
import torch.optim as optim
from torch.optim.lr_scheduler import ReduceLROnPlateau
from pytorch_tabnet.tab_model import TabNetRegressor
# カテゴリ変数がある場合、以下の変数を設定してください(なければ空リストでOK)
cat_dims = [] # 例: [4, 3] # 各カテゴリ変数のユニークな値の数
cat_emb_dim = 1 # カテゴリ変数の埋め込み次元
cat_idxs = [] # 例: [0, 2] # カテゴリ変数の列インデックス
# 最大エポック数
MAX_EPOCH = 50
# TabNet のパラメータ定義
tabnet_params = dict(
n_d=8, # 決定層の次元数
n_a=8, # アテンション層の次元数
n_steps=2, # アーキテクチャ内のステップ数
gamma=1.3, # 特徴量再利用のリラクゼーション係数
lambda_sparse=0, # スパース性正則化パラメータ
optimizer_fn=optim.Adam, # オプティマイザとしてAdamを使用
optimizer_params=dict(lr=1e-2, weight_decay=1e-5), # 学習率やweight decayの設定
mask_type="entmax", # マスクの種類("sparsemax"も選択可能)
scheduler_params=dict(
mode="min", patience=5, min_lr=1e-5, factor=0.9), # 学習率スケジューラの設定
scheduler_fn=ReduceLROnPlateau, # 学習率スケジューラ
seed=42, # 乱数シード
verbose=5, # ログ出力の詳細レベル
cat_dims=cat_dims, # カテゴリ変数の次元数リスト
cat_emb_dim=cat_emb_dim, # カテゴリ変数の埋め込み次元
cat_idxs=cat_idxs # カテゴリ変数の列インデックス
)
# TabNetRegressor のモデル定義
model = TabNetRegressor(**tabnet_params)
# ダミーデータの生成(実際はご自身のデータを使用してください)
# X_train: (サンプル数, 特徴量数) の numpy array, y_train: ターゲット値 (サンプル数, 1)
X_train = np.random.rand(1000, 20)
y_train = np.random.rand(1000).reshape(-1, 1)
X_valid = np.random.rand(200, 20)
y_valid = np.random.rand(200).reshape(-1, 1)
# モデルの学習
model.fit(
X_train, y_train,
eval_set=[(X_valid, y_valid)],
max_epochs=MAX_EPOCH, # 最大エポック数の指定
batch_size=512, # バッチサイズの指定
virtual_batch_size=64, # 仮想バッチサイズ(Ghost Batch Normalization用)
num_workers=0, # データローダーのワーカー数(0ならメインスレッドで実行)
drop_last=False # 最後の不完全なバッチを切り捨てるか否か
)
# 検証データに対する予測
preds = model.predict(X_valid)
print("Predictions:", preds)
# ※ TabNet は教師なし学習による事前学習を追加することも可能です。
英語にはなりますが、TabNetの解説をしたNotebookも公開しています。参考になれば幸いです。https://www.kaggle.com/code/masayakawamata/s5e2-tabnet-baseline
3. TabM
2024年末頃に、CatBoostの開発元であるYandexから公開された新たなテーブルデータ用ニューラルネットワークモデルが「TabM」です。TabMは、従来のGBDTに匹敵する、あるいはそれを超える性能が期待されるモデルとして注目されています。実際、UM – Game-Playing Strength of MCTS Variantsコンペのトップソリューションでも、アンサンブルの一要素として採用され話題となりました。今後の活躍が非常に期待される注目モデルです。他のモデルと比べ実装はハードめです。現に、私自身まだ慣れていないのでコード例は今のところ出せません。。自分のためにも別記事でまとめようと思っているところです。
Kaggleの公開コードを見ると実装例が増えてきていますね。
https://www.kaggle.com/code?searchQuery=tabM
まとめ
テーブルデータコンペでまず検討すべきは、信頼性の高いGBDT系モデル(XGBoost、LightGBM、CatBoost)です。テーブルデータコンペにおいてこれらは基本中の基本であり、実装やパラメータ調整を通じて徐々に理解を深めることができるでしょう。さらに、TabNetや最新のTabMといったニューラルネットワークベースのモデルも、アンサンブルの一部として導入することで、より高い精度が期待できる可能性があります。
まずは動くコードを書けるようにし、身をもって体験しながら、各モデルの特徴を学んでいくことが大事だと思います。
各モデルの長所を理解し、実践で使い分けられる人が安定していい順位を取っている印象です、
コメント