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のすごさを見てみようと思う。