02 Jan 2018, 05:31

KaggleのためのMOOCがcourseraに!How to win a Data Science Competitionを受けた

kaggleの攻略法について、以前調査した。あまり、学習教材がなかった。

Kaggleを初心者が進めるには、とにかくコンペに参加してKernelを読むしかないのかなと思っていた。そんな自分に朗報!この courseraが提供するものこそ、自分が求めていたものだ。

その名も・・・

How to Win a Data Science Competition: Learn from Top Kaggler

特徴

ロシアのカグルマスターが講師

この講座では、Yandexというロシアのgoogleが講座をサポートしている。そのため、ロシア切ってのデータサイエンティストから学ぶことができるのだ。

また、catboostなどの、ロシア魂がこもったライブラリを紹介される。これはかのxgboostよりも強力だった。

難易度高い…

正直、難しいです。quiz, assignment, 解けなかった。

この講座は機械学習の手法を教える講座ではない。それらはすでに身についているものとして、コンペで使える技や知識を教えてくれる。

kaggle コンペで腕試し

習ったことは即試してみようということで、練習用のkaggleコンペが用意されている。

ロシアのIT企業の売上予測を行う。時系列データコンペ。

各週の内容

week1:

recap&introduction ということで、データ分析コンペについて紹介される。

基本的な手法はもう知っているよねということで、MLの手法はサラッと紹介されて終わる。

そのあと、前処理についての紹介。これはよくまとまっている。数値変数、カテゴリ変数、時間の扱いと位置の扱い、欠損値の扱い。これは大事なので、なんども復習したいところだ。

assignmentはpandasについての演習。groupbyを多用する必要があり、初心者サヨウナラ感がとてもする。

week2:

EDAについての解説。これも一通りの手法は紹介される。とはいえ、すべてを網羅できるわけではなく、自分で習ったことを実践してみないとこれは身につかない気がした。

次に Validationということで、データ分割の戦略について紹介される。データ分割がなぜ必要か(過学習を避けるため)、その手法と注意点について。

最後に、Data Leakageが扱われる。具体的な事例を元に、DataLeakageにどうやって気づくかなどが紹介される、が、

ここはよくわからなかったな。。。Assignmentも Data Leakageについてなのだが。

week3:

Metrix(評価指標)について学ぶ。回帰、分類それぞれでよく使われる指標を学ぶ。MetrixとLoss functionの違いについて説明。ココらへん、理解していなかったので参考になる。

続いて、mean encodingという手法について紹介される。カテゴリカル変数を変換するための方法で、label/one-hot-encodingよりも、強力だとか。そして、その実装がassignmentとして課される。

week4:

ハイパーパラメータのチューニングについて、まず紹介される。ランダムフォレストやxgboost, ニューラルネットワークのパラメータチューニングについての実践的なアドバイス。また、自動チューニングツールの紹介(hyperoptなど)

次に、特徴量エンジニアリングの小ネタ第二弾。

  • Matrix Factorization
  • Feature Interaction
  • t-SME

最後に、一番むずかしい話題、アンサンブル学習が紹介される。weight average, bagging, stacking, boosting, stacknet…ムズい。assignmentはstackingの実装。

week5:

過去のコンペティションで講師の人が上位入賞をどうやってしたか、カグルマスターがその手法の種明かしをしてくれる。

ただ、これらの動画はおまけのようなもので、最後の週の本題は、用意されたKaggleコンペで上位スコアを取ること。

Assignmentがスコアのcsvデータの提出。一定以上のスコアを超えていないと、クリアとみなされない。そしてこの水準がとても高い。MSE1.0より低くないと、どうやら合格できないよう。LBを見ると、そんな人は30人くらいしかいない。

それに加えて、ペアレビューがある。以下のフォーマットに従って、自分がどうやってコンペに望んだかを説明するレポートを作成して、コードと一緒に提出する。

提出がすむと、他の人のコードをレビューできるようになる。

おわりに

この記事を執筆している時点では、私はコースを完了していない。

QuizもAssignmentも終わらなかった。

ただ、とてもこのコースはとても充実していた。かけた時間は現在95時間。kaggleのための実践的なテクニックが豊富に紹介されていて、吸収することがたくさんある。mean encodingや stackingなど、ネットにはほんとど情報がないが重要な手法も紹介されている

(assignmentにもなっている)

さらに、その知識を実践するする機会もコンペという形で与えられている。MOOCをいろいろと受けてきたけれども、そのなかでもかなり楽しい講座だった。それは、自分が今興味があることがデータサイエンスであり、ちょうど知りたい内容だったからだ。

この講座の内容をよくよく復習し、今後もKaggleに取り組んでいこう。Kaggle用のマシンも購入したことだし、まずはそれでグリッドサーチやアンサンブルを試してスコアを上げる。

01 Oct 2017, 03:56

タイタニックで決定木、交差検証、グリッドサーチ(Python)

はじめに

データサイエンティスト養成講座の第二回を受けてきました。

扱った内容は、

  • 決定木
  • クロスバリデーション
  • グリッドサーチ

講座では、Rを使うのだけれども、Pythonにもなれておきたいので、

講座の内容をPythonで復習しました。

ついでに、kaggleのタイタニック問題を決定木で解きました。

今回のコードは、githubにあげています。以下は、コードの抜粋です。

Pythonで決定木

Pythonで決定木を使うには、scikit-learnライブラリを使う。

from sklearn import tree
clf = tree.DecisionTreeClassifier(random_state=17)
clf.fit(X, y)

簡単!

クロスバリデーション with KFold

決定木は、max_depthパラメータを大きくすればするほど精度が上がっていくが、汎化性能が下がっていく。なので、クロスバリデーションという方法を使って、過学習が起こっていないかチェックすることが重要になる。

from sklearn.model_selection import KFold
from sklearn import metrics
from sklearn.metrics import accuracy_score
K = 5
kf = KFold(n_splits=K, shuffle=True, random_state=17)

score_train_tmp = 0
score_test_tmp = 0

for train_index, test_index in kf.split(X):
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]

    # 構築データでモデル構築
    clf.fit(X_train, y_train)

    # 構築データの予測値
    pred_train = clf.predict(X_train)

    # 構築データのaccuracy
    auccuracy = accuracy_score(pred_train, y_train)

    #構築データのaccuracyを足していく
    score_train_tmp+=auccuracy

    #検証データの予測値
    pred_test = clf.predict(X_test)

    #検証データのaccuracy
    auccuracy = accuracy_score(pred_test, y_test)

    #検証データのaccuracyを足していく
    score_test_tmp+=auccuracy
score_train_tmp/K
0.82463676190176005

score_test_tmp/K
0.80247944259619608

構築データと検証データのスコアが近ければ、過学習が起こっていないと判断できる。これが乖離していると過学習が起こっているので、パラメータチューニングが必要。

グリッドサーチ

最適なパラメータをしらみつぶしにパラメータを組み合わせて探索していく方法をグリッドサーチという。普通はfor文を回してパラメータを変えてスコアを見ることで調整していく。しかし、scikit-learnには、GridSearchCVというグリッドサーチをするための専用のクラスが用意されている。

