AI

コンペでの勾配Boostingについて

Kaggleなどのコンペでは初手にGBDT(Gradient Boosting Decision Tree)と言われるけど、なんでなんだっけ?みたいなところを勉強してみる。
ここではまずlightGBMを触って理解をしてみる。

とりあえずなけなしの知識での仮説としては、

1.カテゴリ変数を変換なく扱うことが出来る
2.欠損値をそのままでも扱うことが出来る

これが大きな要素であると理解をしている状況。

まずはLightGBMを使ってみる

titanicデータを使う。

import pandas as pd
import lightgbm as lg
import numpy as np

from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score,confusion_matrix

train = pd.read_csv('./titanic/train.csv')
test = pd.read_csv('./titanic/test.csv')

train.head()

簡単のために色々とドロップし、欠損があることを確認。

Y = train['Survived']

train.drop(['PassengerId','Survived','Name','Ticket'],axis=1,inplace=True)
test.drop(['PassengerId','Name','Ticket'],axis=1,inplace=True)

train.isnull().sum()

Pclass        0
Sex           0
Age         177
SibSp         0
Parch         0
Fare          0
Cabin       687
Embarked      2
dtype: int64

さすがにカテゴリー変数の指定を少ししないといけないのでそれの対応と学習処理。そして評価。

#先にやっとけばよかったね。
train_X,val_X,train_y,val_y = train_test_split(train,Y)

train_X.loc[:,['Sex','Cabin','Embarked']] = train_X.loc[:,['Sex','Cabin','Embarked']].astype('category')
val_X.loc[:,['Sex','Cabin','Embarked']] = val_X.loc[:,['Sex','Cabin','Embarked']].astype('category')

lg_train = lg.Dataset(train_X,train_y)
lg_eval  = lg.Dataset(val_X,val_y)
params={'objective':'binary','seed':71,'verbose':0,'metrics':'binary_logloss'}

model = lg.train(params,lg_train,num_boost_round=100,valid_names=['tran','test'],valid_sets=[lg_train,lg_eval])

va_pred = np.where(model.predict(val_X) >= 0.5,1,0)

accuracy_score(val_y,va_pred)
>0.7937219730941704

confusion_matrix(val_y,va_pred)
>array([[112,  25],
>       [ 21,  65]])

簡単に学習~推論が可能。

scikit-learnでロジスティック回帰

from sklearn.linear_model import LogisticRegression

model = LogisticRegression()

train = pd.read_csv('./titanic/train.csv')
test = pd.read_csv('./titanic/test.csv')

train.dropna(inplace=True)
test.dropna(inplace=True)

Y = train['Survived']

train.drop(['PassengerId','Survived','Name','Ticket'],axis=1,inplace=True)
test.drop(['PassengerId','Name','Ticket'],axis=1,inplace=True)

train_X,val_X,train_y,val_y = train_test_split(train,Y)

train_X.loc[:,['Sex','Cabin','Embarked']] = train_X.loc[:,['Sex','Cabin','Embarked']].astype('category')
val_X.loc[:,['Sex','Cabin','Embarked']] = val_X.loc[:,['Sex','Cabin','Embarked']].astype('category')

model.fit(train_X,train_y)

>could not convert string to float: 'S'

途中まではほぼ一緒。推論をしようとすると案の定エラーとなる。
カテゴリ変数でのエラーですね。

train = pd.read_csv('./titanic/train.csv')
test = pd.read_csv('./titanic/test.csv')

train.dropna(inplace=True)
test.dropna(inplace=True)

Y = train['Survived']

for c in ['Sex','Cabin','Embarked']:
    le = LabelEncoder()
    le.fit(train[c])
    train[c] = le.transform(train[c])

train.drop(['PassengerId','Survived','Name','Ticket'],axis=1,inplace=True)
test.drop(['PassengerId','Name','Ticket'],axis=1,inplace=True)

train_X,val_X,train_y,val_y = train_test_split(train,Y)

model = LogisticRegression(solver='liblinear')
model.fit(train_X,train_y)

va_pred = model.predict(val_X)

accuracy_score(val_y,va_pred)
>0.717391304347826

confusion_matrix(val_y,va_pred)
>array([[ 6,  7],
        [ 6, 27]])

欠損をdropしたり、カテゴリ変数をエンコーディングなどして、学習~推論が出来るようになる。
弊害は見てわかる通り、データ数がめっちゃ減る。
このあたりの補完方法を考えるとまぁまぁ、GBDTのほうに部が高いのかな、とも思う。

実際はどうなのか?

色々しらべると大体7個くらいの理由が上げられそうなことが分かった

初手GBDTの理由

1.欠損値をそのまま扱える
2.カテゴリ変数の指定が出来る
3.特徴量のスケーリングが不要
4.feature_importanceがわかる
5.精度が出やすい
6.比較的大きなデータにも使える
7.過去の経験からハイパーパラメータの勘所がある

とのこと。
一応、1,2に関しては知識通りで安心。

一旦ここで終わりにして、次はhttps://signate.jp/competitions/264/dataのデータを使ってGBDTのすごさを見てみようと思う。

-AI
-,