『【PFN】OPTUNAを簡単に使ってみた 』でOPTUNA(オプチュナ)の使い方やら挙動やらを簡単にみていきましたので、それを、この界隈の方なら必ず通るであろう、タイタニックデータで使ってみようと思います。ひとまず、実データでOPTUNAを動かすことが目的なので、Feature Engineeringをせずシンプルにやっていきます。
kaggleタイタニックデータ
これがここでDLできます⇒Titanic – Machine Learning from Disaster
同じものかどうか分かりませんが、カグルの日本版的なSIGNATEにもありますね。
タイタニック号の乗船者リスト(trainとtest)用意したから、
trainデータでモデル作ってtestデータで生存者予測してみればすごくいいMLの練習になるんだよ、
っていうやつですね。
passengerId | 通し番号 | |
survived(目的変数) | 生存 | 0 =いいえ、1=はい |
pclass | チケットクラス | 1 = 1st, 2 = 2nd, 3 = 3rd |
name | 名前 | |
sex | 性別 | |
Age | 年齢 | |
sibsp | タイタニック号に乗っている兄弟/配偶者の数 | |
parch | タイタニック号に乗っている親/子供の数 | |
ticket | チケット番号 | |
fare | 運賃 | |
cabin | 客室番号 | |
embarked | 乗船港 | C =チェルブール、Q =クイーンズタウン、S=サウサンプトン |
これらがまとまってます。
具体的に見ていく
前回同様グーグルコラボでやるので、インストールから。
!pip install optuna
インストール完了。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use("ggplot")
import optuna
いつものと、optunaをインポート。
DLしたデータを読み込みます。
df_train=pd.read_csv("/content/drive/MyDrive/Colab Notebooks/Machine Learning/data/kaggle/titanic/train.csv")
df_test=pd.read_csv("/content/drive/MyDrive/Colab Notebooks/Machine Learning/data/kaggle/titanic/test.csv")
trainとtest、それぞれこんなです。
df_train.head()
index | PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.25 | NaN | S |
1 | 2 | 1 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Thayer) | female | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | C |
2 | 3 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.925 | NaN | S |
3 | 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35.0 | 1 | 0 | 113803 | 53.1 | C123 | S |
4 | 5 | 0 | 3 | Allen, Mr. William Henry | male | 35.0 | 0 | 0 | 373450 | 8.05 | NaN | S |
df_train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PassengerId 891 non-null int64
1 Survived 891 non-null int64
2 Pclass 891 non-null int64
3 Name 891 non-null object
4 Sex 891 non-null object
5 Age 714 non-null float64
6 SibSp 891 non-null int64
7 Parch 891 non-null int64
8 Ticket 891 non-null object
9 Fare 891 non-null float64
10 Cabin 204 non-null object
11 Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
df_test.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 11 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PassengerId 418 non-null int64
1 Pclass 418 non-null int64
2 Name 418 non-null object
3 Sex 418 non-null object
4 Age 332 non-null float64
5 SibSp 418 non-null int64
6 Parch 418 non-null int64
7 Ticket 418 non-null object
8 Fare 417 non-null float64
9 Cabin 91 non-null object
10 Embarked 418 non-null object
dtypes: float64(2), int64(4), object(5)
memory usage: 36.0+ KB
ぱっと見よくわからないチケット番号と欠損値の多い客室番号やらを落とします。
df_train=df_train.drop(["PassengerId","Name","Ticket","Cabin"],axis=1)
df_test=df_test.drop(["PassengerId","Name","Ticket","Cabin"],axis=1)
trainみてやると
df_train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Survived 891 non-null int64
1 Pclass 891 non-null int64
2 Sex 891 non-null object
3 Age 714 non-null float64
4 SibSp 891 non-null int64
5 Parch 891 non-null int64
6 Fare 891 non-null float64
7 Embarked 889 non-null object
dtypes: float64(2), int64(4), object(2)
memory usage: 55.8+ KB
年齢も欠損多いので、dropnaでないやつ落とします。
df_train=df_train.dropna()
df_train.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 712 entries, 0 to 890
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Survived 712 non-null int64
1 Pclass 712 non-null int64
2 Sex 712 non-null object
3 Age 712 non-null float64
4 SibSp 712 non-null int64
5 Parch 712 non-null int64
6 Fare 712 non-null float64
7 Embarked 712 non-null object
dtypes: float64(2), int64(4), object(2)
memory usage: 50.1+ KB
これで学習データ形成します。
x=df_train.drop("Survived",axis=1)
t=df_train.iloc[:,0:1]
testデータ加工
続いて、testデータの方ですが、
df_test.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Pclass 418 non-null int64
1 Sex 418 non-null object
2 Age 332 non-null float64
3 SibSp 418 non-null int64
4 Parch 418 non-null int64
5 Fare 417 non-null float64
6 Embarked 418 non-null object
dtypes: float64(2), int64(3), object(2)
memory usage: 23.0+ KB
年齢と運賃をどうにかしないとなので、
df_test["Age"]=df_test["Age"].fillna(df_test["Age"].median())
df_test["Fare"]=df_test["Fare"].fillna(df_test["Fare"].median())
各々中央値でサクッと埋めます。
あとは、カテゴリデータを数値に変換していきます。
from sklearn.preprocessing import LabelEncoder
lbl=LabelEncoder()
x["Embarked"]=lbl.fit_transform(x["Embarked"])
x["Sex"]=lbl.fit_transform(x["Sex"])
df_test["Embarked"]=lbl.fit_transform(df_test["Embarked"])
df_test["Sex"]=lbl.fit_transform(df_test["Sex"])
これにて準備完了。
lightGBMをOPTUNAで探索
from sklearn.model_selection import train_test_split
from sklearn import metrics
これらインポートして、分ける。
x_train,x_val,t_train,t_val=train_test_split(x,t,test_size=0.3,stratify=t,random_state=0)
print(x_train.shape,x_val.shape,t_train.shape,t_val.shape)
(498, 7) (214, 7) (498, 1) (214, 1)
lightGBMデータ作って、
import lightgbm as lgb
lgb_train=lgb.Dataset(x_train,t_train)
lgb_eval=lgb.Dataset(x_val,t_val)
さて、ここです。
def objective(trial):
params={"metric":"auc",
"objective":"binary",
"max_depth":trial.suggest_int("max_depth",5,1000),
"num_leaves":trial.suggest_int("num_leaves",2,1000),
"min_child_samples":trial.suggest_int("min_child_samples",1,300),
"learning_rate":trial.suggest_uniform("learning_rate",0.001,2)}
lgbm=lgb.train(params,
lgb_train,
valid_sets=lgb_eval,
num_boost_round=1000,
early_stopping_rounds=10,
verbose_eval=False)
return metrics.accuracy_score(t_val["Survived"],np.round(lgbm.predict(x_val)))
めちゃくちゃ簡単で、いつものをdef objective(trial)でくくって、中身を探索範囲に書き換えるだけ。
accuracyを、記載のハイパーパラメータの範囲で最大化させます。
study=optuna.create_study(direction="maximize")
study.optimize(objective, n_trials=1000)
1000回探索してもらいます。
長いので最後の1行の出力だけ書くと
Trial 999 finished with value: 0.8691588785046729
and parameters: {'max_depth': 5, 'num_leaves': 152, 'min_child_samples': 28, 'learning_rate': 0.8356853957155714}.
Best is trial 892 with value: 0.9065420560747663.
1000回目の探索は上記パラメータで正解率0.869、最高は893回目の0.907だったよー、と教えてくれました。ありがとう。
ベストモデルを評価
study.best_params,study.best_value
({'learning_rate': 0.6015951276617406,
'max_depth': 822,
'min_child_samples': 27,
'num_leaves': 998},
0.9065420560747663)
studyのbest_paramsに上記のように格納されているので、改めてこれらでモデル構築
bestparams={"metric":"auc",
"objective":"binary",
"max_depth":study.best_params["max_depth"],
"num_leaves":study.best_params["num_leaves"],
"min_child_samples":study.best_params["min_child_samples"],
"learning_rate":study.best_params["learning_rate"]}
best_lgbm=lgb.train(bestparams,
lgb_train,
valid_sets=lgb_eval,
num_boost_round=1000,
early_stopping_rounds=20,
verbose_eval=50)
ベストモデルでの正解率(train,val)は、
print(metrics.accuracy_score(t_train["Survived"],np.round(best_lgbm.predict(x_train))))
print(metrics.accuracy_score(t_val["Survived"],np.round(best_lgbm.predict(x_val))))
0.8755020080321285
0.9065420560747663
こんな感じ。テストデータでの予測は、
np.round(best_lgbm.predict(df_test))
array([0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 1., 0., 1., 1., 0.,
0., 1., 0., 0., 0., 1., 1., 1., 0., 1., 0., 1., 0., 0., 0., 1., 0.,
1., 0., 1., 0., 0., 0., 0., 1., 0., 1., 1., 0., 0., 0., 1., 1., 1.,
0., 1., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 1., 1., 1., 1., 0.,
0., 1., 1., 0., 1., 0., 1., 0., 0., 1., 0., 1., 1., 0., 0., 0., 0.,
0., 1., 1., 1., 1., 0., 0., 1., 0., 0., 0., 1., 0., 0., 0., 1., 0.,
0., 0., 1., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 1., 1.,
1., 1., 0., 1., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 0., 0., 1., 0., 0., 1., 0., 1., 0., 1., 0., 1., 0., 0.,
0., 0., 0., 1., 1., 1., 0., 1., 1., 1., 0., 0., 0., 0., 0., 1., 0.,
0., 0., 0., 0., 0., 1., 1., 0., 1., 1., 0., 0., 1., 0., 1., 0., 1.,
0., 0., 0., 0., 0., 0., 0., 1., 0., 1., 1., 0., 0., 1., 1., 0., 1.,
0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 1., 0., 1., 0., 1.,
0., 1., 0., 1., 1., 0., 1., 0., 0., 1., 1., 0., 0., 1., 0., 0., 0.,
1., 1., 1., 1., 0., 0., 0., 0., 1., 0., 1., 0., 1., 0., 0., 0., 0.,
0., 0., 0., 1., 0., 0., 0., 1., 1., 0., 0., 0., 0., 1., 0., 0., 0.,
1., 1., 0., 1., 0., 0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 0.,
0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 1., 1.,
0., 1., 0., 0., 0., 0., 0., 0., 1., 1., 0., 0., 0., 0., 0., 0., 0.,
1., 1., 0., 1., 0., 0., 0., 1., 0., 0., 1., 0., 0., 0., 0., 0., 0.,
0., 0., 0., 1., 0., 1., 0., 0., 0., 1., 1., 0., 0., 1., 1., 0., 1.,
0., 0., 1., 0., 1., 1., 0., 1., 0., 0., 0., 1., 0., 0., 1., 0., 0.,
1., 1., 0., 0., 0., 0., 0., 0., 0., 1., 0., 1., 0., 0., 0., 0., 0.,
1., 0., 0., 0., 1., 0., 1., 0., 0., 1., 0., 1., 1., 0., 0., 0., 0.,
1., 1., 1., 1., 0., 0., 1., 0., 0., 0.])
こんなんなりました、さて、提出データ作ってカグルに送信!