kaggleによるタイタニック生存者予測第二弾。
今回は積み上げヒストグラム生成、欠損値処理、k-fold法による正答率計算などを追加で行いました。
前回記事

前回はkaggleアカウントを作成し、簡単な機械学習モデルを作成して提出するまでを行いました。
今回はそこから少し改良を加えていきます。
データの可視化
まずは前回も行った性別と乗客の階級の可視化から。
特徴量1:性別(Sex)
1 2 3 |
import seaborn as sns #性別と生存率 sns.factorplot(data=train,x="Sex",y="Survived", kind="bar") |
seabornのfactorplotで、性別の生存率を1行で可視化することができます。
特徴量2:乗客の階級(Pclass)
1 2 |
#乗客の階級と生存率 sns.factorplot(data=train,x="Pclass",y="Survived", kind="bar") |
これらの特徴量は今回も使用します。
欠損値処理、特徴量追加
ここからさらに、特徴量を増やしていきます。
特徴量3:乗船場所(Embarked)
1 2 |
#乗船場所の種類と生存率 sns.factorplot(data=train,x="Embarked",y="Survived", kind="bar") |
グラフを見ると、乗船位置によって生存率にばらつきがあることが分かります。
しかし、このデータは一部欠損しているため、そのままでは学習させることができません。
1 2 |
#乗船場所の種類と乗船者数 sns.countplot(data=train, x="Embarked") |
場所別の乗船者数をみると、データの最頻値は”S”であることが分かります。
なので、欠損している値はとりあえず”S”で埋めることにしました。
1 2 |
#Embarkedの欠損値を最頻値であるSで埋める。 train.fillna({"Embarked": "S"}, inplace = True) #inplace=True:オブジェクト自体を変更 |
特徴量4:年齢
1 |
train["Age"].hist(bins=40) |
まずは年齢のばらつきをヒストグラムで確認。
1 2 3 4 5 6 7 8 9 10 |
#生存者リスト、死亡者リスト生成 survived_list = train["Survived"] == 1 dead_list = train["Survived"] == 0 import matplotlib.pyplot as plt #積み上げヒストグラム plt.xticks([0,6,10,20,30,40,50,60,70,80]) # 目盛りを変更 plt.hist((train[survived_list]["Age"], train[dead_list]["Age"]), histtype="barstacked", bins=40, label=("survived", "dead")) plt.legend() plt.show() |
次に、ヒストグラムを生存者と死亡者に色分けして表示してみました。
よく見ると、6歳以下の生存率が比較的高いことが分かります。
1 2 3 4 5 6 7 |
#Ageの欠損値を20で埋める。 train.fillna({"Age": 20}, inplace = True) test.fillna({"Age": 20}, inplace = True) #child 列追加 6歳以下を子供に設定 train["Child"] = train["Age"] <= 6 #pythonでは、true/false は 1/0 test["Child"] = test["Age"] <= 6 train.head() |
今回は、新たな特徴量として変数”Child”を設定し、6歳以下かどうかで分類しました。
年齢が欠損しているデータについては、20歳(“Child”=false)として設定しています。
特徴量5:料金
1 2 3 4 5 |
# 金額ヒストグラム plt.xticks([0,50,100,200,300,400,500]) # 目盛りを変更 plt.hist((train[survived_list]['Fare'], train[dead_list]['Fare']), histtype='barstacked', bins=40, label=('survived', 'dead')) plt.legend() plt.show() |
年齢と同様、船の乗船料金もヒストグラムで表示しました。料金が高いほど生存率が高そうです。
このデータから、料金が50以上で分類する新たな変数”Rich”を追加しました。
1 2 3 4 5 6 7 |
#Fareの欠損値を0で埋める。 train.fillna({"Fare": 0}, inplace = True) test.fillna({"Fare": 0}, inplace = True) #50以上Richに設定。 train["Rich"] = train["Fare"] >= 50 test["Rich"] = test["Fare"] >= 50 train.head() |
データ整形
前回と同様、判定に用いない不要な変数は取り除きます。
また、性別(Sex)と乗船地(Embarked)のデータは数値に変換しました。
1 2 3 4 5 6 7 8 9 10 11 |
# 不必要な列を消去する train2 = train.drop(["PassengerId","Name","Age","SibSp","Parch","Ticket","Fare","Cabin"], axis=1) test2 = test.drop(["PassengerId","Name","Age","SibSp","Parch","Ticket","Fare","Cabin"], axis=1) # 性別を数値に変換 train2 = train2.replace("male",0).replace("female",1) test2 = test2.replace("male",0).replace("female",1) # 乗船地を数値に変換 train2 = train2.replace("S",0).replace("Q",1).replace("C",2) test2 = test2.replace("S",0).replace("Q",1).replace("C",2) train2.head() |
結果は以下の通り。
Pclass, Sex, Embarked, Chile, Rich 5つの特徴量を用いて予測を行っていきます。
ランダムフォレストによる予測→提出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import KFold from sklearn.model_selection import cross_val_score forest = RandomForestClassifier(n_estimators = 100) #n_estimators:決定木の本数 train_x = train2[["Pclass", "Sex", "Embarked", "Child", "Rich"]] #特徴量 train_y = train2["Survived"] # 正解データ # 学習 forest = forest.fit(train_x, train_y) #訓練データの判定率をk-fold法で求める kfold = KFold(n_splits=10, random_state=42) result = cross_val_score(forest, train_x, train_y, cv = kfold, scoring = "accuracy") print(result.mean()) #.mean():平均 |
ランダムフォレストを用いて学習モデルの作成を行います。
学習モデル作成後、提出を行う前に、k-fold法で訓練データでの正答率を求めてみました。
訓練データの正答率は80%ほどでした。
まずまず良さそうなので、これを用いてテストデータの判定を行い、提出します。
1 2 3 4 5 6 7 8 9 |
test_x = test2[["Pclass", "Sex", "Embarked", "Child", "Rich"]] # 予測 pred = forest.predict(test_x) result = pd.DataFrame({ "PassengerID" : test["PassengerId"], "Survived" : pred }) print(result) result.to_csv("result.csv", index=False) |
提出した結果↓
0.76555→0.77033
と、ほんの少しだけ精度が向上しました。
上位58%ほどなので、まだまだポンコツです。
おわりに
欠損値のあるデータを上手く加工して特徴量に加えることで、少しだけ精度を向上させることができました。
今回ヒストグラムからあたりをつけてイイ感じの新たな特徴量を生成する、ということをしましたが、データ数が少ないため、あまり良い方法ではないかもしれません。(訓練データで見られた傾向が、必ずしもテストデータでも見られるとは限らないため)
まだ改善の余地があるとすれば、機械学習モデルの生成方法がランダムフォレスト以外にも色々あるので、次回はそれを試してみたいなと思います。
参考にしたサイト