これをつかえば、煩わしいfor文のネストを書かずとも、複数パラメータに対して探索をすくことができる。

調べたいパラメータをまずは辞書で定義する。

from sklearn.model_selection import GridSearchCV

# use a full grid over all parameters
param_grid = {"max_depth": [2,4,6,8,10],
              "max_features": ['log2', 'sqrt','auto'],
              "min_samples_split": [2, 3, 5],
              "min_samples_leaf": [1,5,8],
              "criterion": ["gini", "entropy"]}

次に、GridSearchCVを読んで、グリッドサーチを実行する。

tree_grid = GridSearchCV(estimator=clf,
                 param_grid = param_grid,   
                 scoring="accuracy",  #metrics
                 cv = K,              #cross-validation
                 n_jobs =-1)          #number of core

tree_grid.fit(X,y) #fit

tree_grid_best = tree_grid.best_estimator_ #best estimator
print("Best Model Parameter: ",tree_grid.best_params_)
print("Best Model Score    : ",tree_grid.best_score_)
Best Model Parameter:  {'criterion': 'gini', 'max_depth': 6, 'max_features': 'log2', 'min_samples_leaf': 8, 'min_samples_split': 2}
Best Model Score    :  0.812570145903

便利だ。素晴らしい。

しかし、このパラメータチューニングした結果をサイトにて提出しても、大したスコアは出ない。これは、特徴量エンジニアリングがそもそもしょぼいという問題がある。

16 Aug 2017, 15:23

Kaggleをはじめたので対策や攻略法についてのブックマーク

Kaggle

Kaggle モチベーション

はじめの一歩

チュートリアル

攻略法ブックマーク

MOOC

Book

手法

Tools

その他

16 Aug 2017, 12:56

決定木とそのアンサンブル法についてメモ(ランダムフォレスト、xgboost)

Pythonではじめる機械学習を読んでいるので、その学習メモ。

今日は、決定木について。前回の線形回帰のように、kaggleの問題を解いてみた。

家に帰るまでが、遠足です!

kaggleするまでが、勉強です!

決定木

Yes/Noで答えられる質問で構成された階層的な木構造を学習する。

  • 過剰適合を防ぐには、構築過程で木の生成を早めに止める事前枝刈りと、

    一度木を構築してから、情報の少ないノードを削除する事後枝刈りがある。

  • scikit-learnには、DecisionTreeRegressorクラスと、DecisionTreeClassifierクラスに実装されている。scikit-learnには事前枝刈りしか実装されていない。

  • 決定木の深さに制約を与えないと、決定木はいくらでも深く、複雑になる。したがって、枝刈りされていない木は過剰適合になりやすく、新しいデータに対する汎化性能が低い傾向にある。

  • 決定木から、特徴量の重要度(feature importance)が導出できる。個々の特徴量かどの程度重要かを示す割合である。

  • 利点は、結果のモデルが容易に可視化可能で、専門家でなくても理解可能であること。

  • 別の利点は、データのスケールに対して完全に不変であること、つまり特徴量の正規化や標準化は必要ない。

  • 最大の問題点は、事前枝狩りを行っても、過剰適合しやすく、汎化性能が低い傾向がある。そのため、単体でつかうのではなくアンサンブル法が用いられる。

アンサンブル法は、複数の機械学習モデルを組み合わせることで、より強力なモデルを構築する手法だ。ランダムフォレストと勾配ブースティング決定木がある。

ランダムフォレスト(RandomForest)

ランダムフォレストとは、少しずつ異なる決定木をたくさん集めたもの。それぞれ異なった方向に過剰適合した決定木をたくさん作れば、その結果の平均を取ることで過剰適合の度合いを減らすことができる。

個々の決定木が互いに異なるように、決定木の構築過程で乱数を導入している。導入方法は、データポイントを選択する方法と、分枝テストに用いる特徴を選択する2つの方法がある。

  • 構築する決定木の数をまず決める。
  • データからブートストラップサンプリングを行う。これは、重複可でデータポイントをランダムにn_samples回選びだす手法(復元抽出)このデータセットを用いて決定木を作る。
  • ただし、個々のノードで最適なテスト(基準値)を選ぶのではなく、特徴量のサブセット(max_features)をランダムに選び、その特徴量を使うものの中から最適なテストを選ぶ。
  • max_featuresが重要なパラメータ。max_featuresを大きくすると、決定木が似たようなものになり、最も識別性の高い特徴量をつかうので、訓練データに容易に適合できる。
  • max_featuresを小さくすると、ランダムフォレスト内の決定木は相互に大幅に異なるものとなるが、それぞれの決定木をかなり深く作らないと、データに適合できない。
  • しかし多くの場合、ランダムフォレストはデフォルトのパラメータで、十分よく機能する。
  • 回帰でもクラス分類でも、非常に強力。多くの場合、それほどパラメータチューニングせずに使える。スケール変換する必要もない。
  • テキストデータなどの、非常に高次元で疎なデータに対しては、うまく機能しない傾向にある。このようなデータに対しては線形モデルのほうが適している。
  • 線形モデルよりも、多くのメモリを消費するし、訓練も予測も遅い。実行時間やメモリが重要なアプリケーションでは、線形モデルをつかったほうがよい。

Kaggle digit-recognizer

これでScore 0.93729。

CNNにはかなわない。問題が悪かったかな??

勾配ブースティング回帰木(gradient boosting regression tree, GBRT)

勾配ブースティングでは、1つ前の決定木の誤りを次の決定木が修正するようにして、決定木を順番に作っていく。

  • モデルの占めるメモリが小さくなり、予測も早くなる。
  • 浅い決定木のような、簡単なモデル(弱学習機)を多数組み合わせるところがポイント。
  • パラメータ設定の影響を受けやすいが、こっちのほうが性能が良い。
  • learning_rate という重要なパラメータがある。
  • 過剰適合を低減するためには、深さの最大値を制限してより強力な事前枝刈りを行うか、学習率をさげればよい。
  • ランダムフォレストを先に試したほうかいい。こっちのほうが頑強だから。予測時間が非常に重要な場合や、kaggleのコンペで最後の1%を絞り出したいときは、勾配ブースティングを試すと良い。
  • xgboostはscikit-learnよりも、高速で、チューニングも容易。
  • 長所は、教師あり学習の中で最も強力なところ。
  • 短所は、パラメータチューニングに細心の注意が必要なところと、訓練にかかる時間が長いこと。

scikit-learnよりも、xgboostをつかったほうがいいよということで、使ってみた。

XGBoost の使い方。

kaggle digit-recognizer

Scoreは、0.93157。RandomForestよりも精度が低かった。

15 Aug 2017, 11:56

線形回帰の正則化についてメモ(リッジ回帰、Lasso)

[mathjax]

はじめに

Pythonではじめる機械学習を読み始めた。

今日は、線形回帰について。今まで、線形回帰は以下の式で表されるものだと思っていた。

$$

\hat{y} = w[0]✕x[0]+w1✕x1 ・・・w[p]✕x[p] + b

$$

しかし、実は正則化項が加えられることで、呼び名があることをしった。

  • L1正則化 ・・・Lasso回帰
  • L2正則化 ・・・Ridge回帰

