Kaggle_Titanic挑戦その2

こんにちは。Kosukeです。3週間ぶりの投稿です。今回もKaggleのTitanicに挑戦しました。

# 変更点
・LabelEncoding
・OneHotEncoding
・SibspとParchの和
・データの標準化
・モデルの追加

#データ準備
前回のデータ準備のプログラムは以下のとおりです。
```Python
import pandas as pd
import numpy as np

# データの読み込み
m_train = pd.read_csv('train.csv')
m_test = pd.read_csv('test.csv')

```

次にヒストグラムで訓練データの確認を行います。
```Python
m_train.hist(figsize = (12,12))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226429/e418267a-925e-fce0-632b-fd7903d43feb.png)
上記の結果を見ると、20~40代の人とチケットのクラスが3の人が多いことが分かります。

欠損値補間を行います。
```Python
#欠損値補完 AgeとEmbarked, Fareのみ
m_train["Age"]=m_train["Age"].fillna((m_train["Age"].median())) #ageを中央値に補填
m_train["Embarked"] = m_train["Embarked"].fillna("S")
m_test["Age"]=m_test["Age"].fillna((m_train["Age"].median())) #ageを中央値に補填
m_test["Fare"]=m_test["Fare"].fillna((m_train["Fare"].median())) #fareを中央値に補填
```


# データ前処理
## LabelEncoding
LabelEncodingは質的関数を数値化することができます。例えば文字列や文字を変換することができます。
```Python
#敬称(Mr. Mrs. Miss.など)を抽出する
m_train['Title'] = m_train['Name'].str.extract(r'([A-Za-z]+)\.', expand=False)
m_test['Title'] = m_test['Name'].str.extract(r'([A-Za-z]+)\.', expand=False)

#敬称を抽出したTitleをラベルエンコーディングする
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
le.fit(m_train['Title'])
m_train['Title'] = le.transform(m_train['Title'])

le.fit(m_test['Title'])
m_test['Title'] = le.transform(m_test['Title'])
```

Titleの元データは以下です。
```Python
m_train['Title'] 
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226429/e8f579c7-ed8d-47a4-c903-def5addab3e6.png)

## OneHotEncoding
ダミー変数は、質的データを0か1で表現することができます。例えば性別や住んでいる地域、血液型などの質的特徴が用いられます。今回はSexとEnbarkedでOneHotベクトルを求めます。


```Python
from sklearn.preprocessing import OneHotEncoder
#Sexをワンホットベクトル化
enc_train = OneHotEncoder(handle_unknown='ignore') 
enc_test = OneHotEncoder(handle_unknown='ignore') 
enc_train.fit(m_train[['Sex']])
enc_test.fit(m_test[['Sex']])
#変換したデータをtrain_regionとtest_regionというDataFrameオブジェクトに格納
train_Sex = pd.DataFrame(enc_train.transform(m_train[['Sex']]).toarray(), columns=enc_train.get_feature_names_out(['Sex'])) 
test_Sex = pd.DataFrame(enc_test.transform(m_test[['Sex']]).toarray(), columns=enc_test.get_feature_names_out(['Sex']))
#
```

上記２つの前処理した結果は以下のとおりです。
```Python
#新しい列として変換後のデータを追加し、それぞれtrain_dataとtest_dataに再代入し
m_train = pd.concat([m_train, train_Sex], axis=1)
m_test = pd.concat([m_test, test_Sex], axis=1)
m_train = pd.concat([m_train, train_Embarked], axis=1)
m_test = pd.concat([m_test, test_Embarked], axis=1)
m_train
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226429/6c3c24bf-2c2a-11dc-7884-8e0ab20a9a16.png)

## SibspとParchの和
搭乗者の人間関係を簡潔にするために、SibspとParchの和を求めます。
```Pythobn
#SibspとParchを足し合わせる
m_train["FamilyNum"] = m_train["SibSp"] + m_train["Parch"]
m_test["FamilyNum"] = m_test["SibSp"] + m_test["Parch"]
```
## データの標準化
さらに、データの数値の範囲を狭めるために、平均が0,分散が1になるように標準化を行います。今回はAgeとFare,Title,FamilyNumを使います。
```Python
from sklearn.preprocessing import StandardScaler

