LoginSignup
3
2

More than 5 years have passed since last update.

Udemy「Pythonで機械学習:scikit-learnで学ぶ識別入門」を受講後の感想・まとめ その1

Last updated at Posted at 2018-10-27

機械学習を仕事で使うため、Udemyで色々と受講しています。
その中で、「Pythonで機械学習:scikit-learnで学ぶ識別入門」を受講したので、そのメモです。

感想

非常に充実しています。
オープニングで、扱っているのは予測ではなく識別のみと宣言しているため、内容が統一されていると感じます。
ボリュームはかなりあります。単に講座を聞くだけなら2~3日で終わりますが、講座を聞いて、手元のJupyter notebookで理解しながらコードを確認・修正して..とやっていると、社会人だと6~7日は必要かと思います。
データ分割~学習~認識の流れで、学習に進んだと思ったらデータ分割の別の方法の説明があるなどで、飛ぶことがある印象です。また、同じ識別器でもサンプルデータ・癌データでセクションが別なので、類似説明が続く印象もあります。その場合はスキップしてよいかと。最後にまとめがあると嬉しかったかもしれません。
なので、その要約です。トピックの紹介なので、詳細は他詳しいwiki/qiitaで調べたほうがよいです。

テストのための大まかなフロー

学習データ(含む訓練データ)とテストデータの分割

  • Cross-Validationを実施する
  • 分割方法は、ShuffleSplitKFoldStratifiedKFold が有名。
  • Leave one outやLeave one group outもある。Leave P outもあるが使われない。
  • 学習サンプルに応じて何の手法を使うか決める必要があるが、ビッグデータの場合は複雑に分割することは難しい。KFoldが無難。
  • 学習時、クラスにランダム性を持たせるためStratified(StratifiedKFold) を利用することが重要。

欠損値・特徴量の加工

  • nanの値をnp.isnan で見つけ、NaNを平均(Imputer からtransform した値)で埋める / medianで埋める(Imputer(strategy='median') ) / 除外する (個々のケースによる)
  • 全ての特徴が識別に有効ではない場合もある。その場合は特徴量を抽出するか、削減する。例えば以下。
  • SelectKBest: 影響する特徴を自動的に抽出する
  • PCA(主成分) : 相関が高い2つの特徴をマージして特徴量を減らす
  • PolynomialFeatures : 非線形変換をおこなうことで、別の特徴量を算出する。例えば、$x1$,$x2$,$x3$ があった場合に、別の特徴量として、$x1\times x2$ をつくる。ただ、増やすと特徴量が大幅に増えるので、増やしたらPCAで削減することも検討すること。最後の手段であり、あまり使わない。

標準化・スケーリング・正規化(重要)

  • StandardScaler (標準化): fit~transformすることで、特徴量を平均0, 標準偏差1にする。
  • MinMaxScaler (スケーリング):最大最小をある範囲に抑える。 scaler=MinMaxScaler([-1, 1])のように設定する。
  • Normalizer (正規化): サンプル毎に正規化する。そのため、fitは不要。transformだけ実行すればよい。
  • PCA Whitening : PCAだけだと次元を減らす。しかし分散が大きいので、whiten=Trueにすることで、平均0, 分散1にすることができる。
  • ZCA Whitening : PCAと類似しているが、ディープラーニングの画像認識で使われている。PCAより性能がでるとのこと。ここはもう少し理論を勉強する必要がありそう。。

学習データの評価

  • Confusion Matrix : trainから算出した結果の正誤表を以下のようなmatrixで表示する。 image.png

TP: True Positive
TN: True Negative
FP: False Positive
FN: False Negative
ちょっと覚えにくい。。
TP/TNはOK, FP/FNは予測と異なるのでNGということ。

  • classification_report : precision/recall/f1-score/supportを算出する。
  • recallは再現率(True Positive Rate)。$TP / (TP + FN)$ の計算式。実際に正で、予測が正だった割合。
  • precisionは適合度。$TP / (TP + FP)$。予測が正で、実際に正だった割合。
  • Fはprecisionとrecallの調和平均で、予測精度の指標を表す。
  • これらは、ROC曲線/AUCで利用する。ROC曲線は、縦軸にTP、横軸にFPの割合を2次元プロットして点を線で連結した曲線。AUCはArea Under the Curveのこと。ROC曲線の曲線よりしたの面積。分類器の精度評価に使う。

