Scikit-Learn チュートリアル: インストール方法と Scikit-Learn の例
Scikit-learnとは何ですか?
シキット学習 オープンソースです Python 機械学習用のライブラリ。KNN、XGBoost、ランダムフォレスト、SVM などの最先端のアルゴリズムをサポートしています。NumPy 上に構築されています。Scikit-learn は、Kaggle コンテストや著名なテクノロジー企業で広く使用されています。前処理、次元削減 (パラメーター選択)、分類、回帰、クラスタリング、モデル選択に役立ちます。
Scikit-learn には、すべてのオープンソース ライブラリに関する最良のドキュメントがあります。 インタラクティブなチャートを提供します。 https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html.

Scikit-learn の使用はそれほど難しくなく、優れた結果が得られます。 ただし、scikit learn は並列計算をサポートしていません。 これを使用して深層学習アルゴリズムを実行することは可能ですが、特に TensorFlow の使用方法を知っている場合には、最適なソリューションではありません。
Scikit-learn をダウンロードしてインストールする方法
今これで Python Scikit-learn チュートリアルでは、Scikit-learn をダウンロードしてインストールする方法を学びます。
オプション1: AWS
scikit-learn は AWS 経由で使用できます。 お願いします 参照する scikit-learn がプリインストールされている docker イメージ。
開発者バージョンを使用するには、次のコマンドを使用します。 Jupyter
import sys !{sys.executable} -m pip install git+git://github.com/scikit-learn/scikit-learn.git
オプション2: マックとか Windows アナコンダを使用する
Anaconda のインストールについて詳しくは、以下を参照してください。 https://www.guru99.com/download-install-tensorflow.html
最近、scikit の開発者は、現在のバージョンが直面する一般的な問題に取り組む開発バージョンをリリースしました。 現在のバージョンではなく開発者バージョンを使用する方が便利であることがわかりました。
Conda 環境で scikit-learn をインストールする方法
conda 環境で scikit-learn をインストールした場合は、手順に従ってバージョン 0.20 に更新してください。
ステップ1) tensorflow 環境をアクティブ化する
source activate hello-tf
ステップ2) conda コマンドを使用して scikit lean を削除する
conda remove scikit-learn
ステップ3) 開発者版をインストールします。
scikit learn 開発者バージョンを必要なライブラリとともにインストールします。
conda install -c anaconda git pip install Cython pip install h5py pip install git+git://github.com/scikit-learn/scikit-learn.git
注: Windows ユーザーがインストールする必要があります Microsoft ビジュアル C++ 14. ここから入手できます こちら
機械学習を使用した Scikit-Learn の例
この Scikit チュートリアルは XNUMX つの部分に分かれています。
- scikit-learn による機械学習
- LIME でモデルを信頼する方法
最初の部分では、パイプラインの構築方法、モデルの作成方法、ハイパーパラメータの調整方法について詳しく説明し、2 番目の部分では、モデル選択に関する最先端の情報を提供します。
ステップ 1) データをインポートする
この Scikit 学習チュートリアルでは、アダルト データセットを使用します。
このデータセットの背景については、を参照してください。記述統計について詳しく知りたい場合は、Dive ツールとOverview ツールを使用してください。
参照する このチュートリアル ダイブと概要について詳しく知る
Pandas を使用してデータセットをインポートします。 連続変数の型を float 形式に変換する必要があることに注意してください。
このデータセットには XNUMX つのカテゴリ変数が含まれています。
カテゴリカル変数は CATE_FEATURES にリストされています。
- ワーククラス
- 教育
- 夫婦の
- 職業
- 関係
- レース
- セックス
- 母国
さらに、XNUMX つの連続変数:
連続変数は CONTI_FEATURES にリストされています。
- 年齢
- fnlwgt
- 教育番号
- 資本利得
- 資本損失
- 時間_週
どの列が使用されているかをよりよく理解できるように、リストを手動で入力していることに注意してください。 カテゴリまたは連続のリストをより迅速に作成する方法は、次を使用することです。
## List Categorical CATE_FEATURES = df_train.iloc[:,:-1].select_dtypes('object').columns print(CATE_FEATURES) ## List continuous CONTI_FEATURES = df_train._get_numeric_data() print(CONTI_FEATURES)
データをインポートするコードは次のとおりです。
# Import dataset import pandas as pd ## Define path data COLUMNS = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country', 'label'] ### Define continuous list CONTI_FEATURES = ['age', 'fnlwgt','capital_gain', 'education_num', 'capital_loss', 'hours_week'] ### Define categorical list CATE_FEATURES = ['workclass', 'education', 'marital', 'occupation', 'relationship', 'race', 'sex', 'native_country'] ## Prepare the data features = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country'] PATH = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data" df_train = pd.read_csv(PATH, skipinitialspace=True, names = COLUMNS, index_col=False) df_train[CONTI_FEATURES] =df_train[CONTI_FEATURES].astype('float64') df_train.describe()
年齢 | fnlwgt | 教育番号 | 資本利得 | 資本損失 | 時間_週 | |
---|---|---|---|---|---|---|
カウント | 32561.000000 | 3.256100e + 04 | 32561.000000 | 32561.000000 | 32561.000000 | 32561.000000 |
意味する | 38.581647 | 1.897784e + 05 | 10.080679 | 1077.648844 | 87.303830 | 40.437456 |
STD | 13.640433 | 1.055500e + 05 | 2.572720 | 7385.292085 | 402.960219 | 12.347429 |
分 | 17.000000 | 1.228500e + 04 | 1.000000 | 0.000000 | 0.000000 | 1.000000 |
25% | 28.000000 | 1.178270e + 05 | 9.000000 | 0.000000 | 0.000000 | 40.000000 |
50% | 37.000000 | 1.783560e + 05 | 10.000000 | 0.000000 | 0.000000 | 40.000000 |
75% | 48.000000 | 2.370510e + 05 | 12.000000 | 0.000000 | 0.000000 | 45.000000 |
マックス | 90.000000 | 1.484705e + 06 | 16.000000 | 99999.000000 | 4356.000000 | 99.000000 |
native_country 機能の一意の値の数を確認できます。 オランダ・オランダから来た世帯は XNUMX 世帯だけであることがわかります。 この世帯は私たちに情報を提供しませんが、トレーニング中のエラーによって提供されます。
df_train.native_country.value_counts()
United-States 29170 Mexico 643 ? 583 Philippines 198 Germany 137 Canada 121 Puerto-Rico 114 El-Salvador 106 India 100 Cuba 95 England 90 Jamaica 81 South 80 China 75 Italy 73 Dominican-Republic 70 Vietnam 67 Guatemala 64 Japan 62 Poland 60 Columbia 59 Taiwan 51 Haiti 44 Iran 43 Portugal 37 Nicaragua 34 Peru 31 France 29 Greece 29 Ecuador 28 Ireland 24 Hong 20 Cambodia 19 Trinadad&Tobago 19 Thailand 18 Laos 18 Yugoslavia 16 Outlying-US(Guam-USVI-etc) 14 Honduras 13 Hungary 13 Scotland 12 Holand-Netherlands 1 Name: native_country, dtype: int64
この有益でない行をデータセットから除外できます。
## Drop Netherland, because only one row df_train = df_train[df_train.native_country != "Holand-Netherlands"]
次に、連続フィーチャの位置をリストに保存します。 これは、パイプラインを構築する次のステップで必要になります。
以下のコードは、CONTI_FEATURES 内のすべての列名をループしてその位置 (つまり、その番号) を取得し、それを conti_features というリストに追加します。
## Get the column index of the categorical features conti_features = [] for i in CONTI_FEATURES: position = df_train.columns.get_loc(i) conti_features.append(position) print(conti_features)
[0, 2, 10, 4, 11, 12]
以下のコードは、カテゴリ変数を除いて上記と同じジョブを実行します。 以下のコードは、カテゴリ特徴を除いて、以前に実行したことを繰り返します。
## Get the column index of the categorical features categorical_features = [] for i in CATE_FEATURES: position = df_train.columns.get_loc(i) categorical_features.append(position) print(categorical_features)
[1, 3, 5, 6, 7, 8, 9, 13]
データセットを確認できます。 各カテゴリ特徴は文字列であることに注意してください。 モデルに文字列値を与えることはできません。 ダミー変数を使用してデータセットを変換する必要があります。
df_train.head(5)
実際には、フィーチャ内のグループごとに XNUMX つの列を作成する必要があります。 まず、以下のコードを実行して、必要な列の合計量を計算します。
print(df_train[CATE_FEATURES].nunique(), 'There are',sum(df_train[CATE_FEATURES].nunique()), 'groups in the whole dataset')
workclass 9 education 16 marital 7 occupation 15 relationship 6 race 5 sex 2 native_country 41 dtype: int64 There are 101 groups in the whole dataset
データセット全体は、上図に示すように 101 のグループで構成されています。たとえば、ワーククラスの特徴には XNUMX つのグループがあります。次のコードを使用して、グループの名前を視覚化できます。
unique() は、カテゴリ特徴の一意の値を返します。
for i in CATE_FEATURES: print(df_train[i].unique())
['State-gov' 'Self-emp-not-inc' 'Private' 'Federal-gov' 'Local-gov' '?' 'Self-emp-inc' 'Without-pay' 'Never-worked'] ['Bachelors' 'HS-grad' '11th' 'Masters' '9th' 'Some-college' 'Assoc-acdm' 'Assoc-voc' '7th-8th' 'Doctorate' 'Prof-school' '5th-6th' '10th' '1st-4th' 'Preschool' '12th'] ['Never-married' 'Married-civ-spouse' 'Divorced' 'Married-spouse-absent' 'Separated' 'Married-AF-spouse' 'Widowed'] ['Adm-clerical' 'Exec-managerial' 'Handlers-cleaners' 'Prof-specialty' 'Other-service' 'Sales' 'Craft-repair' 'Transport-moving' 'Farming-fishing' 'Machine-op-inspct' 'Tech-support' '?' 'Protective-serv' 'Armed-Forces' 'Priv-house-serv'] ['Not-in-family' 'Husband' 'Wife' 'Own-child' 'Unmarried' 'Other-relative'] ['White' 'Black' 'Asian-Pac-Islander' 'Amer-Indian-Eskimo' 'Other'] ['Male' 'Female'] ['United-States' 'Cuba' 'Jamaica' 'India' '?' 'Mexico' 'South' 'Puerto-Rico' 'Honduras' 'England' 'Canada' 'Germany' 'Iran' 'Philippines' 'Italy' 'Poland' 'Columbia' 'Cambodia' 'Thailand' 'Ecuador' 'Laos' 'Taiwan' 'Haiti' 'Portugal' 'Dominican-Republic' 'El-Salvador' 'France' 'Guatemala' 'China' 'Japan' 'Yugoslavia' 'Peru' 'Outlying-US(Guam-USVI-etc)' 'Scotland' 'Trinadad&Tobago' 'Greece' 'Nicaragua' 'Vietnam' 'Hong' 'Ireland' 'Hungary']
したがって、トレーニング データセットには 101 + 7 列が含まれます。 最後の XNUMX 列は連続的な特徴です。
Scikit-learn が変換を処理できます。 これは XNUMX つの手順で行われます。
- まず、文字列を ID に変換する必要があります。 たとえば、State-gov は ID 1、Self-emp-not-inc は ID 2 などになります。 LabelEncoder 関数がこれを実行します。
- 各IDを新しい列に転置します。前述のように、データセットには101101のグループのIDがあります。したがって、すべてのカテゴリ機能のグループをキャプチャするXNUMXの列があります。Scikit-learnには、この操作を実行するOneHotEncoderという関数があります。
ステップ 2) トレーニング/テスト セットを作成する
データセットの準備ができたので、80/20 に分割できます。
トレーニング セットが 80 パーセント、テスト セットが 20 パーセントです。
train_test_split を使用できます。 最初の引数はデータフレームであり、XNUMX 番目の引数はラベル データフレームです。 test_size でテストセットのサイズを指定できます。
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(df_train[features], df_train.label, test_size = 0.2, random_state=0) X_train.head(5) print(X_train.shape, X_test.shape)
(26048, 14) (6512, 14)
ステップ 3) パイプラインを構築する
パイプラインにより、一貫したデータをモデルに供給することが容易になります。
背後にある考え方は、生のデータを「パイプライン」に入れて操作を実行することです。
たとえば、現在のデータセットでは、連続変数を標準化し、カテゴリデータを変換する必要があります。パイプライン内では任意の操作を実行できることに注意してください。たとえば、データセットに「NA」がある場合は、それを平均または中央値に置き換えることができます。新しい変数を作成することもできます。
あなたには選択の余地があります。 XNUMX つのプロセスをハードコーディングするか、パイプラインを作成します。 最初の選択肢はデータ漏洩につながり、時間の経過とともに不整合が生じる可能性があります。 より良いオプションはパイプラインを使用することです。
from sklearn.preprocessing import StandardScaler, OneHotEncoder, LabelEncoder from sklearn.compose import ColumnTransformer, make_column_transformer from sklearn.pipeline import make_pipeline from sklearn.linear_model import LogisticRegression
パイプラインは、ロジスティック分類器にデータを供給する前に 2 つの操作を実行します。
- 変数を標準化します: `StandardScaler()`
- カテゴリ特徴量を変換します: OneHotEncoder(sparse=False)
make_column_transformer を使用して 0.19 つの手順を実行できます。 この機能は、scikit-learn の現在のバージョン (XNUMX) では使用できません。 現在のバージョンでは、パイプラインでラベル エンコーダーと XNUMX つのホット エンコーダーを実行することはできません。 これが開発者版を使用することにした理由の XNUMX つです。
make_column_transformer は簡単に使用できます。変換を適用する列と、実行する変換を定義する必要があります。たとえば、連続機能を標準化するには、次のようにします。
- conti_features、make_column_transformer 内の StandardScaler()。
- conti_features: 連続変数を含むリスト
- StandardScaler: 変数を標準化します。
make_column_transformer 内のオブジェクト OneHotEncoder は、ラベルを自動的にエンコードします。
preprocess = make_column_transformer( (conti_features, StandardScaler()), ### Need to be numeric not string to specify columns name (categorical_features, OneHotEncoder(sparse=False)) )
fit_transformを使用してパイプラインが機能するかどうかをテストできます。データセットは次の形状になります: 26048, 107
preprocess.fit_transform(X_train).shape
(26048, 107)
データ トランスフォーマーを使用する準備ができました。 make_pipeline を使用してパイプラインを作成できます。 データが変換されたら、ロジスティック回帰をフィードできます。
model = make_pipeline( preprocess, LogisticRegression())
scikit-learn を使用してモデルをトレーニングするのは簡単です。 パイプライン、つまりモデルの前にオブジェクト フィットを使用する必要があります。 scikit-learn ライブラリのスコア オブジェクトを使用して精度を出力できます。
model.fit(X_train, y_train) print("logistic regression score: %f" % model.score(X_test, y_test))
logistic regression score: 0.850891
最後に、predict_proba を使用してクラスを予測できます。 各クラスの確率を返します。 合計すると XNUMX になることに注意してください。
model.predict_proba(X_test)
array([[0.83576663, 0.16423337], [0.94582765, 0.05417235], [0.64760587, 0.35239413], ..., [0.99639252, 0.00360748], [0.02072181, 0.97927819], [0.56781353, 0.43218647]])
ステップ 4) グリッド検索でパイプラインを使用する
ハイパーパラメータ (隠れユニットなどのネットワーク構造を決定する変数) の調整は、面倒で疲れる可能性があります。
モデルを評価する XNUMX つの方法は、トレーニング セットのサイズを変更してパフォーマンスを評価することです。
この方法を XNUMX 回繰り返すと、スコア メトリックを確認できます。 しかし、それは大変な作業です。
代わりに、scikit-learn はパラメーター調整と相互検証を実行する機能を提供します。
交差検証
相互検証とは、トレーニング中に、トレーニング セットがフォールドで n 回スリップされ、モデルが n 回評価されることを意味します。 たとえば、cv が 10 に設定されている場合、トレーニング セットはトレーニングされ、10 回評価されます。 各ラウンドで、分類器はモデルをトレーニングするためにランダムに XNUMX つの分割を選択し、XNUMX 番目の分割が評価用になります。
グリッド検索
各分類子には調整するハイパーパラメータがあります。 別の値を試したり、パラメーター グリッドを設定したりできます。 scikit-learn 公式 Web サイトにアクセスすると、ロジスティック分類器に調整すべきさまざまなパラメーターがあることがわかります。 トレーニングを高速化するには、C パラメーターを調整することを選択します。 正則化パラメータを制御します。 ポジティブである必要があります。 値が小さいほど、レガライザーの重みが大きくなります。
GridSearchCV オブジェクトを使用できます。 調整するハイパーパラメータを含むディクショナリを作成する必要があります。
ハイパーパラメータの後に、試したい値をリストします。 たとえば、C パラメータを調整するには、次を使用します。
- 'logisticregression__C': [0.1, 1.0, 1.0]: パラメーターの前に、分類子の名前 (小文字) と XNUMX つのアンダースコアが続きます。
モデルは 0.001 つの異なる値 (0.01、0.1、1、XNUMX) を試します。
10 個のフォールドを使用してモデルをトレーニングします: cv=10
from sklearn.model_selection import GridSearchCV # Construct the parameter grid param_grid = { 'logisticregression__C': [0.001, 0.01,0.1, 1.0], }
GridSearchCV をパラメーター gri と cv で使用してモデルをトレーニングできます。
# Train the model grid_clf = GridSearchCV(model, param_grid, cv=10, iid=False) grid_clf.fit(X_train, y_train)
出力
GridSearchCV(cv=10, error_score='raise-deprecating', estimator=Pipeline(memory=None, steps=[('columntransformer', ColumnTransformer(n_jobs=1, remainder='drop', transformer_weights=None, transformers=[('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True), [0, 2, 10, 4, 11, 12]), ('onehotencoder', OneHotEncoder(categorical_features=None, categories=None,...ty='l2', random_state=None, solver='liblinear', tol=0.0001, verbose=0, warm_start=False))]), fit_params=None, iid=False, n_jobs=1, param_grid={'logisticregression__C': [0.001, 0.01, 0.1, 1.0]}, pre_dispatch='2*n_jobs', refit=True, return_train_score='warn', scoring=None, verbose=0)
最適なパラメータにアクセスするには、best_params_ を使用します。
grid_clf.best_params_
出力
{'logisticregression__C': 1.0}
XNUMX つの異なる正則化値を使用してモデルをトレーニングした後の最適なパラメーターは次のとおりです。
print("best logistic regression from grid search: %f" % grid_clf.best_estimator_.score(X_test, y_test))
グリッド検索からの最良のロジスティック回帰: 0.850891
予測確率にアクセスするには:
grid_clf.best_estimator_.predict_proba(X_test)
array([[0.83576677, 0.16423323], [0.9458291 , 0.0541709 ], [0.64760416, 0.35239584], ..., [0.99639224, 0.00360776], [0.02072033, 0.97927967], [0.56782222, 0.43217778]])
scikit-learn を使用した XGBoost モデル
Scikit-learnの例を使って、市場で最も優れた分類器の1つをトレーニングしてみましょう。XGBoostはランダムフォレストの改良版です。分類器の理論的背景はこの記事の範囲外です。 Python Scikit チュートリアル。XGBoost は多くの Kaggle コンテストで優勝していることに留意してください。平均的なデータセット サイズでは、ディープラーニング アルゴリズムと同等かそれ以上のパフォーマンスを発揮します。
分類器は調整するパラメーターが多数あるため、トレーニングが困難です。 もちろん、GridSearchCV を使用してパラメーターを選択することもできます。
代わりに、最適なパラメーターを見つけるためのより良い方法を使用する方法を見てみましょう。 GridSearchCV は、多くの値を渡す場合、退屈でトレーニングに非常に時間がかかる可能性があります。 検索空間はパラメータの数とともに増加します。 推奨される解決策は、RandomizedSearchCV を使用することです。 この方法は、各反復後に各ハイパーパラメータの値をランダムに選択することで構成されます。 たとえば、分類器が 1000 回の反復にわたってトレーニングされた場合、1000 個の組み合わせが評価されます。 多かれ少なかれ同じように機能します。 グリッドサーチCV
xgboostをインポートする必要があります。 ライブラリがインストールされていない場合は、pip3 install xgboost または
use import sys !{sys.executable} -m pip install xgboost
In Jupyter 環境
次に、
import xgboost from sklearn.model_selection import RandomizedSearchCV from sklearn.model_selection import StratifiedKFold
このScikitの次のステップ Python チュートリアルには、調整するパラメータを指定することが含まれています。調整するすべてのパラメータを確認するには、公式ドキュメントを参照してください。 Python Sklearn チュートリアルでは、それぞれ 2 つの値を持つ 2 つのハイパーパラメータのみを選択します。XGBoost のトレーニングには時間がかかり、グリッド内のハイパーパラメータが多いほど、待機時間も長くなります。
params = { 'xgbclassifier__gamma': [0.5, 1], 'xgbclassifier__max_depth': [3, 4] }
XGBoost 分類器を使用して新しいパイプラインを構築します。600 個の推定器を定義することを選択します。n_estimators は調整可能なパラメータであることに注意してください。値が高いとオーバーフィッティングにつながる可能性があります。さまざまな値を自分で試すこともできますが、数時間かかる可能性があることに注意してください。他のパラメータにはデフォルト値を使用します。
model_xgb = make_pipeline( preprocess, xgboost.XGBClassifier( n_estimators=600, objective='binary:logistic', silent=True, nthread=1) )
Stratified K-Folds 相互検証を使用して相互検証を改善できます。 ここでは、計算を高速化するために 5 つの折り目のみを構築しますが、品質は低下します。 結果を改善するには、自宅でこの値を 10 または XNUMX に増やします。
XNUMX 回の反復にわたってモデルをトレーニングすることを選択します。
skf = StratifiedKFold(n_splits=3, shuffle = True, random_state = 1001) random_search = RandomizedSearchCV(model_xgb, param_distributions=params, n_iter=4, scoring='accuracy', n_jobs=4, cv=skf.split(X_train, y_train), verbose=3, random_state=1001)
ランダム化検索を使用する準備ができました。モデルをトレーニングできます。
#grid_xgb = GridSearchCV(model_xgb, params, cv=10, iid=False) random_search.fit(X_train, y_train)
Fitting 3 folds for each of 4 candidates, totalling 12 fits [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5 ............ [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5 ............ [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5 ............ [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5 ............ [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5, score=0.8759645283888057, total= 1.0min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5 ............ [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5, score=0.8729701715996775, total= 1.0min [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5, score=0.8706519235199263, total= 1.0min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5 ............ [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1 .............. [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5, score=0.8735460094437406, total= 1.3min [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1 .............. [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1, score=0.8722791661868018, total= 57.7s [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1 .............. [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1, score=0.8753886905447426, total= 1.0min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1 .............. [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5, score=0.8697304768486523, total= 1.3min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1 .............. [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5, score=0.8740066797189912, total= 1.4min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1 .............. [CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1, score=0.8707671043538355, total= 1.0min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1, score=0.8729701715996775, total= 1.2min [Parallel(n_jobs=4)]: Done 10 out of 12 | elapsed: 3.6min remaining: 43.5s [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1, score=0.8736611770125533, total= 1.2min [CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1, score=0.8692697535130154, total= 1.2min
[Parallel(n_jobs=4)]: Done 12 out of 12 | elapsed: 3.6min finished /Users/Thomas/anaconda3/envs/hello-tf/lib/python3.6/site-packages/sklearn/model_selection/_search.py:737: DeprecationWarning: The default of the `iid` parameter will change from True to False in version 0.22 and will be removed in 0.24. This will change numeric results when test-set sizes are unequal. DeprecationWarning)
RandomizedSearchCV(cv=<generator object _BaseKFold.split at 0x1101eb830>, error_score='raise-deprecating', estimator=Pipeline(memory=None, steps=[('columntransformer', ColumnTransformer(n_jobs=1, remainder='drop', transformer_weights=None, transformers=[('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True), [0, 2, 10, 4, 11, 12]), ('onehotencoder', OneHotEncoder(categorical_features=None, categories=None,... reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None, silent=True, subsample=1))]), fit_params=None, iid='warn', n_iter=4, n_jobs=4, param_distributions={'xgbclassifier__gamma': [0.5, 1], 'xgbclassifier__max_depth': [3, 4]}, pre_dispatch='2*n_jobs', random_state=1001, refit=True, return_train_score='warn', scoring='accuracy', verbose=3)
ご覧のとおり、XGBoost のスコアは前のロジスティック回帰よりも優れています。
print("Best parameter", random_search.best_params_) print("best logistic regression from grid search: %f" % random_search.best_estimator_.score(X_test, y_test))
Best parameter {'xgbclassifier__max_depth': 3, 'xgbclassifier__gamma': 0.5} best logistic regression from grid search: 0.873157
random_search.best_estimator_.predict(X_test)
array(['<=50K', '<=50K', '<=50K', ..., '<=50K', '>50K', '<=50K'], dtype=object)
scikit-learn で MLPClassifier を使用して DNN を作成する
最後に、scikit-learn を使用して深層学習アルゴリズムをトレーニングできます。 方法は他の分類器と同じです。 分類子は MLPClassifier で入手できます。
from sklearn.neural_network import MLPClassifier
次のディープラーニングアルゴリズムを定義します。
- アダムソルバー
- Relu活性化関数
- アルファ = 0.0001
- バッチサイズ 150
- それぞれ 100 個と 50 個のニューロンを持つ XNUMX つの隠れ層
model_dnn = make_pipeline( preprocess, MLPClassifier(solver='adam', alpha=0.0001, activation='relu', batch_size=150, hidden_layer_sizes=(200, 100), random_state=1))
レイヤーの数を変更してモデルを改善できます
model_dnn.fit(X_train, y_train) print("DNN regression score: %f" % model_dnn.score(X_test, y_test))
DNN 回帰スコア: 0.821253
ライム: 自分のモデルを信頼してください
適切なモデルを作成したら、それを信頼するためのツールが必要です。 機械学習 アルゴリズム、特にランダムフォレストとニューラルネットワークは、ブラックボックスアルゴリズムとして知られています。言い換えれば、動作はしますが、その理由は誰にもわかりません。
XNUMX 人の研究者が、コンピューターがどのように予測を行うかを確認するための優れたツールを考案しました。 この論文は「なぜあなたを信頼すべきですか?」と題されています。
彼らは、という名前のアルゴリズムを開発しました。 ローカルで解釈可能なモデルに依存しない説明 (LIME).
例を見てみましょう:
機械学習による予測が信頼できるかどうかわからない場合があります。
たとえば、医師は、コンピューターが診断したからといって、その診断を信頼することはできません。 また、モデルを実稼働環境に導入する前に、そのモデルが信頼できるかどうかを知る必要もあります。
ニューラル ネットワーク、ランダム フォレスト、カーネルを備えた SVMS などの信じられないほど複雑なモデルであっても、分類器が予測を行う理由を理解できると想像してください。
予測の背後にある理由を理解できれば、予測を信頼しやすくなります。 医師の例から、モデルがどの症状が重要であるかを彼に告げた場合、あなたはそれを信頼するでしょうが、そのモデルを信頼すべきでないのかどうかも判断しやすくなります。
Lime は、どの機能が分類器の決定に影響を与えるかを知ることができます
データの準備
LIME を実行するには、変更する必要があるものがいくつかあります。 パイソン。 まず、ターミナルに lime をインストールする必要があります。 pip install limeを使用できます
Lime は、LimeTabularExplainer オブジェクトを使用してモデルをローカルで近似します。 このオブジェクトには次のものが必要です。
- numpy 形式のデータセット
- 機能の名前: feature_names
- クラスの名前: class_names
- カテゴリ特徴量の列のインデックス: categorical_features
- 各カテゴリ特徴量のグループの名前: categorical_names
numpy 列車セットを作成する
df_train を pandas からコピーして変換できます。 numpy とても簡単に
df_train.head(5) # Create numpy data df_lime = df_train df_lime.head(3)
クラス名を取得する ラベルには、オブジェクト unique() を使用してアクセスできます。 君は見るべきだ:
- '<= 50K'
- '> 50K'
# Get the class name class_names = df_lime.label.unique() class_names
array(['<=50K', '>50K'], dtype=object)
カテゴリ特徴量の列のインデックス
グループの名前を取得するには、前に学んだ方法を使用できます。ラベルは LabelEncoder でエンコードします。すべてのカテゴリ機能に対してこの操作を繰り返します。
## import sklearn.preprocessing as preprocessing categorical_names = {} for feature in CATE_FEATURES: le = preprocessing.LabelEncoder() le.fit(df_lime[feature]) df_lime[feature] = le.transform(df_lime[feature]) categorical_names[feature] = le.classes_ print(categorical_names)
{'workclass': array(['?', 'Federal-gov', 'Local-gov', 'Never-worked', 'Private', 'Self-emp-inc', 'Self-emp-not-inc', 'State-gov', 'Without-pay'], dtype=object), 'education': array(['10th', '11th', '12th', '1st-4th', '5th-6th', '7th-8th', '9th', 'Assoc-acdm', 'Assoc-voc', 'Bachelors', 'Doctorate', 'HS-grad', 'Masters', 'Preschool', 'Prof-school', 'Some-college'], dtype=object), 'marital': array(['Divorced', 'Married-AF-spouse', 'Married-civ-spouse', 'Married-spouse-absent', 'Never-married', 'Separated', 'Widowed'], dtype=object), 'occupation': array(['?', 'Adm-clerical', 'Armed-Forces', 'Craft-repair', 'Exec-managerial', 'Farming-fishing', 'Handlers-cleaners', 'Machine-op-inspct', 'Other-service', 'Priv-house-serv', 'Prof-specialty', 'Protective-serv', 'Sales', 'Tech-support', 'Transport-moving'], dtype=object), 'relationship': array(['Husband', 'Not-in-family', 'Other-relative', 'Own-child', 'Unmarried', 'Wife'], dtype=object), 'race': array(['Amer-Indian-Eskimo', 'Asian-Pac-Islander', 'Black', 'Other', 'White'], dtype=object), 'sex': array(['Female', 'Male'], dtype=object), 'native_country': array(['?', 'Cambodia', 'Canada', 'China', 'Columbia', 'Cuba', 'Dominican-Republic', 'Ecuador', 'El-Salvador', 'England', 'France', 'Germany', 'Greece', 'Guatemala', 'Haiti', 'Honduras', 'Hong', 'Hungary', 'India', 'Iran', 'Ireland', 'Italy', 'Jamaica', 'Japan', 'Laos', 'Mexico', 'Nicaragua', 'Outlying-US(Guam-USVI-etc)', 'Peru', 'Philippines', 'Poland', 'Portugal', 'Puerto-Rico', 'Scotland', 'South', 'Taiwan', 'Thailand', 'Trinadad&Tobago', 'United-States', 'Vietnam', 'Yugoslavia'], dtype=object)} df_lime.dtypes
age float64 workclass int64 fnlwgt float64 education int64 education_num float64 marital int64 occupation int64 relationship int64 race int64 sex int64 capital_gain float64 capital_loss float64 hours_week float64 native_country int64 label object dtype: object
データセットの準備ができたので、以下の Scikit 学習の例に示すように、別のデータセットを構築できます。 LIME でのエラーを回避するために、実際にはパイプラインの外側でデータを変換します。 LimeTabularExplainer のトレーニング セットは、文字列のない numpy 配列である必要があります。 上記の方法では、トレーニング データセットはすでに変換されています。
from sklearn.model_selection import train_test_split X_train_lime, X_test_lime, y_train_lime, y_test_lime = train_test_split(df_lime[features], df_lime.label, test_size = 0.2, random_state=0) X_train_lime.head(5)
XGBoostから最適なパラメータでパイプラインを作成できます
model_xgb = make_pipeline( preprocess, xgboost.XGBClassifier(max_depth = 3, gamma = 0.5, n_estimators=600, objective='binary:logistic', silent=True, nthread=1)) model_xgb.fit(X_train_lime, y_train_lime)
/Users/Thomas/anaconda3/envs/hello-tf/lib/python3.6/site-packages/sklearn/preprocessing/_encoders.py:351: FutureWarning: The handling of integer data will change in version 0.22. Currently, the categories are determined based on the range [0, max(values)], while in the future they will be determined based on the unique values. If you want the future behavior and silence this warning, you can specify "categories='auto'."In case you used a LabelEncoder before this OneHotEncoder to convert the categories to integers, then you can now use the OneHotEncoder directly. warnings.warn(msg, FutureWarning)
Pipeline(memory=None, steps=[('columntransformer', ColumnTransformer(n_jobs=1, remainder='drop', transformer_weights=None, transformers=[('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True), [0, 2, 10, 4, 11, 12]), ('onehotencoder', OneHotEncoder(categorical_features=None, categories=None,... reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None, silent=True, subsample=1))])
警告が表示されます。警告では、パイプラインの前にラベル エンコーダーを作成する必要がないことが説明されています。LIME を使用しない場合は、Scikit-learn を使用した機械学習チュートリアルの最初の部分の方法を使用しても問題ありません。それ以外の場合は、この方法を使用し、最初にエンコードされたデータセットを作成し、パイプライン内でホット エンコーダーを設定します。
print("best logistic regression from grid search: %f" % model_xgb.score(X_test_lime, y_test_lime))
best logistic regression from grid search: 0.873157
model_xgb.predict_proba(X_test_lime)
array([[7.9646105e-01, 2.0353897e-01], [9.5173013e-01, 4.8269872e-02], [7.9344827e-01, 2.0655173e-01], ..., [9.9031430e-01, 9.6856682e-03], [6.4581633e-04, 9.9935418e-01], [9.7104281e-01, 2.8957171e-02]], dtype=float32)
LIME を実際に使用する前に、間違った分類の特徴を含む numpy 配列を作成しましょう。後でそのリストを使用して、分類器を誤解させる原因について理解することができます。
temp = pd.concat([X_test_lime, y_test_lime], axis= 1) temp['predicted'] = model_xgb.predict(X_test_lime) temp['wrong']= temp['label'] != temp['predicted'] temp = temp.query('wrong==True').drop('wrong', axis=1) temp= temp.sort_values(by=['label']) temp.shape
(826、16)
新しいデータを使用してモデルから予測を取得するラムダ関数を作成します。 すぐに必要になります。
predict_fn = lambda x: model_xgb.predict_proba(x).astype(float) X_test_lime.dtypes
age float64 workclass int64 fnlwgt float64 education int64 education_num float64 marital int64 occupation int64 relationship int64 race int64 sex int64 capital_gain float64 capital_loss float64 hours_week float64 native_country int64 dtype: object
predict_fn(X_test_lime)
array([[7.96461046e-01, 2.03538969e-01], [9.51730132e-01, 4.82698716e-02], [7.93448269e-01, 2.06551731e-01], ..., [9.90314305e-01, 9.68566816e-03], [6.45816326e-04, 9.99354184e-01], [9.71042812e-01, 2.89571714e-02]])
pandas データフレームを numpy 配列に変換します
X_train_lime = X_train_lime.values X_test_lime = X_test_lime.values X_test_lime
array([[4.00000e+01, 5.00000e+00, 1.93524e+05, ..., 0.00000e+00, 4.00000e+01, 3.80000e+01], [2.70000e+01, 4.00000e+00, 2.16481e+05, ..., 0.00000e+00, 4.00000e+01, 3.80000e+01], [2.50000e+01, 4.00000e+00, 2.56263e+05, ..., 0.00000e+00, 4.00000e+01, 3.80000e+01], ..., [2.80000e+01, 6.00000e+00, 2.11032e+05, ..., 0.00000e+00, 4.00000e+01, 2.50000e+01], [4.40000e+01, 4.00000e+00, 1.67005e+05, ..., 0.00000e+00, 6.00000e+01, 3.80000e+01], [5.30000e+01, 4.00000e+00, 2.57940e+05, ..., 0.00000e+00, 4.00000e+01, 3.80000e+01]])
model_xgb.predict_proba(X_test_lime)
array([[7.9646105e-01, 2.0353897e-01], [9.5173013e-01, 4.8269872e-02], [7.9344827e-01, 2.0655173e-01], ..., [9.9031430e-01, 9.6856682e-03], [6.4581633e-04, 9.9935418e-01], [9.7104281e-01, 2.8957171e-02]], dtype=float32)
print(features, class_names, categorical_features, categorical_names)
['age', 'workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country'] ['<=50K' '>50K'] [1, 3, 5, 6, 7, 8, 9, 13] {'workclass': array(['?', 'Federal-gov', 'Local-gov', 'Never-worked', 'Private', 'Self-emp-inc', 'Self-emp-not-inc', 'State-gov', 'Without-pay'], dtype=object), 'education': array(['10th', '11th', '12th', '1st-4th', '5th-6th', '7th-8th', '9th', 'Assoc-acdm', 'Assoc-voc', 'Bachelors', 'Doctorate', 'HS-grad', 'Masters', 'Preschool', 'Prof-school', 'Some-college'], dtype=object), 'marital': array(['Divorced', 'Married-AF-spouse', 'Married-civ-spouse', 'Married-spouse-absent', 'Never-married', 'Separated', 'Widowed'], dtype=object), 'occupation': array(['?', 'Adm-clerical', 'Armed-Forces', 'Craft-repair', 'Exec-managerial', 'Farming-fishing', 'Handlers-cleaners', 'Machine-op-inspct', 'Other-service', 'Priv-house-serv', 'Prof-specialty', 'Protective-serv', 'Sales', 'Tech-support', 'Transport-moving'], dtype=object), 'relationship': array(['Husband', 'Not-in-family', 'Other-relative', 'Own-child', 'Unmarried', 'Wife'], dtype=object), 'race': array(['Amer-Indian-Eskimo', 'Asian-Pac-Islander', 'Black', 'Other', 'White'], dtype=object), 'sex': array(['Female', 'Male'], dtype=object), 'native_country': array(['?', 'Cambodia', 'Canada', 'China', 'Columbia', 'Cuba', 'Dominican-Republic', 'Ecuador', 'El-Salvador', 'England', 'France', 'Germany', 'Greece', 'Guatemala', 'Haiti', 'Honduras', 'Hong', 'Hungary', 'India', 'Iran', 'Ireland', 'Italy', 'Jamaica', 'Japan', 'Laos', 'Mexico', 'Nicaragua', 'Outlying-US(Guam-USVI-etc)', 'Peru', 'Philippines', 'Poland', 'Portugal', 'Puerto-Rico', 'Scotland', 'South', 'Taiwan', 'Thailand', 'Trinadad&Tobago', 'United-States', 'Vietnam', 'Yugoslavia'], dtype=object)}
import lime import lime.lime_tabular ### Train should be label encoded not one hot encoded explainer = lime.lime_tabular.LimeTabularExplainer(X_train_lime , feature_names = features, class_names=class_names, categorical_features=categorical_features, categorical_names=categorical_names, kernel_width=3)
テスト セットからランダムな世帯を選択し、モデルの予測とコンピューターがどのように選択を行ったかを見てみましょう。
import numpy as np np.random.seed(1) i = 100 print(y_test_lime.iloc[i]) >50K
X_test_lime[i]
array([4.20000e+01, 4.00000e+00, 1.76286e+05, 7.00000e+00, 1.20000e+01, 2.00000e+00, 4.00000e+00, 0.00000e+00, 4.00000e+00, 1.00000e+00, 0.00000e+00, 0.00000e+00, 4.00000e+01, 3.80000e+01])
Explain_instance を使用して Explainer を使用すると、モデルの背後にある説明を確認できます。
exp = explainer.explain_instance(X_test_lime[i], predict_fn, num_features=6) exp.show_in_notebook(show_all=False)
分類器が世帯を正しく予測したことがわかります。 収入は確かに50万以上です。
まず言えることは、分類器は予測される確率についてそれほど確信を持っていないということです。機械は、世帯の収入が 50 万ドルを超える確率は 64% であると予測しています。この 64% は、キャピタル ゲインと婚姻収入で構成されています。青色は正のクラスにマイナスの影響を与え、オレンジ色の線はプラスの影響を与えています。
この世帯の資本利得はゼロであるため、分類子は混乱しています。資本利得は通常、富の優れた予測子ですが、この世帯の資本利得はゼロです。また、この世帯の労働時間は週 40 時間未満です。年齢、職業、性別は分類子にプラスの影響を与えています。
婚姻状況が独身の場合、分類器は50万ドル未満の収入を予測しただろう(0.64-0.18 = 0.46)。
間違って分類された別の世帯で試してみることができます
temp.head(3) temp.iloc[1,:-2]
age 58 workclass 4 fnlwgt 68624 education 11 education_num 9 marital 2 occupation 4 relationship 0 race 4 sex 1 capital_gain 0 capital_loss 0 hours_week 45 native_country 38 Name: 20931, dtype: object
i = 1 print('This observation is', temp.iloc[i,-2:])
This observation is label <=50K predicted >50K Name: 20931, dtype: object
exp = explainer.explain_instance(temp.iloc[1,:-2], predict_fn, num_features=6) exp.show_in_notebook(show_all=False)
分類器は収入が 50 未満であると予測しましたが、これは真実ではありません。 この家庭は奇妙に見える。 キャピタルゲインもキャピタルロスもありません。 彼は離婚していて 60 歳で、教育を受けた人々です。つまり、education_num > 12 です。全体的なパターンによれば、この世帯は、分類子によって説明されるように、収入が 50 未満になるはずです。
LIME をいじってみます。 分類器による重大な間違いに気づくでしょう。
ライブラリの所有者の GitHub を確認できます。 これらは、画像とテキストの分類に関する追加のドキュメントを提供します。
まとめ
以下は、scikit learn バージョン >=0.20 でのいくつかの便利なコマンドのリストです。
トレーニング/テスト データセットを作成する | 練習生が分かれる |
パイプラインを構築する | |
列を選択して変換を適用します | メイクカラムトランスフォーマー |
変換の種類 | |
標準化する | StandardScaler |
最小最大 | MinMaxScaler |
ノーマライズ | ノーマライザー |
欠損値の代入 | 代入する |
カテゴリカルに変換する | OneHotEncoder |
データを適合させて変換する | フィットトランスフォーム |
パイプラインを作る | パイプラインの作成 |
ベーシックモデル | |
ロジスティック回帰 | ロジスティック回帰 |
XGブースト | XGB分類子 |
ニューラルネット | MLP分類子 |
グリッド検索 | GridSearchCV |
ランダム検索 | ランダム化検索CV |