#標準化を行う
standard = StandardScaler()
train_std = pd.DataFrame(standard.fit_transform(m_train.loc[:, ['Age', 'Fare','Title','FamilyNum']]), columns=['Age', 'Fare','Title','FamilyNum'])
test_std = pd.DataFrame(standard.fit_transform(m_test.loc[:, ['Age', 'Fare','Title','FamilyNum']]), columns=['Age', 'Fare','Title','FamilyNum'])

# Age を標準化
m_train['Age_std'] = train_std['Age']
m_test['Age_std'] = test_std['Age']

# Fare を標準化
m_train['Fare_std'] = train_std['Fare']
m_test['Fare_std'] = test_std['Fare']

# Title を標準化
m_train['Title_std'] = train_std['Title']
m_test['Title_std'] = test_std['Title']

# FamilyNum を標準化
m_train['FamilyNum_std'] = train_std['FamilyNum']
m_test['FamilyNum_std'] = test_std['FamilyNum']
```

以上のようにデータの前処理を行ったので、。前処理結果は以下のとおりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226429/e82ab8c5-73f5-732f-3d53-073dbcce2423.png)

# モデルの追加
データの前処理が終わったので、モデル構築して精度の比較を行います。
今回使うモデルは以下のとおりです。
・決定木
・ランダムフォレスト
・ロジスティック回帰
・線形サポートベクターマシン
・XGBoost分類モデル

## データの分割
まず、データの分割を行います。学習をする際にはテストデータと学習データに分割をしなければなりません。
```Python
#テストデータと訓練データを分ける
from sklearn.model_selection import train_test_split

seed=0
#データ処理
X = m_train.drop(['Survived'], axis=1)
X = m_train[["Pclass", "Sex_female","Sex_male","Embarked_C","Embarked_Q","Embarked_S","Age_std","Fare_std","Title_std","FamilyNum_std"]].astype(float)
y = m_train[["Survived"]]

from sklearn.model_selection import train_test_split

# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,train_size=0.7, random_state=10,shuffle=True) 
```

## 学習モデルの選定
次にそれぞれの学習モデルを用いて精度を確認します。

### 決定木モデル
決定木モデルは、分類と回帰でクラスをツリー上で分類する手法です。
```Python
# 決定木モデルのライブラリのインポート
from sklearn.tree import DecisionTreeClassifier

# 決定木モデルの作成
dtc = DecisionTreeClassifier(random_state=10,max_depth=5)

# 学習
dtc.fit(X_train, y_train)

# 予測
y_pred = dtc.predict(X_test)

# 精度の計算
from sklearn.metrics import accuracy_score
score = accuracy_score(y_test, y_pred)
score```

正解率は<b>0.8435754189944135</b>です。

### ランダムフォレスト
ランダムフォレストは決定木とアンサンブル学習を組み合わせた分類モデルのアルゴリズムです。
```Python
# ランダムフォレストのライブラリのインポート
from sklearn.ensemble import RandomForestClassifier

# モデルの作成と評価(RandomForestClassifier)
rfc = RandomForestClassifier(criterion = 'gini',n_estimators=14,random_state=10)
rfc.fit(X_train, y_train)
y_pred = rfc.predict(X_test)
score = accuracy_score(y_test, y_pred)
score
```
正解率は<b>0.8491620111731844</b>です。

### ロジスティック回帰
ロジスティック回帰は様々な説明変数から2つの結果が起きる確率を予測することができます。
```Python
# ロジスティック回帰のライブラリのインポート
from sklearn.linear_model import LogisticRegression