色々な識別器

ロジスティック回帰・SVM(線形非線形)、ランダムフォレスト、(多層)パーセプトロン、k近傍識別器あたりが説明の中心です。最初はOneVsRestの説明、その後は各識別器の説明でした。かいつまんで記載します。

  • ロジスティック回帰のOne-vs-Rest:One-vs-Rest: 例えば3クラス分類の際、あるクラスAと、それ以外のB/Cの識別器を作る。ロジスティック回帰でもone-vs-oneはあるにはあるが、sklearnでは実装されていない。

  • SVMのOne-vs-Rest: ovr指定にて、one-vs-restになる。

 svm.SVC(kernel='linear', decision_function_shape='ovr')
  • SVMのOne-vs-One: ovoを設定する。ovrと異なり、1:1で識別器を作成する。 ovoはコンビネーションで増えてしまうので、クラス数が多いと使われない

  • k近傍識別器(kNN: neighbors): 以下のようにして使う。

sklearn import neighbors
clf = neighbors.KNeighborsClassifier(n_neighors=N) 
# Nは自身からの距離を示す。N=3なら、3番目に近いところまでを含める。
clf.fit(X, y)
  • radius NN(RadiusNeighborsClassifier): ある半径の中に入っているもののサンプルで多数決を取る。
clf = neighbors.RadiusNeighborsClassifier()
clf.fit(X_train, y_train)
  • パーセプトロン: 講座ではパーセプトロンの動き・損失関数を可視化して説明。損失関数は、正の値の際には変更しない。 基本は単独では使わない。線形識別の場合、ロジスティック回帰が基本使われる。
from sklearn.linear_model import Perceptoron
clf = Perceptron() # default n_iter=5(epoch)
# 既に学習済の場合、clf.warm_start = Trueで、前回の結果を流用する
clf.fit(X, y)
  • ロジスティック回帰: 損失関数がパーセプトロンとは異なり、正しい値でも一部を損失に含める。講座では頻繁に登場。
clf = LogisticRegression()
clf.fit(X_Train, y_train)
clf.predict(X_test)
  • SVM: 損失関数はパーセプトロンに類似しているが、正の値でも少しだけ損失を加える。識別境界に近いものは損失を加える。線形非線形があり、非線形がよく使われる。線形の場合、LinearSVCを使うべき。
from sklearn.svm import SVC
clf = SVC(kernel='linear')
# 確率を算出するには、fit前にprobability = Trueを設定しておく必要がある。
# 非線形カーネル(rbf/poly)もある。
# デフォルトはrbf。linearの場合、LinearSVCが用意されているので、そちらを使うほうが高速。
# polyは、スケーリングしておかないと計算が終わらない可能性あり。

  • MLP(多層パーセプトロン): パーセプトロンにおいて、中間層を複数にしたモデル。
from sklearn.neural_network import MLPClassifier
clf = MLPClassifier(random_state=8)
clf.alpha = 1 # 仮
clf.max_iter = 2000 # 仮
hidden_layer_sizes = (10,10,5) # 中間層3つ(計5層)の例
  • ランダムフォレスト: 決定木の応用で、決定木(sklearnのDecisionTreeClassifier())が多数集まった構成。使うツリーの数をn_estimatorsで変更する。n_estimators=1なら決定木と同じ。本講座では分類だけだが、ランダムフォレストは回帰でも利用可能(RandomForestRegressor)。 また、ランダムフォレストではスケーリングの効果はない。縦軸横軸をスケーリングしても変わらないため。
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(random_state=8)
clf.max_depth = N 
# 決定木の深さの最大値。過学習をおこさないため、調整が必要。
clf.n_estimators = M 
# 決定木の個数。こちらも調整が必要。
clf.fit(X, y)

