タイタニックで機械学習お勉強の振り返り記事第二弾です。
前回はこちら↓
全体の予定
#1 最低限の前処理+パラメータチューニングなしの3モデル+stratified-k-fold
#2 特徴量をいくつか追加投入
#3 RFEによる特徴選択を試みる
#4 モデルのパラメータチューニング
#5 アンサンブルその1:シンプルなブレンド
#6 アンサンブルその2:スタッキング
今回は、前回のものにいくつか特徴量を追加で作成して投入して、モデルのスコアが改善されるかどうか見てみようと思います。
特徴量エンジニアリング
既存のデータセット内の特徴量から、新しい特徴量を作成してそれを用いることで、スコアが改善するかどうか試してみようと思います。
今回は簡単に作成できるもの、ということで、
①HasCabin:Cabinの値を持っているかどうか
②FamilySize:何人家族か
③IsAlone:一人で搭乗
の3つの特徴量を作成して、モデルに投入してみることにします。
カーネルを見ると、Nameからちょこっと複雑な処理をして敬称をわけたりだとかいろいろな特徴量作成の試みが見られます。
時間に余裕ができたらもっとそこを勉強していきたいです、、。
Cabinを扱いたい
前回では、Cabinは欠損値が非常に多かったため、説明変数としては扱わず、データセットから除外しました。
pandas_profiling_reportを見ると
Cabin
has 687 / 77.1% missing values MissingCabin
has a high cardinality: 148 distinct values Warning
なんていう風に警告を出してくれています。
ですが、使わないのはもったいないので、(効果あるかどうかは別として)Cabinの値を持っているかどうか、という特徴量として利用したいと思います。
1 2 3 4 5 6 7 8 |
#データの読み込み train = pd.read_csv("train.csv") test = pd.read_csv("test.csv") full_data = [train,test] #HasCabin for dataset in full_data: dataset["HasCabin"] = dataset["Cabin"].apply(lambda x : 0 if type(x) == float else 1) |
欠損はNaNとして入っており、NaNはfloat型ですので、type()関数で条件文をつくります。
np.isnan()を使ってもできると思います。
FamilySizeとIsAlone
デフォルトで存在する
SibSp : 乗船者の兄弟・配偶者の数
Parch : 乗船者の親・子供の数
を用いて、家族の人数や、一人で乗船したかどうかの特徴量を作ります。
1 2 3 4 5 6 7 8 |
#FamilySize for dataset in full_data: dataset["FamilySize"] = dataset["SibSp"] + dataset["Parch"] +1 #IsAlone for dataset in full_data: dataset["IsAlone"] =0 dataset.loc[dataset["FamilySize"]==1,"IsAlone"]=1 |
FamilySizeで最後にプラス1するのは、本人を含めるためです。
IsAloneは、いったんすべての行を0埋めした後に、FamilySizeが1(すなわち一人で乗船)の行のみ1を立てる処理です。
その他の処理(#1と同じ)
前回同様、欠損値埋めとカテゴリ変数処理も行います。
1 2 3 4 5 6 7 8 9 |
for dataset in full_data: #欠損値の処理 dataset["Embarked"] = dataset["Embarked"].fillna("S") dataset["Fare"] = dataset["Fare"].fillna(train["Fare"].median()) dataset["Age"] = dataset["Age"].fillna(train["Age"].median()) #カテゴリ変数の処理 dataset = pd.get_dummies(dataset,columns=["Embarked"]) dataset = dataset["Sex"].map({"male":0,"female":1}) |
使わない特徴量を落とす
以下の特徴量は使わないのでデータセットから削除します。
・passengerId :予測には役に立たないでしょう
・Name : これはうまくいじくると有効な特徴量になるようです。が、今回は見送ります。
・Ticket : これも使えるようですが、扱いが難しいため見送ります。
・Cabin : そのままでは使えないので、HasCabinを作りました。もとのCabinは不要です
・SibSp : FamilySizeで使用したので、落とします。
1 2 3 |
drop_elements = ["PassengerId","Name","Ticket","Cabin","SibSp"] train = train.drop(drop_elements,axis=1) test = test.drop(drop_elements,axis=1) |
最終的に以下のようになりました。

モデルのスコア比較
では、今回の特徴量では、どのようなスコアが出るか見ていきたいと思います。
前回(#1)と同じように、stratified-k-foldでRF,XGB,LGBMで学習します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
kf = StratifiedKFold(n_splits=10,shuffle=True,random_state=1) #Random Forest rf_scores = [] for i,(train_index,test_index) in enumerate(kf.split(X_set,y_set)): X_cv_train = X_set.iloc[train_index] X_cv_test = X_set.iloc[test_index] y_cv_train = y_set[train_index] y_cv_test = y_set[test_index] clf = RandomForestClassifier(random_state=1) clf.fit(X_cv_train,y_cv_train) y_cv_pred = clf.predict(X_cv_test) acc = accuracy_score(y_cv_test,y_cv_pred) rf_scores.append(acc) #XGBoost xgb_scores = [] for i,(train_index,test_index) in enumerate(kf.split(X_set,y_set)): X_cv_train = X_set.iloc[train_index] X_cv_test = X_set.iloc[test_index] y_cv_train = y_set[train_index] y_cv_test = y_set[test_index] clf = xgb.XGBClassifier(random_state=1) clf.fit(X_cv_train,y_cv_train) y_cv_pred = clf.predict(X_cv_test) acc_score = accuracy_score(y_cv_test,y_cv_pred) xgb_scores.append(acc_score) #LightGBM gbm_scores = [] for i,(train_index,test_index) in enumerate(kf.split(X_set,y_set)): X_cv_train = X_set.iloc[train_index] X_cv_test = X_set.iloc[test_index] y_cv_train = y_set[train_index] y_cv_test = y_set[test_index] clf = gbm.LGBMClassifier(random_state=1) clf.fit(X_cv_train,y_cv_train) y_cv_pred = clf.predict(X_cv_test) acc_score = accuracy_score(y_cv_test,y_cv_pred) gbm_scores.append(acc_score) |
結果は以下の通りです。
▼今回のスコア

▼前回のスコア

総じて、LBscoreはすべてのモデルで改善が見られました。
一方で、CVスコアはRF,XGBで下がってしまっています。
いったんおわり
今回は、特徴量を作って加えた、いわば足し算の作業でしたが、おそらく不要な特徴量も混じっているはずです。
Garbage in, garbage out
なんていう言葉もあるように、予測に無意味な特徴量があったら削除する引き算の操作も必要です。
次は現在の特徴量の中から、予測に意味のある特徴の選択を行ってスコアを見てみたいと思います。
最後まで読んでいただきありがとうございました。
続きはこちら↓
【Kaggle】タイタニックの振り返り#3 RFECVで特徴選択