KaggleのTitanicで上位10%に入った手法のまとめ
初心者向けですが深層学習の講師を最近やりました。
講義の中で実際にKaggleのコンペで腕試しをするということをしたかったので講義をやる前にチャレンジした。
今回腕試しをするコンペはkaggleのチュートリアルで有名なtitanicを選んだ。
Titanic: Machine Learning from Disaster | Kaggle
どういった内容かというと、タイタニック号の乗客のデータからある乗客は生存したか否かを判定し、その正解率を競う感じ。
試行錯誤して自分の最高スコアは 0.81339 になった。上位10%だしそこそこ頑張れたはず。
もう少し上を目指したいとこだが授業も始まったので一旦打ち切り
コードはここ
データ分析にはpandas
を用いた。最初はdescribe()
やdf.isnull().sum()
とかで統計や欠損値の確認をする。
訓練データのAge、Cabinなどに欠損値があるのがわかる。
次に仮説をいくつか立ててその条件でデータを操作し、その時の生存者の割合を確認していった。仮説は主に
子供や赤ん坊など年齢が若い人の方が優先して救助されるのではないか
女性のが優先して救助されるのではないか
Pclass1(だいたいお金持ちの乗客)の人たちは優先して救助されるのではないか
などなど
年齢はやっぱりというか子供のが生存率が高いのは確認できた
生存率に関しては性別の違いが一番別れていた。
後は名前の属性を何かしら使いたい(文字列の操作を練習したかった)ので名前からMr
やMiss
などを抽出してそれらの生存率を確認したりした。
生存の判別モデル構築の問題として年齢を特徴として扱いたいけど欠損している乗客がいる。
この問題に対して訓練データの年齢における欠損値を除いた年齢の中央値で穴埋めか年齢自体を予測するモデルを作り、そのモデルの予測結果で穴埋めするといった2つの手法をとった。
良い精度が出たのは後者の方だった。年齢予測モデルはXGBoostで構築した。
最終的に使う特徴はこれらに絞った
one_hot
系は文字列カテゴリを数値に変換したもの
SibParch
はSibSp
とParch
を合わせたもの
Fare_rounddown_split
はFare
の小数点を打ち切り、10ドルごとにカテゴリ分けしたもの
By_Age_class
はAge
を10歳ごとにカテゴリ分けしたもの
生存者の判別モデルとしてTensorflowでロジスティック回帰モデルとXGBoostモデルの2つを構築し、比較した。
Tensorflowのロジスティック回帰モデルは以下のように構築した
# 入力層 X = tf.placeholder(tf.float32, shape=[None, 7], name="input") t = tf.placeholder(tf.float32, shape=[None, 1]) # パラメータ1 stddev = np.sqrt(2.0 / 7) W1 = tf.Variable(tf.truncated_normal([7,24], stddev=stddev)) b1 = tf.Variable(tf.constant(0.1, shape=[24])) # パラメータ2 stddev = np.sqrt(2.0 / 24) W2 = tf.Variable(tf.truncated_normal([24,48], stddev=stddev)) b2 = tf.Variable(tf.constant(0.1, shape=[48])) keep_prob = tf.placeholder(tf.float32) # ドロップアウトする割合 # パラメータ3 stddev = np.sqrt(2.0 / 48) W3 = tf.Variable(tf.truncated_normal([48,1], stddev=stddev)) b3 = tf.Variable(tf.constant(0.1, shape=[1])) layer1 = tf.nn.relu(tf.matmul(X,W1) + b1) layer2 = tf.nn.relu(tf.matmul(layer1,W2) + b2) layer2_drop = tf.nn.dropout(layer2, keep_prob) layer3 = tf.matmul(layer2_drop,W3)+b3 p = tf.nn.sigmoid(layer3,name="output") # 荷重減衰 norm_term = tf.nn.l2_loss(layer1) + tf.nn.l2_loss(layer2_drop) # 正則項 lambda_ = 0.001 # 損失関数 loss = tf.reduce_mean(tf.square(p - t))+ lambda_*norm_term # 学習アルゴリズム optimizer = tf.train.AdamOptimizer() train_step = optimizer.minimize(loss) # 精度 correct_prediction = tf.equal(tf.sign(p-0.5), tf.sign(t-0.5)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
XGboostとlog_lossで誤差の値を比べたがXGboostの勝利だった
NNと決定木における表現力の問題だろうか・・・
ハイパーパラメータをいじって提出していたら 0.81339 という結果が出た。
終わった後に他の人と話してタイタニックは実際にあった話、つまり背景があるから背景から得られる情報を使えばよかったとか元のタイタニック号の船構造を見つけて救命艇がどこにあるかや部屋番号の割り当て(Cabin)を確認するのもアリだったよねーとか灯台下暗しって感じに知見を得た。
他にもstackingや交差検証など学習方法の見直しも大事