【kaggle初級入門編】タイタニック号乗客の生存予測

# タイタニック号乗客の生存予測の前に
【プログを書く目的】
　●プログを書くことで、今後の転職活動に利用するため
　●レポートの向上のため
　●プログを書いていくことで自身のスキルの向上を確認し、モチベーションの維持のため

【現在の経歴】
　●市場調査会社に約2年半年在籍後、未経験でデータサイエンスの会社に転職
　●現在携わっている案件が、「データ抽出」,「ツールの研修講師」から
　機械学習を行うことがないためkaggleで腕を磨く

# モデルの評価方法
　●タイタニック号の沈没で乗客が生き残ったかどうかを予測する精度の高いモデルの構築

# データの中身
PassengerId：乗客ID
Survived：生き残り（1 = 生存、0 = 死亡）
Pclass：チケットのクラス（ 1 = 1等,、2 = 2等、 3 = 3等）
Name：名前
Sex：性別
Age：年齢
SibSp：タイタニック号に同乗している配偶者/兄弟の数
Parch：タイタニック号に同乗している親/子供の数
Ticket：チケット番号
Fare：運賃
Cabin：キャビン（客室）番号
Embarked：どこで乗船したか
（C = Cherbourg, Q = Queenstown, S = Southampton）

```
# モデルの学習で使用するデータ
df_train = pd.read_csv("/kaggle/input/titanic/train.csv")

# 予測に使用するデータ
df_test = pd.read_csv("/kaggle/input/titanic/test.csv")
```
```
# trainデータを先頭から5行を表示
df_train.head(5)"
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/6a0cc840-946e-883f-4d73-94b446439ad0.png)
```
# testデータを先頭から5行を表示
df_test.head(5)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/b07723bb-585b-03c0-e720-2feac0097a9d.png)

# データ件数
学習データが891データ,テストデータが418データがある
```
# 学習データ件数の確認
df_train.shape
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/6fcde8f7-8da9-23cd-2024-25ca22bc514b.png)
```
# テストデータ件数の確認
df_test.shape
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/00b78799-2d74-e120-09ad-10f693dc6404.png)

# 正解データ（Survived）の集計
死亡者が549人,生存者が342人と比率が不均等のデータであることがわかる
```
# 正解データ（生存有無）のデータ数確認
df_train['Survived'].value_counts()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/9b298a7f-5f03-7714-e711-084a6d361247.png)

# 欠損値の確認
・学習用データは、以下のカラムの欠損値を確認
年齢（Age）：177件
キャビン番号（Cabin）：687件
どこで乗船したか（mbarked）：2件
```
# 欠損値の確認
df_train.isnull().sum()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/1937408c-5acc-795f-80c4-67c78a43990d.png)
・テスト用データは、以下のカラムの欠損値を確認
年齢（Age）：86件
運賃（Fare）：1件
キャビン番号（Cabin）：327件
```
# 欠損値の確認
df_test.isnull().sum()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/81cae6e8-9d64-4965-bbb8-7d1e0a989203.png)

# 学習用データとテストデータを結合
統合する理由として、学習データ,テストデータを合わせた全体の集計や統計情報をとるため
```
# 学習データとテストデータを統合
all_df = pd.concat([df_train, df_test],sort = False).reset_index(drop = True)
all_df
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/bd56d18e-4e3f-7142-71c6-ce5681737e33.png)
```
# 全体データで欠損値の数を確認
all_df.isnull().sum()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/33fac790-4e16-200c-ba5d-10f9b4478263.png)

# 性別を数値に変換
性別がmale,femaleと文字列のため数値に変換
```
#　性別を文字列から数値に変換
male = pd.get_dummies(all_df['Sex'], drop_first = True)

# データを結合
all_df_male = pd.concat([all_df,male], axis = 1)
all_df_male.head(2)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/3047ca24-723a-b043-c22d-7b7b4d4a08fa.png)


# 生き残る人の仮説・使用する特徴量
生き残るには、救命ボートに乗ることが必須
他に生き残るには、海に飛込み救助を待つこともあるが、氷山にぶつかる場所から、水温は低く長時間海にいることはできないと考えれえる。
そのため、「泳ぎが得意な人」,「ライフジャケットを着ている人」がいたとしては生存は厳しい。

救命ボードに乗るには、社会的地位が高い　かつ　子供⇒女性⇒男性の順で助けられると考える。
理由：当時イギリスは格差社会があり、家系を守るには子供,女性が必要であるため

# 欠損値の処理
今回使用する特徴で、年齢の欠損値が177件ある。
割合として、19.8%（欠損値 / 全体)あり、異なった数値を当てはめてしまうと精度が下がるため、補完する。
年齢と関係性のある特徴量を把握するためにまず相関を求める
```
import matplotlib.pyplot as plt
import seaborn

%matplotlib inline

# 相関の表示
plt.figure(figsize=(5,5))
seaborn.heatmap(all_df_male.corr(), annot=True)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/90964d7e-5488-f2b5-ff46-5c17fbd2c05c.png)


年齢と関係のある特徴量は、Fareとmaleである。
そのためFareとmaleを使って年齢を割り当てる。
①Fareをカテゴリ化する
※欠損値が1件あるため、平均値で代用
```
# Fareの列内にある欠損値部分をFare列のmean(平均値)で補完
all_df['Fare'] = all_df['Fare'].fillna(all_df['Fare'].mean())

