Kaggle のタイタニック問題をやってみる(2)
前回はタイタニック問題のデータの中身を調査しましたので、今回はそのデータを元に学習し予測していきたいと思います。
訓練データ準備
今回使いたいデータの項目は、Pclass(チケットクラス)と年齢と性別です。まずは、年齢について何とかします。欠損値がたくさんあったので、これを何とかしないといけません。欠損値を何か適当なそれっぽいデータで埋めようと思うので、Pclass(チケットクラス)毎に年齢の平均を出してみます。
import numpy as np import pandas as pd import seaborn as sns from sklearn.model_selection import train_test_split from keras.layers import Dense from keras.models import Sequential %matplotlib inline
df = pd.read_csv("/root/practice/titanic/csv/train.csv") df[["Pclass", "Age"]].dropna().groupby(["Pclass"]).mean()
Pclass | Age |
---|---|
1 | 38.233441 |
2 | 29.877630 |
3 | 25.140620 |
得られたPclass(チケットクラス)毎の年齢の平均値で、欠損値を埋めます。
# Age 欠損値を埋める def fill_age(value): if not np.isnan(value[1]): return value[1] pclass_age_map = { 1: 38, 2: 30, 3: 25 } return pclass_age_map.get(value[0], 0) df["Age"] = df[["Pclass", "Age"]].apply(fill_age, axis=1)
続いて、性別を0,1の値にして、学習に適した形にします。
# 性別を0, 1にする sex = pd.get_dummies(df["Sex"], drop_first=True, dtype=int) # 性別を0,1にしたデータを結合しておく --> male という列が最後にできている形になる df = pd.concat([df, sex], axis=1)
この時点でこのようなデータになっています。
df.head()
PassengerId | Survived | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | male | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 3 | Braund, Mr. Owen Harris | male | 22.0 | 1 | 0 | A/5 21171 | 7.2500 | NaN | S | 1 |
1 | 2 | 1 | 1 | Cumings, Mrs. John Bradley (Florence Briggs Thayer) | female | 38.0 | 1 | 0 | PC 17599 | 71.2833 | C85 | C | 0 |
2 | 3 | 1 | 3 | Heikkinen, Miss. Laina | female | 26.0 | 0 | 0 | STON/O2. 3101282 | 7.9250 | NaN | S | 0 |
3 | 4 | 1 | 1 | Futrelle, Mrs. Jacques Heath (Lily May Peel) | female | 35.0 | 1 | 0 | 113803 | 53.1000 | C123 | S | 0 |
4 | 5 | 0 | 3 | Allen, Mr. William Henry | male | 35.0 | 0 | 0 | 373450 | 8.0500 | NaN | S | 1 |
今回は、学習に利用する項目としてPclass(チケットクラス)と性別と年齢のみを対象にしたいので、必要な列を除いて(性別の元データ列も含めて)削除します。
# 不要カラム削除 df.drop(["Name", "Sex", "SibSp", "Parch", "Ticket", "Fare", "Cabin", "Embarked"], axis=1, inplace=True)
そうすると、これだけスッキリしたデータになりました。
df.head()
PassengerId | Survived | Pclass | Age | male | |
---|---|---|---|---|---|
0 | 1 | 0 | 3 | 22.0 | 1 |
1 | 2 | 1 | 1 | 38.0 | 0 |
2 | 3 | 1 | 3 | 26.0 | 0 |
3 | 4 | 1 | 1 | 35.0 | 0 |
4 | 5 | 0 | 3 | 35.0 | 1 |
このデータで訓練データを作成します。作成には sklearn の train_test_splitを利用します。
X_train, X_test, y_train, y_test = train_test_split( df.drop(["Survived"], axis=1), df["Survived"], test_size=0.10, random_state=101 )
訓練データの元となるデータは、データから Survived 列を除いたもの(train_test_splitの第一引数)、教師データの元となるデータは Survived 列のデータ(train_test_splitの第二引数)になります。これで訓練データが作成できました。X_train, y_train の中身を確認しておきます。
X_train.head()
PassengerId | Pclass | Age | male | |
---|---|---|---|---|
825 | 826 | 3 | 25.0 | 1 |
8 | 9 | 3 | 27.0 | 0 |
689 | 690 | 1 | 15.0 | 0 |
513 | 514 | 1 | 54.0 | 0 |
729 | 730 | 3 | 25.0 | 0 |
y_train.head()
Survived | |
---|---|
825 | 0 |
8 | 1 |
689 | 1 |
513 | 1 |
729 | 0 |
学習
データの下準備はできたので、学習していきます。まずはニューラルネットワークを構築します。
model = Sequential() # [中間層] ユニット数: 32, 重み初期化方法: uniform, 活性化関数: reru, 入力: 4項目 model.add(Dense(units=32, kernel_initializer='uniform', activation='relu', input_dim=4)) model.add(Dense(units=32, kernel_initializer='uniform', activation='relu')) # [出力層] ユニット(出力)数: 1, 重み初期化方法: uniform, 活性化関数: シグモイド model.add(Dense(units=1, kernel_initializer='uniform', activation='sigmoid')) # 最適化アルゴリズム: adam, 目的(損失)関数: 平均二乗誤差 model.compile(optimizer='adam', loss='mean_squared_error', metrics=['accuracy'])
三層のニューラルネットワークを構築しました。各層の詳細な設定はソース内のコメントを参照してください。
それでは学習していきます。
# バッチサイズ: 32, 反復数: 300 history = model.fit(X_train, y_train, batch_size=32, epochs=300, verbose=1)
学習結果を折れ線グラフで表示させてみます。
sns.lineplot(data=history.history["loss"])
sns.lineplot(data=history.history["accuracy"])
学習を重ねる毎に誤差が減少し、精度が増加していくことがわかります。
テストデータ準備
学習ができたので、テストデータの予測していきます。 前回のブログでも書いた通り、訓練データから「生存フラグ」項目が無いものがテストデータになります。 データの準備は訓練データと同じなので、同じ手順でデータを加工していきます。
df_test = pd.read_csv("/root/practice/titanic/csv/test.csv")
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_test.isnull().sum().sort_values(ascending=False)
data | |
---|---|
Cabin | 327 |
Age | 86 |
Fare | 1 |
PassengerId | 0 |
Pclass | 0 |
Name | 0 |
Sex | 0 |
SibSp | 0 |
Parch | 0 |
Ticket | 0 |
Embarked | 0 |
データ数は418行、テストデータの年齢の項目にも欠損値が多数あるようです。
# Age の欠損値を埋める df_test["Age"] = df_test[["Pclass", "Age"]].apply(fill_age, axis=1) # 性別を 0, 1 にする sex = pd.get_dummies(df_test["Sex"], drop_first=True, dtype=int) df_test = pd.concat([df_test, sex], axis=1)
df_test.head()
PassengerId | Pclass | Name | Sex | Age | SibSp | Parch | Ticket | Fare | Cabin | Embarked | male | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 892 | 3 | "Kelly, Mr. James" | male | 34.5 | 0 | 0 | 330911 | 7.8292 | NaN | Q | 1 |
1 | 893 | 3 | "Wilkes, Mrs. James (Ellen Needs)" | female | 47.0 | 1 | 0 | 363272 | 7.0000 | NaN | S | 0 |
2 | 894 | 2 | "Myles, Mr. Thomas Francis" | male | 62.0 | 0 | 0 | 240276 | 9.6875 | NaN | Q | 1 |
3 | 895 | 3 | "Wirz, Mr. Albert" | male | 27.0 | 0 | 0 | 315154 | 8.6625 | NaN | S | 1 |
4 | 896 | 3 | "Hirvonen, Mrs. Alexander (Helga E Lindqvist)" | female | 22.0 | 1 | 1 | 3101298 | 12.2875 | NaN | S | 0 |
# 不要カラム削除 df_test.drop(["Name", "Sex", "SibSp", "Parch", "Ticket", "Fare", "Cabin", "Embarked"], axis=1, inplace=True)
df_test.head()
PassengerId | Pclass | Age | male | |
---|---|---|---|---|
0 | 892 | 3 | 34.5 | 1 |
1 | 893 | 3 | 47.0 | 0 |
2 | 894 | 2 | 62.0 | 1 |
3 | 895 | 3 | 27.0 | 1 |
4 | 896 | 3 | 22.0 | 0 |
予測
テストデータの準備ができたので、いよいよ予測していきたいと思います。
# 学習済みのニューラルネットワークで予測 test_predicts = model.predict(df_test) test_predicts = [ 1 if y >= 0.5 else 0 for y in test_predicts]
出力された値(予測)を0,1にするところまでできたので、予め決められた提出するファイルのフォーマットにする準備をします。
# 提出用のCSVを出力する準備 df_test_result = pd.DataFrame({ 'PassengerId': df_test['PassengerId'], 'Survived': test_predicts }) df_test_result.head()
PassengerId | Survived | |
---|---|---|
0 | 892 | 0 |
1 | 893 | 1 |
2 | 894 | 0 |
3 | 895 | 0 |
4 | 896 | 1 |
後はCSVに出力するだけです。
df_test_result.to_csv("/root/practice/titanic/csv/predictions.csv", index=False)
提出
予測結果をCSVに出力することができたので、提出してみます。 Titanic - Machine Learning from Disasterのページに行き、「Submit Predictions」ボタンを押下して、CSVファイルをアップロードします。 エラーが無ければ、アップロードに成功した旨の通知が来るので、Leaderboardで自分の順位を確認します。
おおおおおおお!圧倒的に下から数えた方が早い順位ですが、Leaderboardに自分の名前が刻まれました!