この辺の知識を本から抜き出してメモ。ついでに、Kaggleも解いた。

線形モデル

線形モデルは入力特徴量の線形関数を用いて予測を行う。

  • 単一の特徴量に対しては、予測が直線になる回帰モデルとして特徴づけられる。特徴量が2つならば予測は平面に、高次元においては予測は超平面になる。
  • 多数の特徴量を持つデータに対しては、線形モデルは非常に強力。

線形回帰

線形回帰、もしくは 通常最小二乗法(OLS) は、最も単純で、最も古典的な線形回帰手法。線形回帰では、訓練データにおいて、予測と真の回帰ターゲットyとの平均二乗誤差が最小になるようにパラメータwとbを求める。

from sklearn.linear_model import LinearRegression
lr = LinearRegression().fit(X_train, y_train)
  • 1次元データセットでは、過剰適合の危険は少ない。
  • 高次元データセットに対しては、線形モデルは、より強力になるので、過剰適合の可能性が高くなる。

リッジ回帰

リッジ回帰 は線形回帰モデルによる回帰の1つである。予測に用いられる式は、通常最小二乗法のものと同じである。しかし、リッジ回帰では、係数(w) を、訓練データに対する予測だけではなく、他の制約に対しても最適化する。

  • 予測をうまく行いつつ、個々の特徴量が出力に与える影響をなるべく小さくしたい。これは、正則化(L2正則化)の一例である。
  • 十分な訓練データがある場合には、正則化はあまり重要ではなくなる。つまり、リッジ回帰と線形回帰は同じ性能を出す。
  • リッジ回帰は、linear_model.Ridgeに実装されている。
from sklearn.linear_model import Ridge
clf = Ridge()
clf.fit(X_train, y_train)

KaggleのHouse Prices: Advanced Regression Techniquesコンペを解いてみた。

Lasso回帰

Lasso回帰 は、L1正則化をかける。L1正則化の結果、いくつかの係数が完全に0になる。これは、モデルにおいていくつかの特徴量が完全に無視されるということになる。

  • 係数を0に向かわせる強さを制御する正則化パラメータalphaがある。
  • 適合不足の度合いを減らすためには、alphaを減らせば良い。
  • Lassoは、linear_model.Lassoに実装されている。
from sklearn.linear_model import Lasso
clf = Lasso()
clf.fit(X_train, y_train)

KaggleのHouse Prices: Advanced Regression Techniquesコンペを解いてみた。これで、上位50%まで行った。優秀だ。

まとめ

実際につかう場合は、リッジ回帰をまず試すのがよい。特徴量がたくさんあって、そのうち重要なのはわずかしかないことが予想されるのであれば、Lassoのほうが向いている。

18 Jun 2017, 07:51

Python で勾配降下法を使って線形の単回帰分析をしてみた

Python で勾配降下法を使って線形の単回帰分析をしてみた。

はじめに

Siraj Ravel さんの新しい動画シリーズ, “The Math of Intelligence”が始まった。

機械学習のための数学を毎週カバーしていくようだ。シラバスは以下。

数学に苦手意識があるので、おもしろそうなトピックだけ Coding Challenge に取り組んでいこうと思う。

Coding Challenge

初めのトピックは Gradient Descent(勾配降下法)。

昔、勉強したのだけれども、すっかり忘れていた。以下の本がとても今回役に立った。

Coding Challenge は Kaggle のデータで、勾配降下法を使って線形の単回帰分析をすること。

今回 チャレンジした Jupyter Notebook は以下です。

データセット

Kaggle のデータを使うようにとのことなので、入門用のデータセット, House Prices を使っていこうと思う。

とりあえずいちばん簡単な方法を試したいので、家の面積と価格の相関関係に注目することにした。

  • SalePrice - the property’s sale price in dollars. This is the target variable that you’re trying to predict
  • GrLivArea: Above grade (ground) living area square feet

データをプロットしてみると正の相関関係がありそうなので、直線が引けそう。

勾配降下法

本当は、偏微分の数式とか書きたいけれど、数式の書き方がよくわからなかった orz

というわけで、説明抜きでいきなりコードですみません m(._.)m

参考リンクだけはっておきます。この記事のコードを参考にしました。

def calcurate_mean_squared_error(x, y, b, m):
    total_error = 0
    n = y.size
    for i in range(n):
        prediction = m*x[i] + b
        total_error += (y[i] - prediction)**2
    return (1/n) * total_error

def step_gradient(x, y, b, m, learning_rate):
    m_grad = 0
    b_grad = 0
    n = y.size

    #Computes the gradients
    for i in range(n):
        # Partial derivative for m
        m_grad += -(2/n) * x[i] * (y[i] - ((m*x[i]) + b))
        # Partial derivative for b
        b_grad += -(2/n) * (y[i] - (m*x[i]) + b)

    # update m and b
    m = m - (learning_rate * m_grad)
    b = b - (learning_rate * b_grad)    
    return b, m

def gradient_descent_runner(x, y, initial_b, initial_m, learning_rate, num_iterations):
    b = initial_b
    m = initial_m
    past_errors = []
    for i in range(num_iterations):
        b, m = step_gradient(x, y, b, m, learning_rate)
        if(i % 100) == 0:
            error = calcurate_mean_squared_error(x, y, b, m)
            past_errors.append(error)
            print('Error after', i, 'iterations:', error)
    return b, m, past_errors

実験結果

学習率 0.0001 だと収束しなかった。

おかしい。もっともっと学習率を小さくしても収束しない。はじめはバグっているのかと思ったけど、そうではなさそうだ。

num_iterations = 1000
learning_late = 0.0001
print("Starting gradient descent at b = {0}, m = {1}, error = {2}".format(
    initial_b, initial_m, 
    calcurate_mean_squared_error(x, y, initial_b, initial_m)))
print("Running...")
[b, m, errors] = gradient_descent_runner(x, y, initial_b, 
                                 initial_m, learning_late, num_iterations)
print("After {0} iterations b = {1}, m = {2}, error = {3}".format(
    num_iterations, b, m, calcurate_mean_squared_error(x, y, b, m)))
Starting gradient descent at b = 0, m = 1.0, error = 38434358058.74041
Running...
Error after 0 iterations: 9.29730669048e+15

/home/tsu-nera/anaconda3/envs/dlnd/lib/python3.6/site-packages/ipykernel_launcher.py:6: RuntimeWarning: overflow encountered in double_scalars

/home/tsu-nera/anaconda3/envs/dlnd/lib/python3.6/site-packages/ipykernel_launcher.py:9: RuntimeWarning: overflow encountered in double_scalars
  if __name__ == '__main__':
/home/tsu-nera/anaconda3/envs/dlnd/lib/python3.6/site-packages/ipykernel_launcher.py:14: RuntimeWarning: invalid value encountered in double_scalars

Error after 100 iterations: inf
Error after 200 iterations: nan

いろいろ学習率をいじって試した結果、0.000000385 というよくわからない数が最も適切だった。なんだこりゃ?!

標準化をためす

coursera の Machine Learning で、フィーチャースケーリング を習ったことを思い出した。

講座の動画を見返したら多変数の場合を扱っていた。