そのほか(tips)

  • グリッドサーチ(パラメータ調整): ロジスティック回帰を例にすると、Cの値がパラメータで設定できる。これをfor文で順番に学習させると手間がかかるので、グリッドサーチを用いる。また、パラメータ変更は大胆に変える。1,2,3..ではなく、$10^0$, $10^1$, $10^2$,..のようにする。
from sklearn.model_selection import GridSearchCV
C_range = {1e-5, 1e-3, 1e-2, 1, 1e2, 1e5, 1e10}
# ケースによっては複数設定するので、その場合は以下のようにリストにする
# param = [ {'C:' C_range}, {'kernel': ['linear']}, ..]
param = {'C': C_range} # clf.Cのこと
gs = GridSearchCV(clf, param) # clfは識別器
gs.fit(X_train, y_train)
# この中で3-fold-cross-validationをおこなっている

#gs.best_params_, gs.best_score_, gs.best_estimator_で結果を参照する
gs.score(X_test, y_test)
#ベストの識別パラメータがgsに設定されている
  • ランダムサーチ(パラメータ調整): MLPになると、パラメータが多数存在する。hidden_layer_sizes, activation, beta_1, beta_2, alphaなど..。これらをグリッドサーチしていると、計算量が膨大になるため、探索パラメータの中から抜粋して計算する。注意点としては、ランダムなので、もう一度実行すると認識率は変わる。
from sklearn.model_selection import RandomizedSearchCV
param = 
gs = RandomizedSearchCV(clf, param, n_iter=20, n_jobs=1, verbose=2)
# n_jobsはコア数、n_iterは組み合わせの試行回数
# verboseは公式ドキュメント見てもわからず、講座でも触れておらず..。あまり性能には関係なさそう。
gs.fit(X_train, y_train)
..
gs.best_params_, gs.best_score_, gs.best_estimator_
  • パイプライン: 一連の処理を一括りにしてくれる。グリッドサーチ・正規化と組み合わせると便利。
# 識別器のパイプライン例
from sklearn.pipeline import Pipeline
estimators = [('pca', PCA(whiten=True)),
('clf', SVC())]
pipe = Pipeline(estimators)
pipe.fit(X_train, y_train)
pipe.score(X_test, y_test)
# pipeline + param + clf
from sklearn.model_selection import RandomizedSearchCV
estimators = [('pca', PCA()),
('clf', SVC())]

param = {'clf__C': [1e-5, 1e-3],
'clf__kernel': ['linear', 'rbf'],
'pca__whiten': [True, False]}
# clf__Cの__は必須。
pipe = Pipeline(estimators)
gs.RandomizedSearchCV(pipe, param, n_jobs=1, verbose=2)
gs.fit(X_train, y_train)
  • 則化パラメータC: ロジスティック回帰・SVMで$C$が重要。その変更の影響の確認。SVMのlinearで試したところ、$C$が正の値で、認識率が高い結果となっている。パイプライン・グリッドサーチと組み合わせて検証してみるのがよいかと。

  • データの作成: sklearnでは癌のデータがすでに存在する。それ以外でもサンプル用に即座に作成することができる。

# 癌データの学習・テストデータ分離の例
from sklearn.datasets import load_breast_cancer
data = load_breast_cancer()
X = data.data
y = data.target
from sklearn.model_selection import ShuffleSplit
ss = ShuffleSplit(n_splits=1,
             tran_size=0.8,
             test_size=0.2,
             random_state=0)

train_index, test_index=next(ss.split(X, y))

X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
# 意図的にサンプル作成
X, y = make_blobs(n_samples=20, # 20個生成
           n_features=2, # 2次元
           centers=2, # クラスタ中心2個
           cluster_std=1, # 標準偏差
           random_state=8 # seed(固定)
           )

最後に

この講座で利用していたnumpy, matplotlibのコマンドについては別途記載予定。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2