戦コンからDSへの転身なるか?

Dev, DS的な勉強と実践の継続の記録

Kaggle / Titanic - Machine Learning from Disaster / 写経 / Gold Medalistから学ぶ Day 6(Final)

環境

Jupyter Notebook / Local

やったこと

今日で複数の機械学習モデルによるモデリングと評価が終わり、Gold MedalistのMr. MANAV SEHGALによるプロセスを一通りやったことになりました。モデリングと評価の部分についてまとめます。

モデリング(Random Forestを例に)

rf = RandomForestClassifier() # モデルのインスタンスをつくり
rf.fit(X_train, Y_train) # 学習データでインスタンスに学習をさせ
Y_pred = rf.predict(X_test) # テストデータによる予測結果を吐き出し
acc_rf = round(rf.score(X_train, Y_train) * 100, 2) # 学習による精度(スコア:%化)を吐き出し
acc_rf # スコアを出力

この構文で全部やれる。

あとはインスタンス名と呼び出すクラスをモデルごとに変えるだけ。

モデルの比較出力

models = pd.DataFrame({
    'Model' : ['Support Vector Machine', 'KNN', 'Logistic Regression', 
               'Random Forest', 'Naive Bayes', 'Perceptron', 
               'Stochastic Gradient Decent', 'Linear SVC', 'Decision Tree'],
    'Score' : [acc_svc, acc_knn, acc_log, acc_rf, acc_gaussian, 
               acc_perceptron, acc_sgd, acc_linear_svc, acc_tree]})

models.sort_values(by='Score', ascending=False)

モデルごとのスコアを出した変数にラベルをつけて、スコア順でリスト一覧表示。

これだけです。

所感

ETLとかクレンジングとかデータの前処理に比べればモデリングはあっけない。特徴量の仮説出しなども含めて前処理が90%くらいの工数という感覚値です。

これでスコアが0.77033で9,037 / 13,846ですから全体の65.3%, 後ろから1/3です。

道のりは遠い…。

Kaggle / Titanic - Machine Learning from Disaster / 写経 / Gold Medalistから学ぶ Day4, 5

環境

Jupyter Notebook / Local

やったこと

Day4は東京から車で早朝に蓼科の山荘に戻ったこともあって疲れていたので日記を残すことができませんでしが、それでも手は動かしてみました。東京出張でリモート会議の合間にカフェで手を動かすことも含めて、やる気スイッチとか以前に、行動へのハードルを下げることで習慣化を狙っています。

さて、Day4, 5と進めてみて、ようやくデータクレンジングと特徴量の生成については一通り写経することができました。写経しているのでたまに本当に無心にただ写し書いていることがありますが、それだけだと身につかない気がするので、この過程で行ったことについて少し抽象化、一般化してみようと思います。

データクレンジングと特徴量生成で良く使うコード

pandasの.info()関数によるDataFrameの中身概観

train_df.info()
print('_'*40) # 区切り線の挿入
test_df.info()

基本ですよね。合計レコード数と変数ごとのnon-null数が分かるので差分がnull値。

pandasの.describe()関数による基本統計量概観

train_df.describe() # デフォルトで数値型カラムについての基本統計量取得
train_df.describe(include='O') # 'O'で文字列取得
train_df.describe(include='all') # 'all'で文字列も数値型も全て取得

※ これはinculude='O'の場合 count, unique, top, freqなどを吐き出してくれるのでざっと状況確認ができる。

pandasの.groupby()関数によるグループ化

train_df[['Pclass', 'Survived']].groupby(['Pclass'], as_index=False).mean().sort_values(by='Survived', ascending=False)

グループ化してその平均値(等)をとってくれる。この場合は'Pclass'でグループ化して.mean()で平均値を取得して、.sort_values()関数で'Survived'(の平均値)順に並び替えてくれる。もう何度も使う。

seabornのFacetGridによるグリットパネル作成で可視化しながら比較

grid = sns.FacetGrid(train_df, col='Survived', row='Pclass', hue='Survived', height=2.2, aspect=1.6)
grid.map(plt.hist, 'Age', alpha=.5, bins=20)
grid.add_legend();