説明変数が1つでも、有効なのかな?とりあえず、標準化を試してみた。

norm_x = (x - x.mean()) / x.std()

今回は、学習率 0.0001 という、馴染みの値で収束した。うまくいったようだ。

コスト関数の値も plot した。イテレーションを繰り返すごとに減っている。

03 May 2017, 09:30

Kaggle: Titanic 問題データ分析

はじめに

  <p>
    先日、Kaggleのタイタニック問題に挑んで惨憺たる結果を出しました。
  </p>

  <ul>
    <li>
      <a href="http://futurismo.biz/archives/6296">Kaggle のタイタニック問題に Keras で挑戦した。前処理が課題だと分かった。 | Futurismo</a>
    </li>
  </ul>

  <p>
    データ分析をするスキルが自分にはない。なんとか身につけたいと思っていたところ、<br /> Udemyの講座でKaggleのタイタニック問題を元にデータ分析を行っている講座を発見した。
  </p>

  <ul>
    <li>
      <a href="https://www.udemy.com/python-jp/learn/v4/">【世界で5万人が受講】実践 Python データサイエンス | Udemy</a>
    </li>
  </ul>

  <p>
    これはいい。まずは、講義にしたがってデータ分析してみたので、これはその講義メモです。
  </p>
</div>

目的

  <p>
    以下について、講義では調べている。
  </p>

  <ul>
    <li>
      タイタニック号の乗客はどのような人達だったのか?
    </li>
    <li>
      それぞれの乗客はどのデッキにいたか?また、それは客室の種類とどのような関係にあったか?
    </li>
    <li>
      乗客は主にどこから来たのか?
    </li>
    <li>
      家族連れか、単身者か?
    </li>
  </ul>
</div>

SetUp

  <p>
    タイタニック号のデータは下記のURLのtrainからダウンロードできる。
  </p>

  <ul>
    <li>
      <a href="https://www.kaggle.com/c/titanic/data?train.csv">https://www.kaggle.com/c/titanic/data?train.csv</a>
    </li>
  </ul>

  <p>
    まずは,csvの中身を確認。カラムの意味は <a href="https://www.kaggle.com/c/titanic/data">kaggleのサイト</a> を参照。
  </p>
</div>

In [3]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>

from pandas import Series, DataFrame titanic_df = pd.read_csv(‘train.csv’) titanic_df.head()

Out[3]:

    <div class="output_html rendered_html output_subarea output_execute_result">
      <div>
        <table class="dataframe" border="1">
          <tr style="text-align: right;">
            <th>
            </th>

            <th>
              PassengerId
            </th>

            <th>
              Survived
            </th>

            <th>
              Pclass
            </th>

            <th>
              Name
            </th>

            <th>
              Sex
            </th>

            <th>
              Age
            </th>

            <th>
              SibSp
            </th>

            <th>
              Parch
            </th>

            <th>
              Ticket
            </th>

            <th>
              Fare
            </th>

            <th>
              Cabin
            </th>

            <th>
              Embarked
            </th>
          </tr>

          <tr>
            <th>
            </th>

            <td>
              1
            </td>

            <td>
            </td>

            <td>
              3
            </td>

            <td>
              Braund, Mr. Owen Harris
            </td>

            <td>
              male
            </td>

            <td>
              22.0
            </td>

            <td>
              1
            </td>

            <td>
            </td>

            <td>
              A/5 21171
            </td>

            <td>
              7.2500
            </td>

            <td>
              NaN
            </td>

            <td>
              S
            </td>
          </tr>

          <tr>
            <th>
              1
            </th>

            <td>
              2
            </td>

            <td>
              1
            </td>

            <td>
              1
            </td>

            <td>
              Cumings, Mrs. John Bradley (Florence Briggs Th&#8230;
            </td>

            <td>
              female
            </td>

            <td>
              38.0
            </td>

            <td>
              1
            </td>

            <td>
            </td>

            <td>
              PC 17599
            </td>

            <td>
              71.2833
            </td>

            <td>
              C85
            </td>

            <td>
              C
            </td>
          </tr>

          <tr>
            <th>
              2
            </th>

            <td>
              3
            </td>

            <td>
              1
            </td>

            <td>
              3
            </td>

            <td>
              Heikkinen, Miss. Laina
            </td>

            <td>
              female
            </td>

            <td>
              26.0
            </td>

            <td>
            </td>

            <td>
            </td>

            <td>
              STON/O2. 3101282
            </td>

            <td>
              7.9250
            </td>

            <td>
              NaN
            </td>

            <td>
              S
            </td>
          </tr>

          <tr>
            <th>
              3
            </th>

            <td>
              4
            </td>

            <td>
              1
            </td>

            <td>
              1
            </td>

            <td>
              Futrelle, Mrs. Jacques Heath (Lily May Peel)
            </td>

            <td>
              female
            </td>

            <td>
              35.0
            </td>

            <td>
              1
            </td>

            <td>
            </td>

            <td>
              113803
            </td>

            <td>
              53.1000
            </td>

            <td>
              C123
            </td>

            <td>
              S
            </td>
          </tr>

          <tr>
            <th>
              4
            </th>

            <td>
              5
            </td>

            <td>
            </td>

            <td>
              3
            </td>

            <td>
              Allen, Mr. William Henry
            </td>

            <td>
              male
            </td>

            <td>
              35.0
            </td>

            <td>
            </td>

            <td>
            </td>

            <td>
              373450
            </td>

            <td>
              8.0500
            </td>

            <td>
              NaN
            </td>

            <td>
              S
            </td>
          </tr>
        </table>
      </div>
    </div>
  </div>
</div>

In [4]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">titanic_df</span><span class="o">.</span><span class="n">info</span><span class="p">()</span>

    <div class="output_subarea output_stream output_stdout output_text">
      <pre>&lt;class 'pandas.core.frame.DataFrame'&gt;

RangeIndex: 891 entries, 0 to 890 Data columns (total 12 columns): PassengerId 891 non-null int64 Survived 891 non-null int64 Pclass 891 non-null int64 Name 891 non-null object Sex 891 non-null object Age 714 non-null float64 SibSp 891 non-null int64 Parch 891 non-null int64 Ticket 891 non-null object Fare 891 non-null float64 Cabin 204 non-null object Embarked 889 non-null object dtypes: float64(2), int64(5), object(5) memory usage: 83.6+ KB

train.csvのなかには、891人の乗客のデータが含まれるけれども、AgeやCabinが Nanが多いことがわかる。

タイタニック号の乗客はどのような人達だったのか

性別に関して、女性、男性の数を調べる。

In [5]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>

import matplotlib.pyplot as plt import seaborn as sns %matplotlib inline

In [6]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">sns</span><span class="o">.</span><span class="n">countplot</span><span class="p">(</span><span class="s1">'Sex'</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">titanic_df</span><span class="p">)</span>

Out[6]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;matplotlib.axes._subplots.AxesSubplot at 0x7f1942ae6a90&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/d51c9a4dafed2cd880f8d588f220ad72.png" />
    </div>
  </div>
</div>

女性の二倍近く男性が多いことがわかる。

客室のクラスで層別化

