{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nimport os\nprint(os.listdir(\"../input\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","collapsed":true,"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":false},"cell_type":"markdown","source":"# 前処理(pre-preccessing)\n## まずはデータを確認する\n### pandasを使ってCSVデータを読み込む"},{"metadata":{"trusted":true,"_uuid":"d675f94966535888cc4cee874c0279d056746993"},"cell_type":"code","source":"train_data = pd.read_csv('../input/train.csv') #訓練用データ\ntest_data = pd.read_csv('../input/test.csv') #テスト用データ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5c633a5ec85dc37edbfc1358f8bcea200ad609f5"},"cell_type":"code","source":"print(train_data.columns)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"40f0b382aa097bc698cbcca200669d2d98c31911"},"cell_type":"code","source":"train_data.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"40e4bbfcd1a633fb65ec04251fd8384bcccf7096"},"cell_type":"code","source":"print(test_data.columns)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"6eb9f8eecf1a2c503e0bdac2cb88e5245a7fb22c"},"cell_type":"code","source":"test_data.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d0a92057cb6f50b7dd2c5cf61475a5a9800152c0"},"cell_type":"markdown","source":"訓練用データの方には'Survived'というカラムがあるのに対し、テスト用データには'Survived'が無い。\n'Survived'というカラムは「生存していれば1,死亡していれば0」という今回求めたい「正解ラベル」であるため、学習用データにのみ含まれている。\n\n言い換えれば、このカーネルの目的は、\n\n> \"訓練用データ\"を使用してモデルを学習させ、そのモデルを使用して\"テストデータ\"の'Survived'を予測して提出すること\n\nであると云える。\n"},{"metadata":{"_uuid":"b2a4e502a7c3da1d55f2880662c53b76c33fc44a"},"cell_type":"markdown","source":"### 欠損値を確認する\n\n機械学習用のデータを用意するにあたって、すべての行のすべてのカラムの値が埋まっているデータを用意できることの方が稀であり、一部データが欠損していることが普通である。よって、今回のデータについても欠損値の有無と、どのカラムに欠損値があるかを確認する。"},{"metadata":{"trusted":true,"_uuid":"42cbc2732e925924105700aa8720545e09319dfe"},"cell_type":"code","source":"train_data.isnull().any()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7d07f5e643b073886f665fee70bfe9e7e03a0c5f"},"cell_type":"markdown","source":"訓練用データについては、'Age','Cabin','Embarked'について欠損があることが分かる。"},{"metadata":{"trusted":true,"_uuid":"ade491565885862f76f4fdb977df6e344284df2d"},"cell_type":"code","source":"test_data.isnull().any()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0a5cfc9e563985dd5dec41113a581ac68e13f4e9"},"cell_type":"markdown","source":"テスト用データについては、'Age','Fare','Cabin'に欠損があることが分かる。\n\n*これらの欠損値を補填を前処理で行わなければならないことが判明した。*"},{"metadata":{"trusted":true,"_uuid":"2e77f583b8af76214db2596fa71d06baec2229cd"},"cell_type":"markdown","source":"## 欠損値を補填する\n### Age\n\nここでは単純に、全Ageの平均値で補填することとする。\n尚、他に考えられる手段としては、例えばNameから肩書(Mr,MissMrsなど)ごとの平均値を割り当てるなどの方法がある。\n\n※例えば、Mrs(既婚女性)の方がMiss(子供も含む未婚女性)より平均年齢が高いことが予想できる\n"},{"metadata":{"trusted":true,"_uuid":"b919383c9fa551509d6cd40be1b22fece27847ef"},"cell_type":"code","source":"age_mean = pd.concat([train_data['Age'],test_data['Age']]).mean() #訓練用データとテスト用データの'Age'を結合して平均を取る\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4d6e63aaf644f2afc066be165cd586ab40d72533"},"cell_type":"code","source":"train_data.fillna({'Age':age_mean},inplace=True)\ntrain_data.isnull().any() #訓練用データの'Age'に欠損値が無くなったことを確認","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3d415b2b16ab426475f6f45bdc62060539320152"},"cell_type":"code","source":"test_data.fillna({'Age':age_mean}, inplace=True)\ntest_data.isnull().any() #テスト用データの'Age'に欠損値が無くなったことを確認","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"dbf5ad01f7473c6483519c3b56da4fe936e279e1"},"cell_type":"markdown","source":"### Fare\nFareも同じく平均値で補填することとする。\n\n他の手段としては、PclassやCabin、Embarkedごとの平均値を出すなど手段が考えられる。"},{"metadata":{"trusted":true,"_uuid":"1d6a022d70f1c2512e59dea7336794f8559111d8"},"cell_type":"code","source":"fare_mean = pd.concat([train_data['Fare'],test_data['Fare']]).mean()\ntest_data.fillna({'Fare':fare_mean},inplace=True) #Fareが欠落していたのはテスト用データだけ\ntest_data.isnull().any()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d0756f272d18780c58fdd03d8a1537c0744b67c5"},"cell_type":"markdown","source":"### Cabin\nCabinは数値ではないため、平均を使って補填することができない。\n\nそこで全データの最頻値で補填することとする。\n\n他の手段としては、pClassごとの最頻値で補填するなどが考えられる。\n\nまた、敢えて補填しない('unkown'として取り扱う)という手段を有力である。"},{"metadata":{"trusted":true,"_uuid":"432f2a02cb62d90695eae9e8c77f8beb79b06b5f"},"cell_type":"code","source":"pd.concat([train_data['Cabin'],test_data['Cabin']]).value_counts()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3a927574c5dd644a0baa62f58e85b64f82016a15"},"cell_type":"markdown","source":"'C23 C25 C27'が最頻値のようなのでそれで補填する"},{"metadata":{"trusted":true,"_uuid":"cab69980902c3b6cfe35309abd4df088091a949f"},"cell_type":"code","source":"most_existing_cabin = pd.concat([train_data['Cabin'],test_data['Cabin']]).value_counts().index[0]\ntrain_data.fillna({'Cabin':most_existing_cabin},inplace=True) \ntrain_data.isnull().any()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"954f9305560b2412170acc78ead7da1bb6be250b"},"cell_type":"code","source":"test_data.fillna({'Cabin':most_existing_cabin},inplace=True) \ntest_data.isnull().any()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cd4b171540100b5ed57d810f316a339d89a17c64"},"cell_type":"markdown","source":"### Embarked\n\nEmbarkedも同じく最頻値を使って補填することとする。"},{"metadata":{"trusted":true,"_uuid":"188ced0e422ac21aeac24a3e5bd4a18512bfc111"},"cell_type":"code","source":"pd.concat([train_data['Embarked'],test_data['Embarked']]).value_counts()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f5e33df25245460e1c872c445c0060aec30d8c98"},"cell_type":"markdown","source":"'S'が最頻のようなので、'S'を補填する"},{"metadata":{"trusted":true,"_uuid":"0e6fe7caedda1b5dc81f1d5f46affe163b3a1f18"},"cell_type":"code","source":"most_existing_embarked = pd.concat([train_data['Embarked'],test_data['Embarked']]).value_counts().index[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"34379c714c19a4ec9a72e673ebf2145de89c797b"},"cell_type":"code","source":"train_data.fillna({'Embarked':most_existing_embarked},inplace=True) #Embarkedが欠損しているのは訓練用データのみ\ntrain_data.isnull().any()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"05de1a9ce9184c698121429187eb2ecb853f5d3f"},"cell_type":"markdown","source":"念のため、訓練用/テスト用双方のデータに欠損が無いことを再度確認する"},{"metadata":{"trusted":true,"_uuid":"b492dc0c1539b87078520555c7e6d6e2d3afaabb"},"cell_type":"code","source":"train_data.isnull().any()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c481e5aaa90b92a21011e83ad6450be55bb5b8c8"},"cell_type":"code","source":"test_data.isnull().any()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"75e3f25b8d5d906ee78d571426310b63535705ff"},"cell_type":"markdown","source":"## 学習・予測用のデータを剪定する\n用意されたデータすべてが学習や予測に使いやすい形であるとは限らず、また、予測したい結果(ここでは生死)に結び付いているとも限らない。\nよって、全データの中から学習・予測に使用するデータを剪定する。\n\nこの工程は何度かの試行錯誤により改善を繰り返すべきだが、ここではあくまでサンプルとして、比較的取り扱いやすい\n\n> 'Pclass','Sex','Age','SibSp','Parch','Fare'\n\nのみを取り扱い、他は切り捨てることとする。"},{"metadata":{"trusted":true,"_uuid":"798a6c9038262b61f98919654acb2541c87cd6ff"},"cell_type":"code","source":"train_X = train_data[['Pclass','Sex','Age','SibSp','Parch','Fare']] #全訓練データの中から対象のカラムのみ抜き出す\ntrain_X.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b0e7bfe4840b452beca5643e090ea5fcba8d7c1c"},"cell_type":"code","source":"train_y = train_data[['Survived']] #正解ラベルである'Survived'も切り出しておく\ntrain_y.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"99522962b267a559ec632a0a1b2686b53b064f69"},"cell_type":"code","source":"test_X = test_data[['Pclass','Sex','Age','SibSp','Parch','Fare']] #全テストデータの中から対象のカラムのみ抜き出す\ntest_X.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3eb4a14de6448eadad45b93ea19bfa994314d693"},"cell_type":"markdown","source":"## カテゴリ変数からダミー変数への変換\n\n剪定したカラムのうち、'Sex'のみが文字列であり、他は数値（intもしくはfloat）である。\n機械学習のモデルでは数値のみを扱えるため、カラム'Sex'をなんらかの手段で数値に変換しなければならない。"},{"metadata":{"trusted":true,"_uuid":"02c19f3d6182f07de794e95d2a74fc8ad50a325d"},"cell_type":"code","source":"pd.concat([train_X['Sex'],test_X['Sex']]).value_counts() #'Sex'のデータの中身を確認","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"32b79e2193efcf0211b06cee35b9d61cd5209290"},"cell_type":"markdown","source":"カラム'Sex'には欠損が無く、取り得る値が、\n* male\n* female\nの二値である。\n\nこのように、ごく少数の値のみを取り得る変数を「カテゴリ変数」と呼ぶ。\n\n「カテゴリ変数」は「ダミー変数」へ変換することにより数値に変換できる。"},{"metadata":{"trusted":true,"_uuid":"3af59c60549d395ea397d696bf1e7b4b35f78804"},"cell_type":"code","source":"pd.get_dummies(train_X['Sex']).head() #カラム'Sex'のダミー変数を取得して先頭を表示","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"db8ff8903e797fe88b093e4cd8df5db9537c3505"},"cell_type":"markdown","source":"ただし、作成されたダミー変数は完全に相互従属の関係である。\n例えば、\n\n> femaleが0であればmaleは必ず1である\n\n> maleが0であればfemaleは必ず1である\n\nという関係にあるため、femaleかmaleのどちらかがあれば良い。\n\nこういった相互従属の変数を訓練/テストデータに残しておくと、\n\n* 過学習のリスクが高まる\n* 余計なリソースを使ってしまう\n\nといった問題があるため、どちらか一方を残した方が望ましい。"},{"metadata":{"trusted":true,"_uuid":"6aebc100d7d0b392fa5fad510e676ce1971d5edb"},"cell_type":"code","source":"pd.get_dummies(train_X['Sex'],drop_first=True).head() #drop_first=Trueを指定することにより先頭のカラムを落とす","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"02a7d914bcb611f932ab150439d1896fdd6aa6d1"},"cell_type":"markdown","source":"よって、上記で確認したdrop_firstしたダミーを変数を元のカラム'Sex'の代わりに代入する"},{"metadata":{"trusted":true,"_uuid":"9840a9397aad8d45372fee5f926bba1621e63651"},"cell_type":"code","source":"train_X = train_X.join(pd.get_dummies(train_X['Sex'],drop_first=True)) #まずダミー変数を結合する\ntrain_X.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"68ee93f7f7205e434e218de9b7032e46c8d735c8"},"cell_type":"code","source":"train_X.drop(['Sex'], axis=1, inplace=True) #元のカラムである'Sex'は削除する\ntrain_X.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9fa4031b5e2b1ef28869d8fbd6736deaeb1d231b"},"cell_type":"code","source":"# テストデータについても同じことを行う（ワンライナー）\ntest_X = test_X.join(pd.get_dummies(test_X['Sex'],drop_first=True)).drop(['Sex'],axis=1)\ntest_X.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"15f9b1aafaa5565a0e2fa94101f07daeb97faf86"},"cell_type":"markdown","source":"この変換により、訓練/テストで使用する値がすべて数値(intもしくはfloat)となった。\n"},{"metadata":{"_uuid":"606a5b2ff68fd0c5b216327fba343ac098a7f450"},"cell_type":"markdown","source":"## 正解ラベルとの相関を確認する\n\n妥当な前処理が出来ているかどうかの判断の一助として、正解ラベルである'Survived'と前処理したデータセットの各カラムとの相関を可視化して確認する。\n\n### 可視化用ライブラリのimport"},{"metadata":{"trusted":true,"_uuid":"97fb3f82160bcae9dd676fdcb72cef85613c430d"},"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport seaborn as sns\nimport warnings\nwarnings.filterwarnings('ignore')\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e86d471dce0a1a3ad0a9f167bc18a863f644fce9"},"cell_type":"markdown","source":"### カラム同士の相関係数を求めてヒートマップで可視化する"},{"metadata":{"trusted":true,"_uuid":"ada66893c56017710a09e97a91fa1a1fac67ca30"},"cell_type":"code","source":"sns.heatmap(train_y.join(train_X).corr(),annot=True,cmap='RdYlGn',linewidths=0.2)\nfig=plt.gcf()\nfig.set_size_inches(20,12)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7c15ebeaad2a9126f1edb0a35451c4dd1d6e2099"},"cell_type":"markdown","source":"まず、Survivedとの相関の列（＝左端の列に）着目すると、\n\n* male(男性かどうか)に最も高い負の相関がある => 女性の方が生き残りやすい\n* Pclass(船室の等級。1等級が最も高級で3等級が手ごろな値段。)に次に高い負の相関がある　=> 1等級の船室の方が生き残りやすく、3等級の船室は生き残りにくい\n* Fare(料金)に正の相関がある　=> 料金が高いほど生き残りやすい\n* Age(年齢)やSibSp(配偶者/兄弟の数)、Parch(親/子供の数)にはそれほど強い相関は無い\n\nといった傾向を読み取ることができる。（つまり、お金持ちの女性が最も生き残りやすい）\n\nただし、Pclass(船室の等級)とFare(料金)の間にもやや強すぎる相関があり、『船室の等級が上がるにつれ料金が上がる』という当たり前の性質がデータセットに含まれてしまっている点がやや不満である。\n\n本来はこの結果を見て前処理の修正（剪定は妥当か？他にダミー変数かすべき属性は無いか？他に相関の強い属性を作ることはできないか？など）を検討するのだが、今回はサンプルであるためこのまま進めることとする。"},{"metadata":{"_uuid":"baf8b0e5435e4fadea1fe10781b27abfb9489272"},"cell_type":"markdown","source":"## カテゴリ変数と正解ラベルとの分布を見る\n\n'male'や'Pclass'のようなカテゴリ変数については、正解ラベルとの分布を見ることによって「どのカテゴリがどの程度結果に影響を与えているか」を確認することができる。\n\n### male"},{"metadata":{"trusted":true,"_uuid":"69426fcf57027741f843a4eaca73f0bca548015b"},"cell_type":"code","source":"g = sns.factorplot(x=\"male\", y=\"Survived\",  data=train_y.join(train_X),size=6, kind=\"bar\", palette=\"muted\")\ng.despine(left=True)\ng = g.set_ylabels(\"survival probability\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e8f84f5da40047a5e693b8328a4b2fa44639edf0"},"cell_type":"markdown","source":"この図により、male=0(つまり女性)は70%以上の割合で生き残っているのに対し、男性が生き残っている割合は20%以下であることが分かる。\n\n### Pclass"},{"metadata":{"trusted":true,"_uuid":"62574471f01a16b3bab2719fb76088ee893ccfeb"},"cell_type":"code","source":"g = sns.factorplot(x=\"Pclass\", y=\"Survived\",  data=train_y.join(train_X),size=6, kind=\"bar\", palette=\"muted\")\ng.despine(left=True)\ng = g.set_ylabels(\"survival probability\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e8a0536c5e2fcf30a4348cfe381fa9cbe17bac88"},"cell_type":"markdown","source":"この図により、一等室の乗客が生き残っている割合が60%以上であるのに対し、二等室は50%弱、三等室は25%前後であることが分かる。"},{"metadata":{"_uuid":"53c6bac50bbdbc9e68ade16a308c30a2f1935ffa"},"cell_type":"markdown","source":"   # 学習(training)\n\n前処理については（いくつか課題を抱えているものの）とりあえずは完了したため、いよいよ学習に入る。\n\n一般的に大きな流れとしては、\n\n1.  学習モデルの選定と構築\n1.  ハイパーパラメータの調整\n1.  学習効果の測定\n\nを繰り返し行うのだが、今回はScikit Learnというライブラリを使ってこの流れを一気に行う。"},{"metadata":{"_uuid":"ab40a31681c67ebb13ca52eb1cfa2a359d049bd9"},"cell_type":"markdown","source":"## SVM\n\n今回はサンプルとして、SVM(サポートベクターマシン)という分類モデルを使用してハイパーパラメータの調整と効果の測定を一気に行う。\n"},{"metadata":{"trusted":true,"_uuid":"bade889b02aa6ea0314611289a3907a27ed284aa"},"cell_type":"code","source":"from sklearn.model_selection import GridSearchCV #交差検証法を用いてハイパーパラメータを検証するライブラリ\n\nfrom sklearn.svm import SVC # カーネルを限定しないSVMモデルのライブラリ\n\n# ハイパーパラメータの候補\nparam_grid = {'kernel': ['rbf'], \n                  'gamma': [ 0.001, 0.01, 0.1 ,1],\n                  'C': [1, 10, 100, 1000]}\n\n# GridSearchCVライブラリのインスタンス化\nmodelsvm = GridSearchCV(SVC(random_state=0),param_grid = param_grid, cv=5, scoring=\"accuracy\", n_jobs= 2, verbose = 1)\n\n# すべてのパラメータの組み合わせで交差検証を行い最も優れたパラメータを探し出す（=Grid Search）\nmodelsvm.fit(train_X,train_y)\n\n# 最もスコアが高かったパラメータの組み合わせ\nprint(modelsvm.best_estimator_)\n# 最も高かったスコア\nprint(modelsvm.best_score_)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d1c9c02496a2e3746f76b4b2906191a9c43e5349"},"cell_type":"markdown","source":"Grid Searchによって、　\n\n> C=1000 gamma=0.001\n\nが（param_gridとして挙げた候補の中で）最も交差検証スコアが良いことが判明し、そのスコアは約0.79であることが判明した。\n\n\n本来は\n\n* SVM以外のモデルでも同様の検証を行い、よりスコアの高いモデルを探す\n* ハイパーパラメータの候補のバリエーションを増やす\n* いくつかのスコアが高いモデルを結合させて評価する（アンサンブル学習）\n* そもそも前処理に立ち返り、より高い精度を目指す\n\nといった工程の繰り返しを行うのだが、今回はサンプルということでこのままテストデータを使って結果を予測し、提出することとする。"},{"metadata":{"_uuid":"6cb38aec24842708177b182ba94961d4a68603f5"},"cell_type":"markdown","source":"# 予測(prediction)とKaggleへの結果の提出\n\n先ほど検証したベストパラメータのSVMを使って、テストデータの生き死に('Survived')を予測し、Kaggleに提出する"},{"metadata":{"trusted":true,"_uuid":"fbfe6643999e80e55e62f2f2cc251229b699ddda"},"cell_type":"code","source":"test_y = modelsvm.best_estimator_.predict(test_X) #予測\n\n#提出用データの作成\nsubmission = pd.DataFrame({\n        \"PassengerId\": test_data[\"PassengerId\"],\n        \"Survived\": test_y}) #予測した結果とPassengerIdを結合する\n\n#表示\nprint(submission)\n\n#CSVファイルに出力\nsubmission.to_csv(\"titanic_submission.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"0cb810f474236464a8a0b0bb7efaf0c23bac4107"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}