seabornでインスタンスsnsをつくり、.FacetGrid()関数でマトリクス(縦・横)のグリッドパネルを作成できる。この場合は横軸((column)に'Survived', 縦軸(row)に'Pclass'を配置し'grid'とする。gridで.map()関数の中でmatplotlib.pyplotのヒストグラムを構成し、数値を'Age'とする。pltインスタンスで.histとすればヒストグラム、.barplotとすれば棒グラフ、.pointplotとすれば折れ線グラフになる。

pandasの.map()関数によるマッピングデータによるデータ置換

title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}

for dataset in combine:
    dataset['TitleId'] = dataset['Title'].map(title_mapping)
    dataset['TitleId'] = dataset['TitleId'].fillna(0)

.map()の中身にあらかじめ準備していた置換するデータがマッピングされた辞書{}を入れることでpandasのDataFrameの中身を置換する。文字列データを数値型にしたり、幅のあるデータを数値型で括ったりする時に使用する。

pandasの.loc()関数による配列・行列の位置取得

for dataset in combine:    
    dataset.loc[ dataset['Age'] <= 16, 'Age'] = 0
    dataset.loc[(dataset['Age'] > 16) & (dataset['Age'] <= 32), 'Age'] = 1
    dataset.loc[(dataset['Age'] > 32) & (dataset['Age'] <= 48), 'Age'] = 2
    dataset.loc[(dataset['Age'] > 48) & (dataset['Age'] <= 64), 'Age'] = 3
    dataset.loc[ dataset['Age'] > 64, 'Age']

.loc()の中で行・列を指定して位置を取得する。行・列の中で条件指定しても良い。

所感

写経した後、ある程度まとまってきたところでこうやってまとめると自分の中で再現性が高まる気がします。いつか見返すというよりは、この行為自体で身につけることの意味の方が大きい的な。続けていきたいです。

Kaggle / Titanic - Machine Learning from Disaster / 写経 / Gold Medalistから学ぶ Day3

環境

Jupyter Notebook / Local

やったこと

ミーティングの合間に1時間くらい時間ができたので、こういう時にネットサーフィンするのではなく、ちょっとでも良いから学びに入れれば習慣になるなということで手を動かしてみました。

前回は'Mr.'などの敬称について文字列カテゴリーとしたので、それを数値カテゴリーにします。

# Titleを数値にしたものをTitleIdとして格納(NaNの場合は0)
title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}

for dataset in combine:
    dataset['TitleId'] = dataset['Title'].map(title_mapping)
    dataset['TitleId'] = dataset['TitleId'].fillna(0)

train_df_dropped.head()

pandasのDataFrameクラスが持っている.map()関数でマッピングを適用して'TitleId'としました。その上でNaN値があればクラス関数である.fillna()で数値の0で埋めました。

所感

まだ前処理段階ですが、'Title'として文字列カテゴリー化した特徴量カラムを’TitleId'として新しい特徴量カラムを作るべきなのか、それとも'Title'を文字列から数値に置換してしまうのが良いのか、経験的に判断ができません。

僕の感覚では、分析では基本的に数値化して行うので置換してしまっても良いのかなとは思っています(実際、この写経をしている先生?も置換していました)。ただ、不安でもあるので新カラムにしてしまいました。この辺りは分析の経験を重ねることで分かってくるところかなと思っています。

Kaggle / Titanic - Machine Learning from Disaster / 写経 / Gold Medalistから学ぶ Day2

環境

Jupyter Notebook / Local

やったこと

'Age', 'Pclass'が'Survived’に相関していそうとか、

'Sex'が'Survived'に相関していそうとか、

'Fare'も相関がありそうで、じゃあ'Embarked’は?とか、

敬称のまとめ方とか英語圏の人じゃないとできんやん!とか💦 黙々とやってます。

所感

英語が読解できていないのかもしれませんが、納得できない解説もあり、ちょっと混乱しながら進めています。

また、'Title’で肩書をくくってみて生存率との相関を見ても、これって結局’Sex'と’Age’の相関が色濃く出ているのではないか、このまま学習用の特徴量としてしまうと、多重共線性にハマるのでは?とか考えたりしながらやってます。