In [7]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">sns</span><span class="o">.</span><span class="n">countplot</span><span class="p">(</span><span class="s1">'Sex'</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">titanic_df</span><span class="p">,</span> <span class="n">hue</span><span class="o">=</span><span class="s1">'Pclass'</span><span class="p">)</span>

Out[7]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;matplotlib.axes._subplots.AxesSubplot at 0x7f194d251dd8&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/7fb95fc331eefbb698644f3780b2890d.png" />
    </div>
  </div>
</div>

In [8]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">sns</span><span class="o">.</span><span class="n">countplot</span><span class="p">(</span><span class="s1">'Pclass'</span><span class="p">,</span><span class="n">data</span><span class="o">=</span><span class="n">titanic_df</span><span class="p">,</span><span class="n">hue</span><span class="o">=</span><span class="s1">'Sex'</span><span class="p">)</span>

Out[8]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;matplotlib.axes._subplots.AxesSubplot at 0x7f193f6ef588&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/6eb2b11a900f4bf0456df8ec822e5e62.png" />
    </div>
  </div>
</div>

三等客室の男性が多いことがわかる。

子供という新しい列を追加

  <p>
    子供を優先して助けたということがkaggleのサイトにかかれているので、子供がどのくらいいるかを調べる。ここでは、16歳未満が子供。
  </p>
</div>

In [9]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="k">def</span> <span class="nf">male_female_child</span><span class="p">(</span><span class="n">passenger</span><span class="p">):</span>
<span class="n">age</span><span class="p">,</span><span class="n">sex</span> <span class="o">=</span> <span class="n">passenger</span>
<span class="k">if</span> <span class="n">age</span> <span class="o">&lt;</span> <span class="mi">16</span><span class="p">:</span>
    <span class="k">return</span> <span class="s1">'child'</span>
<span class="k">else</span><span class="p">:</span>
    <span class="k">return</span> <span class="n">sex</span>

titanic_df[‘person’] = titanic_df[[‘Age’,‘Sex’]].apply(male_female_child,axis=1)

In [12]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">sns</span><span class="o">.</span><span class="n">countplot</span><span class="p">(</span><span class="s1">'Pclass'</span><span class="p">,</span><span class="n">data</span><span class="o">=</span><span class="n">titanic_df</span><span class="p">,</span><span class="n">hue</span><span class="o">=</span><span class="s1">'person'</span><span class="p">)</span>

Out[12]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;matplotlib.axes._subplots.AxesSubplot at 0x7f19433e22e8&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/5e2fc220fd19b91aba0ba0ab152dc580.png" />
    </div>
  </div>
</div>

In [13]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">titanic_df</span><span class="p">[</span><span class="s1">'person'</span><span class="p">]</span><span class="o">.</span><span class="n">value_counts</span><span class="p">()</span>

Out[13]:

    <div class="output_text output_subarea output_execute_result">
      <pre>male      537

female 271 child 83 Name: person, dtype: int64

1等客室、2客室には子供が少ない。3客室に多い。これで年齢分布が分かった。

  <p>
    次に、カーネル密度推定で分布を見てみる。
  </p>
</div>

In [17]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">fig</span> <span class="o">=</span> <span class="n">sns</span><span class="o">.</span><span class="n">FacetGrid</span><span class="p">(</span><span class="n">titanic_df</span><span class="p">,</span> <span class="n">hue</span><span class="o">=</span><span class="s2">"person"</span><span class="p">,</span> <span class="n">aspect</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>

fig.map(sns.kdeplot, ‘Age’, shade=True) oldest = titanic_df[‘Age’].max() fig.set(xlim=(, oldest)) fig.add_legend()

    <div class="output_subarea output_stream output_stderr output_text">
      <pre>/home/tsu-nera/anaconda3/lib/python3.6/site-packages/statsmodels/nonparametric/kdetools.py:20: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future

y = X[:m/2+1] + np.r_[0,X[m/2+1:],0]*1j

  <div class="output_area">
    <div class="prompt output_prompt">
      Out[17]:
    </div>

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;seaborn.axisgrid.FacetGrid at 0x7f193f213e80&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/8922e58c431d0cc763e62204ea897a07.png" />
    </div>
  </div>
</div>

In [18]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">fig</span> <span class="o">=</span> <span class="n">sns</span><span class="o">.</span><span class="n">FacetGrid</span><span class="p">(</span><span class="n">titanic_df</span><span class="p">,</span> <span class="n">hue</span><span class="o">=</span><span class="s2">"Pclass"</span><span class="p">,</span><span class="n">aspect</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>

fig.map(sns.kdeplot,‘Age’,shade= True) oldest = titanic_df[‘Age’].max() fig.set(xlim=(,oldest)) fig.add_legend()

    <div class="output_subarea output_stream output_stderr output_text">
      <pre>/home/tsu-nera/anaconda3/lib/python3.6/site-packages/statsmodels/nonparametric/kdetools.py:20: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future

y = X[:m/2+1] + np.r_[0,X[m/2+1:],0]*1j

  <div class="output_area">
    <div class="prompt output_prompt">
      Out[18]:
    </div>

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;seaborn.axisgrid.FacetGrid at 0x7f193f238208&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/1716019788b55655778ec18831b54e9c.png" />
    </div>
  </div>
</div>

それぞれの乗客はどのデッキにいたか(Cabin)?

  <p>
    Cabinは Nanが多いので、これを取り除く。Cabinは頭文字(Cxx, Dxx, Exx など)でレベル別に分けられるので、レベル別に見てみる。
  </p>
</div>

In [19]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">deck</span> <span class="o">=</span> <span class="n">titanic_df</span><span class="p">[</span><span class="s1">'Cabin'</span><span class="p">]</span><span class="o">.</span><span class="n">dropna</span><span class="p">()</span>

In [23]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">levels</span> <span class="o">=</span> <span class="p">[]</span>

for level in deck: levels.append(level[]) cabin_df = DataFrame(levels) cabin_df.columns = [‘Cabin’] sns.countplot(‘Cabin’,data=cabin_df,palette=‘winter_d’,order=sorted(set(levels)))

Out[23]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;matplotlib.axes._subplots.AxesSubplot at 0x7f193f0ce780&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/0bfa7bd5bc987b02fdd1c4af6558cc2b.png" />
    </div>
  </div>
</div>

A,B,C,D,E,F,G… T と T が外れ値となっている(間違ったデータ??)ので、Tを取り除く。

In [24]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">cabin_df</span> <span class="o">=</span> <span class="n">cabin_df</span><span class="p">[</span><span class="n">cabin_df</span><span class="o">.</span><span class="n">Cabin</span> <span class="o">!=</span> <span class="s1">'T'</span><span class="p">]</span>

sns.countplot(‘Cabin’,data=cabin_df,palette=‘summer’,order=sorted(set(cabin_df[‘Cabin’])))

Out[24]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;matplotlib.axes._subplots.AxesSubplot at 0x7f193f00ecf8&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/c024cc6b97ab2f8b039a9ee8f305f511.png" />
    </div>
  </div>
</div>

乗客はどこから乗ったか?

  <p>
    Embarkedのカラムを見る。C,Q,S という値は、それぞれCherbourg, Queenstown, Southhampton。Southhamptonが圧倒的におおいことが分かる。
  </p>
