前回の反省
Kernelを眺めていると
すばらしいまとめがありました。
https://www.kaggle.com/pliptor/how-am-i-doing-with-my-score
によると僕が前回までに出した0.75598 というスコアは
全員死亡としてsubmit:0.62679
Sex, Embark, Pclass だけ考慮したら:0.76555
というわけで、僕のスコアは余計な処理をした割には凡人スコアでした。
Embark を使わなかったけど・・・
だいたい0.8が専門家との分かれ目という感じです。(0.8から何が書いてあるのかわからない)
前回断念した、名前の関連性(ファミリーか、親子か?)みたいなこともやってる方がいて、いい結果が出たそうです。
というわけで、
みんなのいいところをパクろう!
Kernelでたくさんのいいね!をもらっている以下のkernelを写経します。
https://www.kaggle.com/startupsci/titanic-data-science-solutions
このkernelは、Age FamilySize などのデータを徹底的に、カテゴリ化して、次元削減?をやっています。
さらに、このkernelは、最後に様々なモデルを使って予想しています。(XGBoost にぶっこんだだけの僕が異常)
Logistic Regression
KNN or k-Nearest Neighbors
Support Vector Machines
Naive Bayes classifier
Decision Tree
Random Forrest
Perceptron
Artificial neural network
RVM or Relevance Vector Machine
このkernelの筆者は訓練データへの予測精度から、Random Forestを採用して結果を予測しています。
機械学習の世界においては、訓練データを過学習してしまうと、汎用性を失ってしまうので、かならずテストデータとの比較(Validation)が必要となります。
Validation
前回の僕の解析で導き出した、少なくとも、牧師全滅説と、子供が死んだ団体全滅説が合っているモデルを使おうと思います。
写経して、最後のpredict部分をかなり触ります。
df_train = pd.read_csv('./train.csv').replace("male",0).replace("female",1)
df_test = pd.read_csv('./test.csv').replace("male",0).replace("female",1)
sep_forward = df_train["Name"].str.split(",",expand=True)
sep_backward = sep_forward[1].str.split(".",expand=True)
job = sep_backward[0].str.replace(" ","")
df_train["job"] = job
sep_forward = df_test["Name"].str.split(",",expand=True)
sep_backward = sep_forward[1].str.split(".",expand=True)
job2 = sep_backward[0].str.replace(" ","")
df_test["job"] = job2
# 16 years old peoples should be child
df_train.loc[df_train["Age"] < 16, ["job"] ] = "Child"
#display(df_train[df_train["Age"]< 18])
df_test.loc[df_test["Age"] < 16, ["job"] ] = "Child"
#display(df_test[df_test["Age"]< 18])
zennmetu_ticket = df_train[(df_train["job"]=="Child") & (df_train["Survived"]== 0)]["Ticket"].unique().tolist()
for izennmetu in zennmetu_ticket:
df_test.loc[df_test["Ticket"] == izennmetu, "Survived"] = 0
df_test.loc[df_test["job"]=="Rev", "Survived"] = 0
val_index = df_test[df_test["Survived"]== 0 ].index
display(df_test[df_test["Survived"]== 0 ])
各出力を目で見て確認します。
display("1",Y_pred_rf[[val_index]])
display("2",Y_pred_DT[[val_index]])
display("3",Y_pred_KNN[[val_index]])
display("4",Y_pred_LS[[val_index]])
display("5",Y_pred_PRE[[val_index]])
display("6",Y_pred_SGD[[val_index]])
display("7",Y_pred_SVC[[val_index]])
display("8",Y_pred_gauss[[val_index]])
最も僕が確信を持っている、「子供が死んでる団体は全滅説」と、「牧師全滅説」を予測していたのは、Perceptron でした。この結果をsubmitしたところ、結果が悪くなりました。orz
素直にRandom Forestを使ったところ、0.77511でした。うーん。
傾向的に、Random Forestの結果が0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 だったので、
80番の実は小家族の子供を生きていると判断(おそらくテストデータで別の子供が死亡)
141の女性
の死亡を予測するのが難しいのかなぁと思います。
推理から求まった結果を上書き
Random Forestの結果に、子供が死んでる家族全滅説と、牧師全滅説を上書きしてsubmitしたところ、0.78468までスコアが伸びました。
どこかのkernelにも書かれてましたが、trainに対してtestの方が明らかに死亡率が高いようです。
というわけで、Random Forestが生きていると判断した部分に対して死亡を提案したので、方向性としては間違ってなかったのでしょう。
Y_pred_rf[[val_index]] = 0
submission = pd.DataFrame({
"PassengerId": test_df["PassengerId"],
"Survived": Y_pred_rf
})
submission.to_csv('submission20181016_rf_2.csv', index=False)
最後に
次は、僕が論理的に導き出したtest中に含まれる生存データもtraiに混ぜてみようかと思います。
あと、「子供が死んでる家族全滅説」となりうるようなパラメータの探索と、家族関係・団体の関係のようなものをするかなぁ?