航海は続く…。

Kaggle / Titanic - Machine Learning from Disaster / 写経 / Gold Medalistから学ぶ

環境

Jupyter Notebook / Local

やったこと

下記の方はTitanicのお題で金メダルをとっており、かつコードを公開しておりコメントも多数ついています。コードとともにAIモデルの構築、評価、予測について、Kaggleのお題をどう処理するのかについて丁寧に解説してくれています。彼の解説を読みながら写経して、Jupyter Notebook内で挙動を確認しながらデータサイエンスのワークフローをステップ・バイ・ステップで学んでいきます。

MANAV SEHGAL www.kaggle.com

所感

今日のところは最初から'Assumtions based on data analysis'まで。

ライブラリのimportに始まり、課題の読み解き、問題の把握、データの読み込み、解析、考察、そしてどの特徴量がSurvivedに繋がるのかについての仮説出し、と言ったところでした。

とても丁寧に解説されているので読みながら頭と手を動かすことで身についていることが実感できます。サイエンスですから闇雲に手を動かすのではなくて、見立てが大事なんだなと。当たり前ですが。

Kaggle / Titanic - Machine Learning from Disaster / 写経 / Submissionの更新

環境

Jupyter Notebook / Local

やったこと

  • RandomForestClassifier
  • LightGBM
  • 乗船地、敬称、家族構成で分類してRandomForestClassifier あたりでなんとか10,000人以内に入りましたw

    所感

    ここまでが今日の限界。

途中Score: 0が続いたのは'Survived'がfloat型になっており、全問不正解扱いになっていたため(int64にしたらスコアが出ました)。

ハイパーパラメーターとか全くいじってません。

とにかく色々とお試しで。

Kaggle / Titanic - Machine Learning from Disaster / 写経 / First Submitまで

環境

Jupyter Notebook / Local

やったこと

カテゴリカルデータの変換

df_train.replace({'Sex': {'male': 0, 'female': 1}}, inplace=True)
df_test.replace({'Sex': {'male': 0, 'female': 1}}, inplace=True)

カテゴリカルのドロップ(※文字列の数値化とかでモデル最適化へ繋げること可能)

category_list = ['Name', 'Ticket', 'Cabin', 'Embarked']
df_train_dropped = df_train.drop(category_list, axis=1, inplace=False)
df_train_dropped.head()

決定木モデルの作成と学習、評価

from sklearn.tree import DecisionTreeClassifier
x = df_train_dropped[['Pclass', 'Sex', 'SibSp', 'Parch', 'Fare']].values
t = df_train_dropped['Survived'].values
tree = DecisionTreeClassifier()
result = tree.fit(x, t)
tree.score(x, t)
0.9225589225589226

学習したモデルによる予測

x_test = df_test_dropped[['Pclass', 'Sex', 'SibSp', 'Parch', 'Fare']].values
pred = tree.predict(x_test)

結果の提出

submit_csv = pd.concat([df_test['PassengerId'], pd.Series(pred)], axis=1)
submit_csv.columns = ['PassengerId', 'Survived']
submit_csv.to_csv('sbmition.csv', index=False)

KaggleでのSubmitとLeadersboard

所感

写経メインでやってきたけど、途中からは”プロセス”について自分で検索してerror出しながら修正しながら提出に持ち込みました。

順位はsubmitした時点で12,326 / 14,060ということで下位22.3%に沈んでおりましてブロンズメダルどころか低迷と言って良いと思いますが、やり遂げたことは嬉しいです(富士ヒルでメダルには届かなかったけど完走した、みたいな)。

  • お題の確認
  • ルールの確認
  • データのロード
  • データのクレンジング
  • 機械学習に用いるためのデータ整形
  • モデルの選択
  • モデルの学習
  • モデルの評価
  • 提出用フォーマットへのデータ整形と出力

と、一通り学ぶことができました。

モデルの最適化に向けては、

  • null値に対する平均値での置き換えを他の統計量で代替
  • ドロップしたカテゴリカルデータの活用
  • 決定木以外のモデルの選択

あたり、色々できそうです。

何より、面白いです!