</div>

In [25]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">sns</span><span class="o">.</span><span class="n">countplot</span><span class="p">(</span><span class="s1">'Embarked'</span><span class="p">,</span><span class="n">data</span><span class="o">=</span><span class="n">titanic_df</span><span class="p">,</span><span class="n">hue</span><span class="o">=</span><span class="s1">'Pclass'</span><span class="p">)</span>

Out[25]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;matplotlib.axes._subplots.AxesSubplot at 0x7f193efbff60&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/f7d081bd05719cad80c2bc53cb7f6d4b.png" />
    </div>
  </div>
</div>

In [27]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">titanic_df</span><span class="o">.</span><span class="n">Embarked</span><span class="o">.</span><span class="n">value_counts</span><span class="p">()</span>

Out[27]:

    <div class="output_text output_subarea output_execute_result">
      <pre>S    644

C 168 Q 77 Name: Embarked, dtype: int64

ちなみに自分が小学生のとき、タイタニックの音楽を合奏する機会があって、Southhamptonのマーチをリコーダーで演奏した。

  <p>
    <a href="http://www.youtube.com/watch?v=fCPC6-6n5Uo"><img src="http://img.youtube.com/vi/fCPC6-6n5Uo/0.jpg" alt="IMAGE ALT TEXT HERE" /></a>
  </p>
</div>

家族連れか、単身者か?

  <p>
    Aloneのカラムを追加します。
  </p>
</div>

In [30]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">titanic_df</span><span class="p">[</span><span class="s1">'Alone'</span><span class="p">]</span> <span class="o">=</span> <span class="n">titanic_df</span><span class="o">.</span><span class="n">Parch</span> <span class="o">+</span> <span class="n">titanic_df</span><span class="o">.</span><span class="n">SibSp</span>

titanic_df[‘Alone’].loc[titanic_df[‘Alone’] >] = ‘With Family’ titanic_df[‘Alone’].loc[titanic_df[‘Alone’] == ] = ‘Alone’

    <div class="output_subarea output_stream output_stderr output_text">
      <pre>/home/tsu-nera/anaconda3/lib/python3.6/site-packages/pandas/core/indexing.py:141: SettingWithCopyWarning: 

A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy self._setitem_with_indexer(indexer, value)

In [31]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">sns</span><span class="o">.</span><span class="n">countplot</span><span class="p">(</span><span class="s1">'Alone'</span><span class="p">,</span><span class="n">data</span><span class="o">=</span><span class="n">titanic_df</span><span class="p">,</span><span class="n">palette</span><span class="o">=</span><span class="s1">'Blues'</span><span class="p">)</span>

Out[31]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;matplotlib.axes._subplots.AxesSubplot at 0x7f193ef73eb8&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/94b2a136ff9bd372b77372348e344399.png" />
    </div>
  </div>
</div>

単身者がおおい。

In [32]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">titanic_df</span><span class="p">[</span><span class="s2">"Survivor"</span><span class="p">]</span> <span class="o">=</span> <span class="n">titanic_df</span><span class="o">.</span><span class="n">Survived</span><span class="o">.</span><span class="n">map</span><span class="p">({</span><span class="mi"></span><span class="p">:</span> <span class="s2">"no"</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span> <span class="s2">"yes"</span><span class="p">})</span>

sns.countplot(‘Survivor’,data=titanic_df,palette=‘Set1’)

Out[32]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;matplotlib.axes._subplots.AxesSubplot at 0x7f193eef0b70&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/89f48756a8c20b39fbb7dd564e0d8807.png" />
    </div>
  </div>
</div>

大勢の人がなくなっていることがわかる。客室の種類は関係があるのかをみると、3等客室が死亡者が多いことがわかる。

In [33]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">sns</span><span class="o">.</span><span class="n">factorplot</span><span class="p">(</span><span class="s1">'Pclass'</span><span class="p">,</span><span class="s1">'Survived'</span><span class="p">,</span><span class="n">data</span><span class="o">=</span><span class="n">titanic_df</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">])</span>

Out[33]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;seaborn.axisgrid.FacetGrid at 0x7f193f082e10&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/a584fc48dd2faee368d63127ee2d1451.png" />
    </div>
  </div>
</div>

「女性と子供を先に」というポリシーが本当に実施されていたかをみる。グラフを見ると、女性や子供の生存率が高い。

In [34]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">sns</span><span class="o">.</span><span class="n">factorplot</span><span class="p">(</span><span class="s1">'Pclass'</span><span class="p">,</span><span class="s1">'Survived'</span><span class="p">,</span><span class="n">hue</span><span class="o">=</span><span class="s1">'person'</span><span class="p">,</span><span class="n">data</span><span class="o">=</span><span class="n">titanic_df</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">],</span> <span class="n">aspect</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>

Out[34]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;seaborn.axisgrid.FacetGrid at 0x7f193ed63f98&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/4d46ccd0c0c9cdc3a67c660cb14b887b.png" />
    </div>
  </div>
</div>

生存率と年齢の、クラスの関係を見てみると、年齢が高いと生存率が下がる。

In [36]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">generations</span><span class="o">=</span><span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="mi">20</span><span class="p">,</span><span class="mi">40</span><span class="p">,</span><span class="mi">60</span><span class="p">,</span><span class="mi">80</span><span class="p">]</span>

sns.lmplot(‘Age’,‘Survived’,hue=‘Pclass’,data=titanic_df,palette=‘winter’, x_bins=generations,hue_order=[1,2,3])

Out[36]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;seaborn.axisgrid.FacetGrid at 0x7f193f0ddac8&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/a81c169dfff765508baed3e42d6f04f8.png" />
    </div>
  </div>
</div>

性別と年齢の関係もみる。

In [37]:
<div class="inner_cell">
  <div class="input_area">
    <div class=" highlight hl-ipython3">
      <pre><span class="n">sns</span><span class="o">.</span><span class="n">lmplot</span><span class="p">(</span><span class="s1">'Age'</span><span class="p">,</span><span class="s1">'Survived'</span><span class="p">,</span><span class="n">hue</span><span class="o">=</span><span class="s1">'Sex'</span><span class="p">,</span><span class="n">data</span><span class="o">=</span><span class="n">titanic_df</span><span class="p">,</span><span class="n">palette</span><span class="o">=</span><span class="s1">'winter'</span><span class="p">,</span><span class="n">x_bins</span><span class="o">=</span><span class="n">generations</span><span class="p">)</span>

Out[37]:

    <div class="output_text output_subarea output_execute_result">
      <pre>&lt;seaborn.axisgrid.FacetGrid at 0x7f193ecdac88&gt;</pre>
    </div>
  </div>

  <div class="output_area">
    <div class="prompt">
    </div>

    <div class="output_png output_subarea ">
      <img src="http://futurismo.biz/wp-content/uploads/fb35b6ecad305e6d0e026ca7ec9bb145.png" />
    </div>
  </div>
</div>

まとめ

  • 男性が女性よりも多い。
  • 女性や子供は男性よりも生存率が高い。(-> personがfactor候補)
  • サウサンプトンからの乗客が多い。
  • 高齢者ほど生存率が低い(->Ageがfactor候補)
  • クラスが高いほど生存率が高い(-> PClassがfactor候補)
  • 単身者が多い

