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

便利だ。素晴らしい。

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

01 Sep 2017, 09:56

Pythonではじめる機械学習(scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎)を読んだ

O’Reilly Japan – Pythonではじめる機械学習 を読んだ。

副題: scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎

動機

ニューラルネットを学ぶ、その前に

今まで、機械学習を通り越してディープラーニングの勉強をしてきた。

つまり基礎をすっ飛ばして、応用にいってしまったのだ。

自分の手法はただひとつ、ニューラルネットワークのみ!!

これでは、機械学習を勉強しているといえるのだろうか?

自分のなかで、疑問が湧き上がった。

本に付いている帯が印象的だった。

ニューラルネットワークを学ぶ、その前に! とのことだ。

これだ!ニューラルネットを学んで、

その後に行ってしまった自分にとってはこの帯はまさに心のうちをいい得ているものだった。

機械学習コンペの壁

ニューラルネットを学んで機械学習コンペに挑もうとしても、

前処理でなにをすればいいのかわからず手が出ない。

前処理は、特徴量エンジニアリングというらしいことを最近知った。

なので、前処理を詳しく解説している書籍はないものかと探していた。

この本の副題は、特徴量エンジニアリングと機械学習の基礎。これだ。

本の特徴

scikit-learnについての実践書

本書は、scikit-learnを使って機械学習をするための実践書だ。

機械学習の難しい理論は、でてこない。

そういう難解なものは、scikit-learnがすべて隠蔽してくれる。

この本では、機械学習アルゴリズムの利点と欠点、

ライブラリのパラメータの調整方法という実践的な知識が載っている。

また、ライブラリの使い方以外のことも書いてある。ズバリ、特徴量エンジニアリング。

どうやって、カテゴリカルデータやフラグデータをどうやってscikit-learnで扱うか、

数学はでてこない

本書は、微分積分、線形代数、確率論を何年も

学ぶことなく機械学習を使いたいという人のための特攻薬だ。

数学は一切出てこない。各機械学習の手法を言葉でわかりやすく説明している。

今、平行して機械学習のための数学の基礎固めを進めているのだけれども、

自分がなにをしたいかを考えた時、理論をガチガチにかためてなにもコーディングできないよりも、

Kaggleでバリバリデータ分析をしたいという思いがあった。

そこで、まずはscikit-learnで機械学習の概要を掴み、

Kaggleに積極的に挑み、理論は後付で学んでいく計画を立てた。

理論よりはコードファーストを目指す人にはオススメの本だ。

scikit-learnをつかった機械学習コンペ対策に

本の前半で教師あり学習と教師なし学習のアルゴリズムが解説されている。

残りの半分はなにが書いてあるかというと、

  • 特徴量エンジニアリング
  • モデルの評価方法
  • 交差検証、他
  • グリッドサーチを使ったパラメータチューニング方法
  • パイプラインを使った効率的なコーディング
  • テキストデータの扱い方

など、機械学習コンペに必要な技が細かく書いてある。

概要を説明したあと、scikit-learnをつかえばこんなふうにかけますよと、

実例を通して学ぶことができる。

学習できるアルゴリズムは豊富

たくさんのアルゴリズムが紹介されている。

それぞれ、どんな利点と欠点があるか、どういう場面で使うべきかが書かれている。

たとえば、教師あり学習のアルゴリズムを本書より抜粋。

  • 最近傍法: 小さいデータに関しては良いベースラインとなる。 説明が容易。
  • 線形モデル: 最初に試してみるべきアルゴリズム。 非常に大きいデータセットに適する。 非常に高次元のデータに適する。
  • ナイーブベイズ: クラス分類にしか使えない。 線形モデルよりもさらに高速。 非常に大きいデータセット、 高次元データに適する。 線形モデルより精度が劣ることが多い。
  • 決定木: 非常に高速。 データのスケールを考慮する必要がない。 可視化が可能で説明しやすい。
  • ランダムフォレスト: ほとんどの場合単一の決定木よりも高速で、 頑健で、 強力。 データのスケールを考慮する必要がない。 高次元の疎なデータには適さない。
  • 勾配ブースティング決定木: 多くの場合ランダムフォレストよりも少し精度が高い。 ランダムフォレストよりも訓練に時間がかかるが、 予測はこちらのほうが速く、 メモリ使用量も小さい。 ランダムフォレストよりもパラメータに敏感。
  • サポートベクタマシン: 同じような意味を持つ特徴量からなる中規模なデータセットに対しては強力。 データのスケールを調整する必要がある。 パラメータに敏感。
  • ニューラルネットワーク: 非常に複雑なモデルを構築できる。 特に大きなデータセットに有効。 データのスケールを調整する必要がある。 パラメータに敏感。 大きいモデルは訓練に時間がかかる。

また、教師なしアルゴリズムでは、以下のようなアルゴリズムが紹介される。

  • データセットの変換 ・・・PCA, NMF, t-SME
  • クラスタリング ・・・ k-means, 凝集型、DBSCAN

終わりに

機械学習の理論は難しいので、とりあえずscikit-learnを使って実際に動かすことで、

感覚をつかむというのはいい方法だと思う。

xgboostとかをはじめに知ってしまうと、理論は知らなくても万能感が得られたりする。

ただ、深く応用するためには理論も抑えていくことが大事なので、

自分はこれからはじめてのパターン認識を次に読んでいこうと思った。

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のほうが向いている。