第二回:Ensemble Model - Gradient Boosted Decistion Trees(GBDT)
概要
引き続いてMachine Learning のEnsemble Model。Gradient Boosted Decision Trees
Gradient-Boosted Decision Trees(GBDT)
連続したいくつもの小さいDecision Tree。Decision Treeごとに前回のDecision Treeのエラーを修正していく。一方、Random Forestsは並行したいくつものDecision Treeでそれぞれ独立している。
最も多く使われるMachine Learning Model。
後述のようにLearning Rateが最も大事なパラメータ。
Pros and Cons
Pros
- 既存のパッケージの中で多くの対象に汎用的に最も高いAccuracyをたたき出す
- メモリの使用量がそれほど高くなく、計算が速い
- 特徴量に対して正規化が必要でない
- Decision Treeと同様に、多種多様な特徴量を加工なく使える
Cons
- Random Forestsと同様に、モデルの解釈が難しい
- Learning Rateやその他のパラメータのチューニングが必要
- 学習のための計算量が大きい
- Decision Treeと同様にText Classificationのような多次元の特徴量の取り扱いがうまくない
Structure
sklearn.ensemble.GradientBoostingClassifier(loss='deviance', learning_rate=0.1, n_estimators=100, subsample=1.0, criterion='friedman_mse', min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_depth=3, min_impurity_decrease=0.0, min_impurity_split=None, init=None, random_state=None, max_features=None, verbose=0, max_leaf_nodes=None, warm_start=False, presort='deprecated', validation_fraction=0.1, n_iter_no_change=None, tol=0.0001, ccp_alpha=0.0)
from sklearn.ensemble import GradientBoostingClassifier
主なParameters
n_estimatorsとlearning_rateはセットで調整する
Parameters | Description |
learning_rate | 前回のTreeからエラーを修正する High: More complex model, overfitting Low: simpler model (Default = 0.1) |
n_estimators | 連続させるDecision Treeの個数。 (Default = 100) |
max_depth | 各Treeの最大深度。通常は小さな値(3-5) (Default = 3) |
Usage
%matplotlib notebook from sklearn.ensemble import GradientBoostingClassifier from sklearn.model_selection import train_test_split from sklearn.datasets import make_blobs from adspy_shared_utilities import plot_class_regions_for_classifier_subplot #パッケージ import matplotlib.pyplot as plt X_D2, y_D2 = make_blobs(n_samples = 100, n_features = 2, centers = 8, cluster_std = 1.3, random_state = 4) y_D2 = y_D2 % 2 X_train, X_test, y_train, y_test = train_test_split(X_D2, y_D2, random_state=0) fig, subaxes = plt.subplots(1,1,figsize = (6,6)) clf = GradientBoostingClassifier(learning_rate=0.01, max_depth=2).fit(X_train, y_train) title = 'GBDT, complex binary dataset, default settings' plot_class_regions_for_classifier_subplot(clf, X_train, y_train, X_test, y_test, title, subaxes) plt.show()
第一回:Ensemble Model - Random Forestsとはなんぞや
Ensemble Model
たくさんのMahcine Learning Model をたばねたもの。ひとつひとつにのOverfittingのような問題があっても、全体としては安定。
サンプルはBootstrapによって集められる。
Random Forests
Decision Tree をいくつも束ねたもの。それぞれのTreeではRandom_stateによって異なるモデルが生成される。
singapp.hatenablog.com
Regression: それぞれのtreeのaverage
Classification: それぞれのtreeが返すprobabilityのaverage, 最後に最も高いprobabilityで予想する
Pros and Cons
Pros
- Normalization やParameterのチューニングが必要ない
- 簡単で幅広い対象に対してすごくよいパフォーマンス
- 並列処理化が簡単
Cons
- できたモデルの解釈が困難
- text classififationのような高次の処理が得意でない
Structure
- Classification: RandomForestClassifier
sklearn.ensemble.RandomForestClassifier(n_estimators=100, criterion='gini', max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False, n_jobs=None, random_state=None, verbose=0, warm_start=False, class_weight=None, ccp_alpha=0.0, max_samples=None)
- Regression: RansomForestRegressor
sklearn.ensemble.RandomForestRegressor(n_estimators=100, criterion='mse', max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, bootstrap=True, oob_score=False, n_jobs=None, random_state=None, verbose=0, warm_start=False, ccp_alpha=0.0, max_samples=None)
Parmeters
decistion treeとだいたい同じだがmax_featuresが一番大事
Parameter | Description |
max_features | i.e. set as 1: ランダムに選ばれた特徴量が一つだけ使われる→more complex set as close to the number of features: 通常のDecision Treeと同じようになる (Default = 'auto') |
n_estimators | ensembleで何個のTreeを使うか (Default = 10) |
max_depth | 各Treeの深さ (Default = 'None') |
n_jobs | 何個のCPU coreを学習中に使うか |
random_state | 再現性のために毎回同じ特定の値を使うこと |
Usage
from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.datasets import make_classification, make_blobs import matplotlib.pyplot as plt X_D2, y_D2 = make_blobs(n_samples = 100, n_features = 2, centers = 8, cluster_std = 1.3, random_state = 4) X_train, X_test, y_train, y_test =train_test_split(X_D2, y_D2, random_state=0) fig , subaxes=plt.subplots(1,1, figsize=(6,6)) clf = RandomForestClassifier().fit(X_train, y_train) title = 'Random Forest Classifier, complex binary dataset, default settings' plot_class_regions_for_classifier_subplot(clf, X_train, y_train, X_test, y_test, title, subaxes) plt.show()
続Python Machine Laerning Models
モデルの書き忘れ.
Logistic Regression, Decision Tree
singapp.hatenablog.com
Logistic Regression
非線形回帰の一種。 各説明変数を入れると0から1間の値、つまり確率分布を返す。
これを使ってBinary Classificationを行う。(ある確率以上は1という判断)
Structure
sklearn.linear_model.LogisticRegression(penalty='l2', dual=False, tol=0.0001, C=1.0, fit_intercept=True, intercept_scaling=1, class_weight=None, random_state=None, solver='lbfgs', max_iter=100, multi_class='auto', verbose=0, warm_start=False, n_jobs=None, l1_ratio=None)
from sklearn.linear_model import LogisticRegression
Parameters
Parameter | Discription |
Penalty | 説明変数自体の大きさによりモデル内での重みが変わってしまうので、正規化する必要がある。ここで説明変数の標準化の手法を選択 ['l1' or 'l2'] L1は絶対値をとり、小さい説明変数への重みがゼロになる。 (Default as l2) |
C | 正則化の速さ(強さ)を指定する。RidgeやLassoのαと逆向き。 Lower: more regularization, simpler model Larger: less regulalization, more complex model -> overfitting (Default as 1.0) |
random_state | random generatorのseed 毎回同じのを使うとよい |
Sample
from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X_fruits, y_fruits, random_state=0) clf = LogisticRegression(C=this_C).fit(X_train, y_train)
Decision Tree
条件分岐によってグループを分割していく。一回の分岐で一つのグループをきれいに抽出できるとスコアが高い(不純度)。
Structure
sklearn.tree.DecisionTreeClassifier(criterion='gini', splitter='best', max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None, random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, class_weight=None, presort='deprecated', ccp_alpha=0.0)
from sklearn.tree import DecisionTreeClassifier
主なParameters
Parameter | Discription |
Criterion | 分割基準、'gini' or 'entropy' (Default = 'gini') |
max_depth | Treeの最大深度 多すぎるとoverfitting (Default = None) |
min_samples_split | 分岐する際の最低サンプル量 (Default = 2) |
min_samples_leaf | Leaf nodeでの最低サンプル量 (Default = 1) |
ほかのは
scikit-learn.org
Sample
from sklearn.datasets import load_iris from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import train_test_split iris = load_iris() X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state = 3) clf = DecisionTreeClassifier(max_depth = 3,min_samples_leaf = 8, random_state = 0).fit(X_train, y_train)
Visualization
sklearn.tree.export_graphviz(decision_tree, out_file=None, max_depth=None, feature_names=None, class_names=None, label='all', filled=False, leaves_parallel=False, impurity=True, node_ids=False, proportion=False, rotate=False, rounded=False, special_characters=False, precision=3)
import pydotplus from IPython.display import Image from graphviz import Digraph from sklearn.externals.six import StringIO dot_data = StringIO() tree.export_graphviz(clf, out_file=dot_data,feature_names=train_X.columns, max_depth=3) graph = pydotplus.graph_from_dot_data(dot_data.getvalue()) graph.write_pdf("graph.pdf") Image(graph.create_png())
Feature importance
どの変数が重要だったかを返すメソッド
clf.feature_importances_)
その他のLinear Classifier - Naive Bayes Classifiers
その他のLinear ClassifierとしてNaive Bayes Classifiersがある
Naive Bayes Classifiers
特徴量間で独立となる確率分布を用いて事後確率が最大となるクラスに分類する。単純で高速なため、他のモデルを評価するbaseとして使われる。
一般的な分析対象の特徴量間では通常はなんらかの関係性が見いだされるため、モデルのあてはまりはよくない。Text Classificationに使われる。
確率分布によって3種類用意されている
- Bernoulli Naive Bayes
- Multinomial Naive Bayes
- Gaussian Naive Bayes
Bernoulli Naive Bayes
ベルヌーイ分布を仮定する。つまり2項分布。
Multinomial Naive Bayes
多項分布
Gaussian Naive Bayes
Strucuture
sklearn.naive_bayes.GaussianNB(priors=None, var_smoothing=1e-09
from sklearn.naive_bayes import GaussianNB
Modelの選び方 - k分割交差検証(k-fold Cross Validation by Validation Curve)とグリッドサーチ(Grid Search)
どのようにModelを選ぶか
- Validation Curveを使って仮定した選んだModelに対して、サンプルのとり方の影響を排除した評価値をだす
- よさげなModelについてGrid Searchにより最適なparemeterを導出
- 最適なparameterでもう一回Validation Curveを使ってModel間の評価をする
Validation Curveを使う
下記で取り上げたようにValidation Curveを使うことで、サンプルのとり方による影響を排除したModelの評価値(Accuracy, Precision等)を導出できる。ホールドアウト法(train_test_split)と比べて小さいデータの時に有効
singapp.hatenablog.com
Structure
sklearn.model_selection.cross_val_score(estimator, X, y=None, groups=None, scoring=None, cv=None, n_jobs=None, verbose=0, fit_params=None, pre_dispatch='2*n_jobs', error_score=nan)
from sklearn.model_selection import validation_curve
主なParameters
Parameters | Description |
scoring | 評価値を選択 accuracy, roc_aucとか sklearn.metricsの関数を選択できる |
cv | データセットの分割個数 |
Usage
- Model のオブジェクトを作成(SampleではDecisionTree)
- Grcross_val_scoreオブジェクトを作成し、Modelを学習データとともに渡す
- 各思考のscoreを取得
- 「平均+/-標準偏差」をこのModelの評価値として用いる
Sample
from sklearn.datasets import load_breast_cancer from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import cross_val_score cancer = load_breast_cancer() cn_data = pd.DataFrame(cancer.data, columns=cancer.feature_names) cn_target= pd.Series(cancer.target) tree = DecisionTreeClassifier(criterion='gini', max_depth=5, random_state=0) scores = cross_val_score(tree, cn_data, cn_target, cv=5) print('Cross Validation Scores: {}'.format(scores)) print('Cross Validation Mean: {:.3f}'.format(scores.mean())) print('Cross Validation Standard Deviation: {:.3f}'.format(scores.std())) print('Cross Validation Score Range: {:.3f}+/-{:.3f}'.format(scores.mean(), scores.std()))
Furthermore
scoringに複数の指標を同時に使いたいときはcross_val_scoreのかわりにcross_validateを使う
from sklearn.model_selection import cross_validate
選択可能なscoring parameter一覧はこちら
Grid Search
指定したモデルの最適パラメータをいろんな評価値で計算する。
Structure
sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None, n_jobs=None, iid='deprecated', refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', error_score=nan, return_train_score=False)
from sklearn.model_selection import GridSearchCV
主なParameters
Parameters | Description |
estimator | 評価するモデル SVCとか |
param_grid | 探索するパラメータ |
scoring | 評価値を選択 accuracy, roc_aucとか |
cv | 試行回数 |
Usage
- GridSearchCVオブジェクトを作成
- GridSearchCV.fit()に学習データを渡す
- 最もよいパラメータを取得 best_estimator_
Sample
from sklearn.svm import SVC from sklearn.model_selection import GridSearchCV from sklearn.metrics import roc_auc_score from sklearn.datasets import load_digits dataset = load_digits() X, y = dataset.data, dataset.target == 1 X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0) clf = SVC(kernel='rbf') grid_values = {'gamma': [0.001, 0.01, 0.05, 0.1, 1, 10, 100]} # default metric to optimize over grid parameters: accuracy grid_clf_acc = GridSearchCV(clf, param_grid = grid_values) grid_clf_acc.fit(X_train, y_train) y_decision_fn_scores_acc = grid_clf_acc.decision_function(X_test) print('Grid best parameter (max. accuracy): ', grid_clf_acc.best_params_) print('Grid best score (accuracy): ', grid_clf_acc.best_score_) # alternative metric to optimize over grid parameters: AUC grid_clf_auc = GridSearchCV(clf, param_grid = grid_values, scoring = 'roc_auc') grid_clf_auc.fit(X_train, y_train) y_decision_fn_scores_auc = grid_clf_auc.decision_function(X_test) print('Test set AUC: ', roc_auc_score(y_test, y_decision_fn_scores_auc)) print('Grid best parameter (max. AUC): ', grid_clf_auc.best_params_) print('Grid best score (AUC): ', grid_clf_auc.best_score_)
続続続Modelの評価 - ROC曲線とAUC
予測確率を用いたClassification Modelの評価
Confusion MatrixではPredicted Label (予測ラベル as 0 or 1)を用いてモデルを評価した。しかし、Predict Probability (予測確率)→Predicted Labelへと写すthreshold(閾値)が事前には決められるとは限らない。そこで、Predict Probabilityそのものからモデルを評価する場合にROC曲線とAUCが役に立つ
Confusion matrixはこちら
singapp.hatenablog.com
Receiver Operating Characteristic (ROC)
False Positive RateとTrue Positive Rateのthreshold =閾値(0-1)ごとの組み合わせ。
- False Positive Rate: Precisionの余事象→ 横軸
- True Positive Rate: Recall→ 縦軸
Structure
from sklearn.metrics import roc_curve fpr_lr, tpr_lr, _ = roc_curve(y_test, y_score_lr)
Output
- fpr_lr: False Positive Rate
- tpr_lr: True Positive Rate
グラフが左上に近いほうが良い結果(つまり右下が広い=AUCが大きい)
Sample
from sklearn.svm import SVC from sklearn.datasets import load_breast_cancer from sklearn.metrics import roc_curve cancer = load_breast_cancer() X = pd.DataFrame(cancer.data, columns=cancer.feature_names) y = pd.Series(cancer.target) X_train, X_test, y_train, y_test = train_test_split(X,y, random_state=0) clf = SVC(kernel='rbf', gamma=0.001, C=1, probability=True) #probability = True としないと学習結果に予測確率が含まれない clf.fit(X_train,y_train) y_score_lr = clf.predict_proba(X_test)[:,1] fpr_lr, tpr_lr, _ = roc_curve(y_test, y_score_lr) #threshold は使わないので'_'に取得 #graph plot plt.figure(figsize=(10,6)) plt.plot(fpr_lr, tpr_lr, color ='red', label = 'ROC curve') plt.plot([0,1], [0,1], color = 'black', linestyle ='--') plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.xlabel('False positive rate') plt.ylabel('True positive rate') plt.title('Receiver Operating Characteristic') plt.legend(loc='best') plt.show()
Area Under Curve (AUC)
ROCの下の面積
Structure
from sklearn.metrics import auc sklearn.metrics.auc(x, y)
Sample
from sklearn.metrics import auc auc = auc(fpr_lr, tpr_lr) print ('AUC:{:.3f}'.format(auc))
またはROCと一緒にグラフへ
#ROCのコードの一部を以下のように変更 plt.plot(fpr_lr, tpr_lr, color ='red', label = 'ROC curve (AUC = %.3f)' % auc)
続続Modelの評価 - Precision-Recall Curve (RecallとPrecisionの可視化)
RecallとPrecisioinの可視化
前準備としてDecision Function
SVC等で推定された境界平面からそのアウトプットへの距離。例えばX_testをインプットした時のアウトプット(y_predicted)がどれだけモデルの境界から遠いかを算定する。似たものとしてpredict_proba(0-1にスケーリングしたもの)がある。
(自分にはもう 限界なのでもっとすごい人の説明を参照求む)
Structure
Sklearnモデルのmethodとして
y_scores_lr = lr.fit(X_train, y_train).decision_function(X_test)
Precision-recall curves
decision functionのであらわされる値を閾値(threshold)としてRecallとPrecisionの組み合わせを返す
Structure
precision, recall, thresholds = precision_recall_curve(y_test, y_scores_lr)
from sklearn.metrics import precision_recall_curve
全体をグラフとして可視化する以外に、precision, recall, thresholdの各値をターゲットに他の2つの値を導出
例えば、thresholdsのうち最小なもののインデックスを取り出して
closest_zero = np.argmin(np.abs(thresholds))
それに対応するprecisionを取り出す
closest_zero_p = precision[closest_zero]