# ロジスティック回帰を学習
clf = LogisticRegression(C=100,random_state=10)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
score = accuracy_score(y_test, y_pred)
score
```
正解率は<b>0.8156424581005587</b>です。

### 線形サポートベクターマシン
```Python
# 線形サポートベクターマシンのライブラリのインポート
from sklearn.svm import LinearSVC

#線形SVCを学習
svc = LinearSVC(random_state=1)
svc.fit(X_train, y_train)
score = svc.score(X_test, y_test)
score
```
正解率は<b>0.8156424581005587</b>です。

### XGBoost
XGBoostは浅い決定木を複数作ってアンサンブル学習を行うアルゴリズムです。
```Python
!pip install xgboost

#XGBoostのライブラリのインポート
import xgboost as xgb
from xgboost import XGBClassifier

# XGBoost分類モデルのインスタンス
model_XGB = XGBClassifier(booster="gbtree",             # ブースター種類（ツリーモデル：gbtree or dart, 線形モデル：gblinear)
                          learning_rate=1,              # 過学習防止を目的とした学習率
                          min_split_loss=0,             # 決定木の葉ノード追加に伴う損失減少の下限値
                          max_depth=8,                  # 決定木の深さの最大値
                          min_child_weight=1,           # 決定木の葉に必要な重みの下限
                          subsample=1,                  # 各決定木においてランダム抽出されるサンプル割合
                          sampling_method="uniform",    # サンプリング方法
                          colsample_bytree=1,           # 各決定木でランダムに設定される説明変数の割合
                          colsample_bylevel=1,          # 決定木が深さ単位で分割される際に利用する説明変数の割合
                          reg_lambda=1,                 # L2正則化のペナルティ項
                          reg_alpha=0,                  # L1正則化のペナルティ項
                          tree_method="auto",           # ツリー構造アルゴリズム
                          process_type="default",       # 実行するブースティングプロセス
                          grow_policy="depthwise",      # 新しい葉ノードを木に追加する際の制御ポリシー
                          max_leaves=0,                 # 追加する葉ノードの最大数
                          objective="reg:squarederror", # 学習プロセスで最小化を目指す損失関数
                          num_round=10,                  # ブースティング回数(=作成する決定木の本数)
                         )


# モデル学習
model_XGB.fit(X_train, y_train)
y_pred = model_XGB.predict(X_test)
score = accuracy_score(y_test, y_pred)
score
```
正解率は<b>0.776536312849162</b>です。

以上のモデルを比較した結果、ランダムフォレストの正解率が高いことが分かりました。よって、ランダムフォレストを採択します。

## モデルの実行
全ての精度を求めたので、モデルの実行作業を行い、目的変数を求めます。
```Python
#前処理した説明変数を用いる。またデータの内容は以下のとおりです。
X_test = m_test[["Pclass", "Sex_female","Sex_male","Embarked_C","Embarked_Q","Embarked_S","Age_std","Fare_std","Title_std","FamilyNum_std"]].astype(float)
X_test
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226429/ce51ba13-c668-aefa-f345-4fb9cd69c6b6.png)

次にランダムフォレストで搭乗者の生死を予測します。
```Python
# ランダムフォレストで予測
y_pred_submit = rfc.predict(X_test)
y_pred_submit
```
最後にcsvファイルに書き込みをして、提出をします。
```Python
submit_sample = pd.read_csv('submit.csv')
submit = pd.DataFrame(data = {'PassengerId': submit_sample['PassengerId'], 'Survived': y_pred_submit})
submit.to_csv('submit_titanic.csv', index=False)
```
提出した結果、スコアは<b>0.77272</b>である。前回よりは若干伸びたが、まだまだ調整する必要があります。さらに、k分割交差検証やパラメータ調整、正規化など多方面で処理する必要があることが分かりました。

# まとめ
このようにKaggleを用いてデータの予測を行いました。今回得られた精度は前回より若干伸びたが、様々なデータの前処理方法や分析手法など理解できたのではないかと考えます。さらに、このTitanicコンペの修正も行うが、加えて回帰問題を使うHouse Pricesにも挑戦します。