ロジスティック回帰とは
ロジスティック回帰とは、線形分離可能なデータの境界線を学習によって見つけて、
データの分類を行う、代表的な教師あり学習の1つです。
呼び名に「回帰」と付いていますが、あくまで「分類」の手法です。
「境界線が直線になること」がロジスティック回帰の大きな特徴です。
そのため、二項分類などクラスの少ないデータに使われ、
また降水確率など、データがクラスに分類される確率を知りたいときにも使われます。
欠点としては、
- データが線形分離可能でないと分類できない
- ⾼次元の疎なデータ(0が多いデータ)には適さない
- 訓練データから学習した境界線がデータの近くを通るため、汎化能力(未知のデータに対する予測能力)が低い
などが挙げられます。
このロジスティック回帰には、モデルを操作する人間が調整しなければいけないハイパラメータがあります。
いくら機械学習といえども、すべての学習過程を自動化することは難しいのですね。
ロジスティック回帰のハイパーパラメータの一覧は以下です。たくさんありますね。
今回は数あるハイパーパラメータの中から、代表的なハイパーパラメータ「C」「panalty」「multi_class」「random_staet」の4つを解説していきます。
ハイパーパラメータ C
Cは「教師データの分類の間違いに対して、モデルが学習する識別境界線をどのくらい厳しくするのか」という指標になります。
Cの値は大きければ大きいほど、
モデルは教師データを完全に分類できるような識別線を学習するようになります。
しかし教師データに対しては過学習になり、
訓練データ以外のデータに予測を行うと、正解率が下がる場合が多くなります。
逆にCの値を小さくすると、
教師データの分類の誤りと外れ値データに寛容になり、より一般化された境界線を得やすくなります。 ただし外れ値の少ないデータでは、
境界線がうまく識別できていないモデルになる場合もあります。
極端に小さくても、うまく境界線が識別できません。
scikit-learnのロジスティック回帰モデルにおいて、Cの初期値は1.0です。
以下でCの値が変化することによって、
どのくらいモデルの正解率が変わるかをグラフで確認してみます。
#ライブラリのインポート
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification
from sklearn import preprocessing
from sklearn.model_selection import train_test_split
# 架空データの生成
X, y = make_classification(
n_samples=1250, n_features=4, n_informative=2, n_redundant=2, random_state=42)
train_X, test_X, train_y, test_y = train_test_split(X, y, random_state=42)
#n_redundantは分類に不要な特徴量の個数
# random_stateは固定(詳しくは下記参照)
# Cの値の範囲を設定(今回は1e-5,1e-4,1e-3,0.01,0.1,1,10,100,1000,10000)
C_list = [10 ** i for i in range(-5, 5)]
# グラフ描画用の空リストを用意
train_accuracy = []
test_accuracy = []
# C_listに納められているCの値を取り出し、順番にモデルに学習
for C in C_list:
model = LogisticRegression(C=C, random_state=42)
model.fit(train_X, train_y)
train_accuracy.append(model.score(train_X, train_y))
test_accuracy.append(model.score(test_X, test_y))
# グラフの描画
# semilogx()はxのスケールを10のx乗のスケールに変更できる
plt.semilogx(C_list, train_accuracy, label="accuracy of train_data")
plt.semilogx(C_list, test_accuracy, label="accuracy of test_data")
plt.title("accuracy by changing C")
plt.xlabel("C")
plt.ylabel("accuracy")
plt.legend()
plt.show()
>>>出力結果
C=0.001のとき、訓練データとテストデータどちらもバランスよく高い正解率が出ています。
一方、C>0.02では、過学習が起きてしまい、訓練データでは高い正解率が出ていますが、
テストデータの正答率は下がってしまっています。
ちなみにCは、線形サポートベクターマシーン(SVM)でも分類の誤りの許容度を示すハイパーパラメータとして定義されています。
ハイパーパラメータpenalty
先ほどのCが分類の誤りの許容度だったのに対し、
penaltyは「モデルの複雑さに対するペナルティ」を表します。
penaltyに入力できる値は「L1」「L2」「elasticnet」「none」の4つがあります。
基本的にはデフォルトのまま「L2」を選びますが、「L1」を選んだほうが欲しいデータが得られる場合もあります。
- L1(ラッソ回帰)...データの"特徴量の削減"により、識別境界線の一般化を図るペナルティ
- L2(リッジ回帰)...データ全体の"重みの減少"により、識別境界線の一般化を図るペナルティ
- elasticnet...L1,L2の両方を使用するペナルティ
- none...正則化を行わない
以下、penaltyの違いによる結果の違いを見てみます。
# パッケージをインポート
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_classification
# データirisを取得
# irisは、特徴量5データ数150のアヤメという花のサンプルデータのテーブル
iris = datasets.load_iris()
X = iris.data[:, [0, 2]]
y = iris.target
# trainデータ、testデータの分割
train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.3, random_state=42)
# ロジスティック回帰モデルの構築(penaltyにL1を指定)
model = LogisticRegression(penalty="l1",solver="liblinear")
# モデルの学習
model.fit(train_X, train_y)
# test_Xに対するモデルの分類予測結果
y_pred = model.predict(test_X)
print(y_pred)
# 以下で可視化
plt.scatter(X[:, 0], X[:, 1], c=y, marker=".",
cmap=matplotlib.cm.get_cmap(name="cool"), alpha=1.0)
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, 0.02),
np.arange(x2_min, x2_max, 0.02))
Z = model.predict(np.array([xx1.ravel(), xx2.ravel()]).T).reshape(xx1.shape)
plt.contourf(xx1, xx2, Z, alpha=0.4,
cmap=matplotlib.cm.get_cmap(name="Wistia"))
plt.xlim(xx1.min(), xx1.max())
plt.ylim(xx2.min(), xx2.max())
plt.title("classification data using LogisticRegression")
plt.xlabel("Sepal length")
plt.ylabel("Petal length")
plt.grid(True)
plt.show()
>>>出力結果
- penalty="l2"の場合(penalty以外のコードは上記と同じため省略)
- penalty="none"の場合(penalty以外のコードは上記と同じため省略)
penaltyがL1のときとnoneのときの出力結果が似ていますね。
L2正則化(リッジ回帰)は「過学習を抑えることで汎化しやすくなる」という特徴がありますので、
ちょうど良い分類になっている可能性が高いです。
逆にL1は「予測に影響を及ぼしにくいデータ」にかかる係数をゼロに近づける手法です。主に余分な情報がたくさん存在するようなデータの回帰分析を行う際に用います。
今回のirisのデータには特徴量が5つしかありませんので、そこを鑑みてもpenaltyにはL2がふさわしいように思えます。
ちなみに"penalty=l1"だけですと、
ValueError: Solver lbfgs supports only 'l2' or 'none' penalties, got l1 penalty.
というエラーメッセージが表示されました。
調べると今はデフォルトのSolverがlbfgsに変わっているそうで、
penaltyにはl2、またはnoneしかサポートしていないそうです。
というわけで、Solverにliblinearを指定しないといけないようでした。
ハイパーパラメータ multi_class
multi_classは多クラス分類を行う際に、「モデルがどういった動作を行うか」を決めるハイパーパラメータです。
ロジスティック回帰では「ovr」「multinomial」の2つがあります。
- ovr...クラスに対して「属する/属さない」の二値分類の問題に適している
- multinomial...各クラスに分類される確率も考慮され、「属する/属さない」だけではなく「どれくらい属する可能性があるか」を扱う問題に適している
ハイパーパラメータ random_state
モデルは学習の際に、データをランダムな順番で処理していきます。
random_stateは、その順番を制御するためのハイパーパラメータです。
ロジスティック回帰モデルの場合、
データの処理順によって大きく境界線が変わる場合があります。
しかしこのrandom_stateの値を固定することによって、同じデータの学習結果を出力できます。
データの再現性も考え、基本はrandom_stateは固定しておく方が良さそうです。
まとめ
今回はロジスティック回帰の数あるハイパーパラメータのなかから、4つを解説してみました。
ロジスティック回帰に関わらず、機械学習モデルそれぞれにハイパーパラメータはいくつもあり、
すべてを100%理解して最適なパラメータを選択するのは非常に難しいようです。
まずは、それぞれのパラメータのデフォルトの組み合わせでモデルを作っていくことからスタートですね。
k-Fold交差検証などで汎化性能を測定し、徐々にふさわしいハイパーパラメータを選んで最も精度が高い組み合わせを探すこともできそうです。
*ハイパーパラメーターの範囲を指定して、精度の良いハイパーパラメーターセットを計算機に見つけてもらうという方法(グリッドサーチやランダムサーチ)もありますが、次回以降記事にしたいと思います。
パラメータの選択には、Try&Errorの場面も多く出そうです。
他の方のいろんなコードを読み、どんなモデルが選択されているのか見たり、
他にどんなハイパーパラメータがあるのかと、リサーチする能力も大切にしたいと思います。