Kaggle 初挑戦: タイタニック号の生存予測その 3 - ニューラルネットワークによる予測 -
Kaggle: タイタニック号生存予測シリーズ
- その1: データの可視化
- その2: データの補完、加工
- その3: ニューラルネットワークによる予測 <-- この記事
ニューラルネットワークとは
ニューラルネットワークとは、脳神経系をモデルにした情報処理システムのことです。学習能力を持ち、必要とされる機能を、提示されるサンプルに基づき自動形成することができます。文字認識や、音声認識など、コンピュータが苦手とされている処理に対して有効です。
いわゆる人工知能の一つのアプローチです。
実は大学時代 (もう10年前か...)、人工知能の一分野である、強化学習というのを研究していました。
当時は実装が大変で、かなり挫折してました...
それが今は Python という言語に強力なライブラリがあるおかげで、とても簡単に実装できるようになっていました。
Python で作るニューラルネットワークの本「ゼロから作る Deep Learning」を買ったので、
せっかくなのでタイタニック号生存予測をニューラルネットワークでやることにしました。
ゼロから作る Deep Learning
ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装
- 作者: 斎藤康毅
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/09/24
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (13件) を見る
Amazon でも大評判のこの本、読んでみました。
たしかに説明もわかりやすく、かつ Python の実装もちゃんと書かれているので、とても理解しやすいです。
また、素晴らしいのはコードが Github で公開されていることです。
MITライセンスで自由に使えるとのことで、ありがたいです。
今回はこのソースからニューラルネットワークを使わせてもらうことにしました。
データの加工
前回の記事のように、まずはデータを加工します。
前回の記事では試行錯誤しながらデータを加工しているので、これをまとめました。
# coding: utf-8 import pandas as pd """Titanic データの前処理をする 同じディレクトリに train.csv, test.csv を置いて使う。 Available functions: wrangle_data - データを加工する。返り値は train_df, test_df (pandas のデータフレーム) """ def wrangle_data (): # Preprocess training data train_df = pd.read_csv ('train.csv') test_df = pd.read_csv ('test.csv') train_df['Title'] = train_df.Name.str.extract(' ([A-Za-z]+)\.', expand=False) test_df['Title'] = test_df.Name.str.extract(' ([A-Za-z]+)\.', expand=False) # train_df title_list = train_df['Title'].sort_values (inplace=False).unique () pclass_list = train_df['Pclass'].sort_values (inplace=False).unique () for title in title_list: for pclass in pclass_list: guess_df = train_df[(train_df['Title'] == title) & (train_df['Pclass'] == pclass)]['Age'].dropna () train_df.loc[(train_df['Age'].isnull()) & (train_df['Title'] == title) & (train_df['Pclass'] == pclass), 'Age'] = guess_df.median () # test_df title_list_t = test_df['Title'].sort_values (inplace=False).unique () pclass_list_t = test_df['Pclass'].sort_values (inplace=False).unique () for title in title_list_t: for pclass in pclass_list_t: guess_df = test_df[(test_df['Title'] == title) & (test_df['Pclass'] == pclass)]['Age'].dropna () test_df.loc[(test_df['Age'].isnull()) & (test_df['Title'] == title) & (test_df['Pclass'] == pclass), 'Age'] = guess_df.median () # test_df 'Title' == 'Ms' の補完 guess_df = train_df[train_df['Title'] == 'Ms']['Age'].dropna () test_df.loc[test_df['Age'].isnull(), 'Age'] = guess_df.median () # train_df 'Embarked' の補完 freq_port = train_df.Embarked.dropna().mode()[0] train_df['Embarked'] = train_df['Embarked'].fillna (freq_port) # test_df 'Fare' の補完 guess_df = test_df[test_df['Pclass'] == 3].dropna() test_df.loc[test_df['Fare'].isnull(), 'Fare'] = guess_df['Fare'].median() df_list = [train_df, test_df] for df in df_list: df.loc[df['Age'] <= 8, 'Age'] = 0 df.loc[(df['Age'] > 8) & (df['Age'] <= 16), 'Age'] = 1 df.loc[(df['Age'] > 16) & (df['Age'] <= 32), 'Age'] = 2 df.loc[(df['Age'] > 32) & (df['Age'] <= 48), 'Age'] = 3 df.loc[(df['Age'] > 48) & (df['Age'] <= 64), 'Age'] = 4 df.loc[(df['Age'] > 64) & (df['Age'] <= 80), 'Age'] = 5 df['Fellow'] = df['SibSp'] + df['Parch'] df['IsAlone'] = 0 df.loc[df['Fellow'] == 0, 'IsAlone'] = 1 df['Sex'] = df['Sex'].map ({'female': 0, 'male': 1}).astype (int) df['Embarked'] = df['Embarked'].map ({'C': 0, 'Q': 1, 'S': 2}).astype (int) df.loc[df['Fare'] <= 7.91, 'Fare'] = 0 df.loc[(df['Fare'] > 7.91) & (df['Fare'] <= 14.454), 'Fare'] = 1 df.loc[(df['Fare'] > 14.454) & (df['Fare'] <= 31), 'Fare'] = 2 df.loc[df['Fare'] > 31, 'Fare'] = 3 df['Fare'] = df['Fare'].astype(int) train_df = train_df.drop (['PassengerId', 'Ticket', 'Cabin', 'Name', 'Title', 'SibSp', 'Parch', 'Fellow'], axis=1) test_df = test_df.drop (['Ticket', 'Cabin', 'Name', 'Title', 'SibSp', 'Parch', 'Fellow'], axis=1) return train_df, test_df if __name__ == '__main__': train_df, test_df = wrangle_data () print (train_df.describe()) print (test_df.describe())
ニューラルネットワークによる予測
いよいよ予測をします!
まずは使用するニューラルネットワークのライブラリを Github からダウンロードしてください。
common ディレクトリだけ使うので、それだけダウンロードしても大丈夫です。
そして、以下のようにスクリプトを配置してください。
dir │ data_wrangle.py │ test.csv │ train.csv │ train_neuralnet.py │ ├───common │ │ functions.py │ │ gradient.py │ │ layers.py │ │ multi_layer_net.py │ │ multi_layer_net_extend.py │ │ optimizer.py │ │ trainer.py │ │ util.py
train_neuralnet.py は以下のソースコードになってます。
自分の Github からもダウンロード可能です。
# coding: utf-8 """titanic の生存予測を、ニューラルネットワークで行う ニューラルネットワークのサイズは MultiLayerNet の引数で決まる。 """ import numpy as np from common.multi_layer_net import MultiLayerNet import pandas as pd import matplotlib.pyplot as plt from common.optimizer import * import data_wrangle def change_one_hot_label(X): """書籍を参考。正解データを one_hot_label 形式にする""" T = np.zeros((X.size, 2)) for idx, row in enumerate(T): row[X[idx]] = 1 return T # 前処理されたデータの取得 train_df, test_df = data_wrangle.wrangle_data () # データを学習物と答えに分ける x_train = train_df.drop (['Survived'], axis=1).values t_train = train_df['Survived'].values t_train = change_one_hot_label (t_train) # ニューラルネットワークの生成。 # 隠れ層は適当に 100, 100, 100 とした。 network = MultiLayerNet(input_size=6, hidden_size_list=[100, 100, 100], output_size=2, weight_decay_lambda=0.01) # Optimizer の選択。AdaGrad() は common.optimizer 以下にある。 optimizer = AdaGrad() iters_num = 1000 train_size = x_train.shape[0] batch_size = 99 train_loss_list = [] train_acc_list = [] iter_per_epoch = max(train_size / batch_size, 1) # 学習 for i in range(iters_num): batch_mask = np.random.choice(train_size, batch_size) x_batch = x_train[batch_mask] t_batch = t_train[batch_mask] # 勾配 #grad = network.numerical_gradient(x_batch, t_batch) grad = network.gradient(x_batch, t_batch) # 更新 optimizer.update(network.params, grad) loss = network.loss(x_batch, t_batch) train_loss_list.append(loss) if i % iter_per_epoch == 0: train_acc = network.accuracy(x_train, t_train) train_acc_list.append(train_acc) # train データでどのように学習されたか図示 plt.plot (train_acc_list) # テストデータの PassengerId を退避させる test_df_id = test_df['PassengerId'] test_df = test_df.drop ('PassengerId', axis=1) x_test = test_df.values # テストデータの生存予測 output = network.predict (x_test) output = np.argmax (output, axis=1) # 生存予測を Kaggle に投稿する形に修正する output_df = pd.DataFrame (output, columns=['Survived']) output_df['PassengerId'] = test_df_id output_df = output_df.ix[:, ['PassengerId', 'Survived']] output_df.to_csv('test_ans.csv', index=False, encoding='utf-8')
さあ、ついにこれで test_ans.csv を得ました!
これを Kaggle に投稿してみましょう!
結果は....
0.7799!!
いまいち!!(笑)
まだまだ全然修行がたりないようです。
でも、こうやってデータ処理を競うっておもしろいですね。
これからも頑張ります。