# 7つのカテゴリーを作成（1つのカテゴリーの割合を15%以内にしたため）
fare_qcut = pd.qcut(all_df_male['Fare'],7)
fare_qcut.value_counts()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/36527393-8ec1-2eb4-833a-93db9b0e18a8.png)
```
# fareをカテゴリ化したのを数値データに置換
all_df_male["fare_int"] = pd.factorize(fare_qcut)[0]

# 表示
all_df_male
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/16b2d378-aa2d-1907-f8a3-887efb62c4f5.png)
②ピポットテーブルでsurviedとFareのカテゴリーごとの年齢の平均を確認
```
# クロス集計で各グループの平均値を確認
pd.pivot_table(all_df_male,index = 'male', columns = 'fare_int', values = 'Age')
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/c3020011-63d6-a6a1-da59-fd17c7f15ecc.png)
③年齢の欠損値をクロス集計で求めた各平均値を入れる
```
# Age列の欠損値の行を抜き出す
is_null = all_df_male['Age'].isnull()

# fare_int 1に関する埋め込み
all_df_male.loc[(all_df_male['fare_int'] == 0) & (all_df_male['male'] == 0) & (is_null),'Age'] = 25
all_df_male.loc[(all_df_male['fare_int'] == 0) & (all_df_male['male'] == 1) & (is_null),'Age'] = 30

# fare_int 2に関する埋め込み
all_df_male.loc[(all_df_male['fare_int'] == 1) & (all_df_male['male'] == 0) & (is_null),'Age'] = 37
all_df_male.loc[(all_df_male['fare_int'] == 1) & (all_df_male['male'] == 1) & (is_null),'Age'] = 36

# fare_int 3に関する埋め込み
all_df_male.loc[(all_df_male['fare_int'] == 2) & (all_df_male['male'] == 0) & (is_null),'Age'] = 23
all_df_male.loc[(all_df_male['fare_int'] == 2) & (all_df_male['male'] == 1) & (is_null),'Age'] = 28

# fare_int 4に関する埋め込み
all_df_male.loc[(all_df_male['fare_int'] == 3) & (all_df_male['male'] == 0) & (is_null),'Age'] = 28
all_df_male.loc[(all_df_male['fare_int'] == 3) & (all_df_male['male'] == 1) & (is_null),'Age'] = 32

# fare_int 5に関する埋め込み
all_df_male.loc[(all_df_male['fare_int'] == 4) & (all_df_male['male'] == 0) & (is_null),'Age'] = 25
all_df_male.loc[(all_df_male['fare_int'] == 4) & (all_df_male['male'] == 1) & (is_null),'Age'] = 27

# fare_int 6に関する埋め込み
all_df_male.loc[(all_df_male['fare_int'] == 5) & (all_df_male['male'] == 0) & (is_null),'Age'] = 28
all_df_male.loc[(all_df_male['fare_int'] == 5) & (all_df_male['male'] == 1) & (is_null),'Age'] = 34

# fare_int 6に関する埋め込み
all_df_male.loc[(all_df_male['fare_int'] == 6) & (all_df_male['male'] == 0) & (is_null),'Age'] = 25
all_df_male.loc[(all_df_male['fare_int'] == 6) & (all_df_male['male'] == 1) & (is_null),'Age'] = 29
```
④年齢の欠損値が修正されているか確認
```
# 欠損値の確認
all_df_male.isnull().sum()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696954/0e8a2515-1e75-a887-5756-59537918d01f.png)

# 学習モデル構築
決定木の機械学習を用いて予測
```
# 全てのデータを学習データとテストデータに戻す
train_X = all_df_male[~all_df_male['Survived'].isnull()].drop('Survived',axis = 1).reset_index(drop = True)
train_Y = df_train['Survived']

test_X = all_df_male[all_df_male['Survived'].isnull()].drop('Survived',axis = 1).reset_index(drop = True)

# 使用するデータ
col = ['male', 'Age', 'Pclass']
df_train_x = train_X[col]

# モデル作成
from sklearn import tree
model = tree.DecisionTreeClassifier(max_depth = 3,random_state = 0, class_weight = 'balanced')

# モデル学習
model.fit(df_train_x,train_Y)
```
# 予測と出力結果
モデルにテストデータを学習させた結果、0.77511の評価となった。
```
# 使用するデータ
col_test = ['male', 'Age', 'Pclass']
df_test_X = test_X[col_test]

# 「test」の説明変数を使ってモデルで予測
my_prediction = model.predict(df_test_X)
```

# 今後
初めて機械学習を行ったが、前処理で行うことが多く大変さを身に染みて感じました...
次回は、モデルのチューニングや他のモデルを使ってより精度の高いモデルを作成したいと思います。