以上を踏まえてKaggle再挑戦

以上から、前回の特徴量を見直して、Kaggle再挑戦しました。

その結果は、5759位でした。

You advanced 305 places on the leaderboard!

Your submission scored 0.75598, which is an improvement of your previous score of 0.74163. Great job!

300人抜きしたけれども、まだまだ改善が必要です。

01 May 2017, 06:36

Kaggle のタイタニック問題に Keras で挑戦した。前処理が課題だと分かった。

Kaggle のタイタニック問題に Keras で挑戦しました。

前置き

タイタニック問題は、Kaggle の看板コンペということで、いろんな人が挑戦している。

自分も早くデータサイエンティストになりたいので、登竜門であるコンペに挑戦してみた。

タイトルが、Titanic: Machine Learning from Disaster とある通り、機械学習を 使って問題を解くことが求められているのだけれども、自分の ToolBox には、 ニューラルネットワーク一本槍しかない。

他の手法も身につけたいのだけれども、他にも手を出すと知識が発散してしまうので、 今はニューラルネットワークひとつにかけている。

最近 Keras をいじりはじめたので、Keras でニューラルネットワークを組んで問題に挑戦してみた。

考察

モデルのチューニングが難しい。

以下のようなモデルを組んでみたのだけれども、精度が 75%。 これで上位 90% という惨憺たる結果。

# create model
model = Sequential()
model.add(Dense(64, input_shape=(8,)))

for i in range(0, 8):
    model.add(Dense(units=64))
    model.add(Activation('relu'))

model.add(Dense(units=1))
model.add(Activation('linear'))

model.compile(loss='mean_squared_error', optimizer='rmsprop')

9 層の Dense レイヤ(Relu 関数で activate) のあとに、1 ノードの出力層を設けた。 コスト関数は、最小二乗誤差、最適化手法は RMSProp.

Bach Norm や Dropout 層を入れることも検討したのだけれども、そうすると精度が下がる。 この設計以上にシンプルにしたり、複雑にしてみたりしたのだけれども、精度が下がる。

チューニング方法が試行錯誤なので、難しい。いい方法がないか、考察中。 チューニングにベストプラクティスはあるのだろうか?直感に頼るしかないのだろうか? 経験を積めば、知識が増えて、いい方法がすぐに思いついたりするのだろうか?

前処理はズルをしました

どういう特徴量を使うかは、以下の記事を参考(パクリ)にしました。

本当は、以下のようなデータ分析をしてデータの傾向を見る必要があるのだけれども、 そういうスキルが自分にはまだない。これから時間をかけて身につけていく。

おそらくだけれども、この前処理の段階を改善することで、精度がグンと上がるのだと思う。 Udemy に参考になりそうな講座がいくつかあるので、購入しようか検討中。(追記:セールだったので購入した。1200 円!)

そういう気づきを得られただけでも、今回参加した価値はあったと思う。 とにかく動くことで課題が明確になる。

コード

github に jupyter notebook をアップロードしました。

29 Apr 2017, 22:10

3 つの戦略で Overfitting を撃退!Tensorflow v1.1 を使って CNN で MNIST に挑んだ

はじめに

fast.ai の Practical Deep Learning for Coders を受けてます。week3 のテーマは overfitting. いかにして、overfitting を防いで精度を向上させるかという話。 理論のあと実際の MNIST のデータを使って精度を向上させるレクチャーがあった。

先週、ちょうど Kaggle の手書き数字認識に挑戦していたので、 今回習ったことを Kaggle に適用してみて、精度が実際どうなるか見てみました。

また、先週 tensorflow 1.1 がリリースされて、 TensorFlow から Keras の機能が使えるようになったので、 それも試してみました。

結論から書くと、1050 位から 342 位への大躍進!上位 20%に近づきました。

Overfitting を防ぐ戦略

Overfitting とは

まずは、Overfitting についておさらい。過学習ともいう。

Overfitting とは、訓練データの精度はいいのだけれども未知のデータの精度が悪いこと。 モデルが汎化されていない状態を指す。

どうやって、確認するかというと、訓練データの他に Validation データを用意して Training のときに、訓練データと validation データの精度を出す。 もし、訓練データの精度がいいけれども、validation データの精度が悪いと Overfitting が起こっている可能性が高い。

Overfitting

OverFitting を防ぐ戦略

講義の中では、以下のステップで対策することが示される。

  1. Add more data
  2. Use data augmentation
  3. Use architectures that generalize well
  4. Add regularization
  5. Reduce architecture complexity.

とくに、2 と 4 に関して、実践的な手法である

が示される。

Dropout

階層の深いニューラルネットワークを精度よく最適化するために Hinton 教授 たちによって提案された手法。

その手法とは、ニューロンをランダムに消去しながら学習する手法。 訓練時に隠れ層のニューロンをランダムに選び出し、 その選び出したニューロンを消去する。

こんな手法で過学習を防げるのかとはじめは驚いたものの、 確かにこれで精度が出るのだ。

今回は、以下のクラスを利用した。

Data Augmentation

画像データを妥当な修正を加えることで、追加合成データを作成すること。 たとえば、ひっくり返したり、回したり、ズームしたり、クリッピングしたり、 色を変更したりなどなど。

参考:

Tensorflow(keras)には、ImageDataGenerator というクラスがあり、これを利用する。

Bach Normalization

Bach Normalization とは、 各層でのアクティベーションの分布を適度な広がりを持つように調整すること。

前処理として、データを加工することはよくやることだけれども、 アクティベーションされた分布に処理を加えることが特徴。これによって、

などの利点がある。

Tensorflow(keras) では、以下のクラスがある。

MNIST に挑戦

今回は、以下の Keras(backend は Theano)を Tensorflow v1.1 にポーティングした。

今回作成した、自分の Jupyter Notebook は以下。

以下、コードの抜粋を以下に示す。

まずは、import。tensorflow.contrib.keras.python.keras と書く。 この書き方がわからずハマった。

import tensorflow as tf
from tensorflow.contrib.keras.python.keras.models import Sequential
from tensorflow.contrib.keras.python.keras.layers import Flatten, Dense, Dropout, Lambda, Conv2D, BatchNormalization, MaxPool2D
from tensorflow.contrib.keras.python.keras.optimizers import Adam
from tensorflow.contrib.keras.python.keras.preprocessing.image import ImageDataGenerator

ネットワークを構成。ちょくちょく BatchNormalization の層が入っているところがポイント。 Dropout 層も出口のところに設けてある。

def get_model_bn_do():
    model = Sequential()
    model.add(Lambda(norm_input, input_shape=(28,28,1)))
    model.add(Conv2D(filters=32,kernel_size=(3,3), activation='relu'))
    model.add(BatchNormalization(axis=1))
    model.add(Conv2D(filters=32,kernel_size=(3,3), activation='relu'))
    model.add(MaxPool2D())
    model.add(BatchNormalization(axis=1))
    model.add(Conv2D(filters=64,kernel_size=(3,3), activation='relu'))
    model.add(BatchNormalization(axis=1))
    model.add(Conv2D(filters=64,kernel_size=(3,3), activation='relu'))
    model.add(MaxPool2D())
    model.add(Flatten())
    model.add(BatchNormalization())
    model.add(Dense(512, activation='relu'))
    model.add(BatchNormalization())
    model.add(Dropout(0.5))
    model.add(Dense(10, activation='softmax'))
    model.compile(Adam(), loss='categorical_crossentropy', metrics=['accuracy'])
    return model

