TPTブログ

テックポート株式会社のブログです。 技術情報や製品・サービス情報、 また未経験社員がデータサイエンティストを 目指す奮闘記など、更新していきます。

▲Kaggleやってみよう【Titanic:生存者の予測】後篇

f:id:TBT_matsu:20200409154540p:plain
こんにちは。
テービーテックの村松です。

本日はこちらの続きをご紹介いたします。
ds-blog.tbtech.co.jp

前回は各項目が生存率に確認していそうかグラフ化しながら確認していきました。
今日は使用する項目を選んで前処理から最終のKaggleに提出してスコアを出すところまでやっていきます。

どれを使っていこうか・・・

とりあえず、前回生存率と関係がありそうだと確認が取れている以下の7つを使用していきます。

・Pclass
・Sex
・Age
・SibSp
・Parch
・Fare
・Embarked

そのまま学習するにはいろいろ不都合もありますのでそれぞれの項目に前処理を施していきます。
最初に欠損値の確認をしてみましょうか。

#欠損値の確認(train_data)
train_data.isnull().sum()
#output
PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64
#欠損値の確認(test_data)
test_data.isnull().sum()
#output
PassengerId      0
Pclass           0
Name             0
Sex              0
Age             86
SibSp            0
Parch            0
Ticket           0
Fare             1
Cabin          327
Embarked         0
dtype: int64

使用する項目で欠損があるのは「Age」・「Fare」・「Embarked」ですね。
これを踏まえて前処理を考えていきましょう。

  • Pclass

要素は整数型で入ってはいますが、項目としてはカテゴリの意味合いだと思います。
なのでOne-Hot Encodingで行きましょう。

  • Sex

こちらもOne-Hot Encodingしましょう。

  • Age

こちらは欠損値の数が結構あります。
悩ましいところですが、変に平均値とか中央値で埋めるのも違和感がありますので、今回はあえて欠損のままにしておきます。

  • SibSp・Parch

こちら2項目は欠損もありませんし、特に何もしません。

  • Fare

欠損数は2つなので中央値あたりで補完します。

  • Embarked

欠損は最頻値で埋めて、そのうえでOne-Hot Encodingします。

前処理開始

まずは前処理をまとめてするために「train_data」と「test_data」結合します。

df_original = pd.concat([train_data, test_data], sort=False)

片方だけ処理し忘れ等うかっり防止と、
test_dataを考慮した処理が可能という利点があります。
ただ、実務ではtest_dataがない場合も多いのでtest_dataの情報を利用することに否定的な意見もあるようです。

続いて、今回使用する項目のみを抜き出します。

#不要な列の削除
drop_list = ['PassengerId', 'Name', 'Ticket', 'Cabin', 'Survived']
_df = df_original.drop(drop_list, axis=1)
_df

f:id:TBT_matsu:20200410135019p:plain
では、欠損値を補完します。

#’Fare’中央値で補完
_df.Fare.fillna(_df.Fare.median(), inplace=True)
#’Embarked’最頻値で補完
_df.Embarked.fillna(_df.Embarked.mode()[0], inplace=True)
#ちゃんと欠損値が補完されたか確認
_df.isnull().sum()
##output
Pclass        0
Sex           0
Age         263
SibSp         0
Parch         0
Fare          0
Embarked      0
dtype: int64

大丈夫そうですね。
最後にカテゴリカル変数をOne-Hot Encodingします。

#’Pclass’を文字列に変換
_df['Pclass'] = _df['Pclass'].astype('str')

#カテゴリカル変数をOneHotEncoder
df = pd.get_dummies(_df)
df

f:id:TBT_matsu:20200410141908p:plain

データの分割

前処理が完了しましたので、結合していた「train_data」と「test_data」を再び分離させ、trainデータをモデルに入れるように分割していきましょう。

#結合していた「train_data」と「test_data」を分離
train_df = df[:train_data.shape[0]]
test_df = df[train_data.shape[0]:]
#train_dfの教師データとして
target = train_data['Survived']

#train_dfとtargetの分割
from sklearn.model_selection import train_test_split
x_train, x_val, y_train, y_val = train_test_split(train_df, target, test_size=0.2, random_state=0, stratify=target)
#確認
x_train.shape, x_val.shape, y_train.shape, y_val.shape
##output
((712, 12), (179, 12), (712,), (179,))

モデルの構築

いよいよ学習を始めます。
ここまで長かったですね。
今回はみんな大好きな機械学習モデル「XGBoost」を使用いたします。

from xgboost import XGBClassifier
model = XGBClassifier(random_state=0)
model.fit(x_train, y_train)
##output
XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
              colsample_bynode=1, colsample_bytree=1, gamma=0,
              learning_rate=0.1, max_delta_step=0, max_depth=3,
              min_child_weight=1, missing=None, n_estimators=100, n_jobs=1,
              nthread=None, objective='binary:logistic', random_state=0,
              reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None,
              silent=None, subsample=1, verbosity=1)

スコアを確認します。

print(model.score(x_train, y_train))
print(model.score(x_val, y_val))
#output
0.8960674157303371
0.8268156424581006

おお・・・。
一発目にしては良い感じ、でしょうか?

本来ならここからハイパーパラメータのチューニングをするのが正しいのでしょうが、割愛。

予測結果の提出

ここからは予測結果を提出用のcsvファイルに書き出していきます。

#推論
pre = model.predict(test_df)
pre
##output
array([0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1,
       1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1,
       1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1,
       1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0,
       1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
       0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
       0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1,
       1, 1, 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, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0,
       1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
       1, 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, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
       0, 0, 0, 0, 0, 1, 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, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
       1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,
       0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0])

これが予測された結果です。

提出用のcsvファイルの中身はというと、

#提出ファイルの形式を確認
gender_submission = pd.read_csv('/content/drive/My Drive/04-15/gender_submission.csv')
gender_submission

f:id:TBT_matsu:20200410144555p:plain
こんな形。
これと同じ形に整えていくので、まずはtestの「PassengerId」が必要ですね。

#testの「PassengerId」の抜出
PassengerId = np.array(test_data['PassengerId']).astype(int)

そして、先ほど出した予測結果と合わせましょう。

# predictで出した結果と一緒にデータフレームにします。
submission = pd.DataFrame(pre, PassengerId, columns = ["Survived"])

現在submissionはこんな感じです。
f:id:TBT_matsu:20200410145328p:plain
あれ、「PassengerId」の要素がインデックスになってると一瞬あわてたのですが、まだもう一段回ありました。

#csvファイルへの書き出し
submission.to_csv('書き出し先/submission.csv', index_label=['PassengerId'])

出力された「submission.csv」を確認すると、
f:id:TBT_matsu:20200410145834p:plain
ちゃんと提出用の形に整いましたね。

結果

f:id:TBT_matsu:20200410150236p:plain
お、おおお。
初歩の初歩とはいえ、最後まで行くと達成感ありますね。
ハイパーパラメータのチューニングや学習方法を変えていけば更に向上させることもできそうですね。
Kaggleは「Norebooks」というタブから色々な方のコードを見ることができますので、そちらも読みながら改良方法を勉強していくことができます。
今回もだいぶお世話になりました。
全世界の先生の胸を借りれると思うと頼もしい限りですね。

では、これにて「Kaggleやってみよう【Titanic:生存者の予測】」終了です。
ここまで目を通していただき、ありがとうございました!