以下のようなネットワークができあがる。

Layer (type)                 Output Shape              Param #   
=================================================================
lambda_1 (Lambda)            (None, 28, 28, 1)         0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 26, 26, 32)        320       
_________________________________________________________________
batch_normalization_1 (Batch (None, 26, 26, 32)        104       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 24, 24, 32)        9248      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 12, 12, 32)        0         
_________________________________________________________________
batch_normalization_2 (Batch (None, 12, 12, 32)        48        
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 10, 10, 64)        18496     
_________________________________________________________________
batch_normalization_3 (Batch (None, 10, 10, 64)        40        
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 8, 8, 64)          36928     
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 4, 4, 64)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 1024)              0         
_________________________________________________________________
batch_normalization_4 (Batch (None, 1024)              4096      
_________________________________________________________________
dense_1 (Dense)              (None, 512)               524800    
_________________________________________________________________
batch_normalization_5 (Batch (None, 512)               2048      
_________________________________________________________________
dropout_1 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 10)                5130      
=================================================================
Total params: 601,258.0
Trainable params: 598,090.0
Non-trainable params: 3,168.0

data augmentation を ImageDataGenerator で実施する。 パラメータでいろいろ変更できるようになっている。

gen = ImageDataGenerator(rotation_range=8, width_shift_range=0.08, shear_range=0.3,
                            height_shift_range=0.08, zoom_range=0.08)
batches = gen.flow(features, labels, batch_size=batch_size)
test_batches = gen.flow(valid_features, valid_labels, batch_size=batch_size)

fit_generator で学習。ちなみに、train_on_batch 関数だと、メモリ枯渇を起こした。

model.fit_generator(batches, batches.n//batch_size, epochs=1,
                    validation_data=test_batches, validation_steps=test_batches.n//batch_size)

predict_classes 関数でテストデータを予測。

classes = model.predict_classes(test_features)

26 Apr 2017, 07:22

Vgg16 モデルを使って Kaggle の Dogs vs Cats をやってみた

fast.ai の Practical Deep Learning for Coders の week2 の課題で、 勉強の理解のために、スクラッチで教えた内容を自分で実装してみてねと書かれていたので、やってみた。

はじめに

Practical Deep Learning for Coders では、 Kaggle の Compatition Dogs vs. Cats Redux| Kaggle に参加することが課題に課せられるのだが、 week1 でいきなり、上位 50% に入ってねという課題が出される。

無理だよ!と思ったのだけれども、week2 で上位 50%に入るための種明かしをしてくれる。 それが、vgg16 モデルを使った fine-tuning による転移学習。これについては、以下の記事がとても参考になった。

課題をスクラッチではなく(できないので)、与えられたコードコピペしまくりでなんとか実装してみた。元ネタこれ。

今回の課題の jupyter notebook は github に あるので、ここではコードを抜粋して載せる。

実装の抜粋

Rearrange image files into their respective directories

まずは、kaggle からデータを持ってきて、以下のようなディレクトクリ構造をつくる。 分類クラスごとにサブディレクトリ(dogs, cats, unknown)を作ることによって、 Keras の ImageDataGenerator がうまいこと処理してくれる。

├── test
│   └── unknown
├── train
│   ├── cats
│   └── dogs
└── valid
    ├── cats
    └── dogs

Finetune and Train model

VGG モデルを作成する。

def ConvBlock(layers, model, filters):
    for i in range(layers):
        model.add(ZeroPadding2D((1,1)))
        model.add(Convolution2D(filters, 3, 3, activation='relu'))
    model.add(MaxPooling2D((2,2), strides=(2,2)))

def FCBlock(model):
    model.add(Dense(4096, activation='relu'))
    model.add(Dropout(0.5))
# Mean of each channel as provided by VGG researchers
vgg_mean = np.array([123.68, 116.779, 103.939]).reshape((3,1,1))

def vgg_preprocess(x):
    x = x - vgg_mean     # subtract mean
    return x[:, ::-1]    # reverse axis bgr->rgb

def VGG_16():
    model = Sequential()
    model.add(Lambda(vgg_preprocess, input_shape=(3,224,224)))
    ConvBlock(2, model, 64)
    ConvBlock(2, model, 128)
    ConvBlock(3, model, 256)
    ConvBlock(3, model, 512)
    ConvBlock(3, model, 512)
    model.add(Flatten())
    FCBlock(model)
    FCBlock(model)
    model.add(Dense(1000, activation='softmax'))
    return model


def finetune(model, num_classes):
    # remove last layer
    model.pop()
    # set all layers untrainable.
    for layer in model.layers: layer.trainable=False
    # add new layer
    model.add(Dense(num_classes, activation='softmax'))
    model.compile(optimizer=Adam(lr=0.001),
                loss='categorical_crossentropy', metrics=['accuracy'])
    return model

def get_batches(path, dirname, gen=image.ImageDataGenerator(), shuffle=True,
                batch_size=64, class_mode='categorical'):
    return gen.flow_from_directory(path+dirname, target_size=(224,224),
                class_mode=class_mode, shuffle=shuffle, batch_size=batch_size)

そして、学習済みの重みを fast.ai のサーバから手に入れる。

wget http://files.fast.ai/models/vgg16.h5

ここ からもダウンロードできる。

なお、keras1.2.0 では、ここによると、 VGG16 モデルが keras.applications.vgg16 モジュールに実装されているらしい。

つまり、自分のやり方は古いということだ!!

model = VGG_16()

# load pre-trained weights!!!
model.load_weights('vgg16.h5')

# remove last layer and add new layer
ftmodel = finetune(model, 2)

print ftmodel.summary() で 最後の層に出力が 2 のレイヤが追加されたことを確認する。

dense_4 (Dense)                  (None, 2)             8194        dropout_2[0][0]                  

追加した層を犬猫判定ように調整する。

batch_size=64
path = DATA_HOME_DIR

batches = get_batches(path,'train', batch_size=batch_size)
val_batches = get_batches(path,'valid', batch_size=batch_size)

# train finetuned model(only last layer)
no_of_epochs=1

for epoch in range(no_of_epochs):
    print "Running epoch: %d" % epoch
    ftmodel.fit_generator(batches, samples_per_epoch=batches.nb_sample, nb_epoch=1,
                validation_data=val_batches, nb_val_samples=val_batches.nb_sample)
    latest_weights_filename = 'ft%d.h5' % epoch
    ftmodel.save_weights(latest_weights_filename)

Generate predictions

test データから犬猫の確率を推測。preds には[猫,犬]とデータが入っている。

test_batches = get_batches(path, 'test', batch_size=2*batch_size, class_mode=None)
preds = ftmodel.predict_generator(test_batches, test_batches.nb_sample)