0
2

ロジスティック回帰の代表的なハイパーパラメータ

Last updated at Posted at 2024-05-19

ロジスティック回帰とは

ロジスティック回帰とは、線形分離可能なデータの境界線を学習によって見つけて、
データの分類を行う、代表的な教師あり学習の1つです。
呼び名に「回帰」と付いていますが、あくまで「分類」の手法です。

「境界線が直線になること」がロジスティック回帰の大きな特徴です。
そのため、二項分類などクラスの少ないデータに使われ、
また降水確率など、データがクラスに分類される確率を知りたいときにも使われます。

欠点としては、

  • データが線形分離可能でないと分類できない
  • ⾼次元の疎なデータ(0が多いデータ)には適さない
  • 訓練データから学習した境界線がデータの近くを通るため、汎化能力(未知のデータに対する予測能力)が低い
    などが挙げられます。

このロジスティック回帰には、モデルを操作する人間が調整しなければいけないハイパラメータがあります。
いくら機械学習といえども、すべての学習過程を自動化することは難しいのですね。

ロジスティック回帰のハイパーパラメータの一覧は以下です。たくさんありますね。

今回は数あるハイパーパラメータの中から、代表的なハイパーパラメータ「C」「panalty」「multi_class」「random_staet」の4つを解説していきます。

ハイパーパラメータ C

Cは「教師データの分類の間違いに対して、モデルが学習する識別境界線をどのくらい厳しくするのか」という指標になります。

Cの値は大きければ大きいほど、
モデルは教師データを完全に分類できるような識別線を学習するようになります。
しかし教師データに対しては過学習になり、
訓練データ以外のデータに予測を行うと、正解率が下がる場合が多くなります。

逆にCの値を小さくすると、
教師データの分類の誤りと外れ値データに寛容になり、より一般化された境界線を得やすくなります。 ただし外れ値の少ないデータでは、
境界線がうまく識別できていないモデルになる場合もあります。
極端に小さくても、うまく境界線が識別できません。

scikit-learnのロジスティック回帰モデルにおいて、Cの初期値は1.0です。
以下でCの値が変化することによって、
どのくらいモデルの正解率が変わるかをグラフで確認してみます。

ハイパーパラメータCの確認.py
#ライブラリのインポート
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()

>>>出力結果

image.png

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の違いによる結果の違いを見てみます。

penalty=L1の場合.py
# パッケージをインポート
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()

>>>出力結果

image.png

  • penalty="l2"の場合(penalty以外のコードは上記と同じため省略)

image.png

  • penalty="none"の場合(penalty以外のコードは上記と同じため省略)

image.png

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の場面も多く出そうです。
他の方のいろんなコードを読み、どんなモデルが選択されているのか見たり、
他にどんなハイパーパラメータがあるのかと、リサーチする能力も大切にしたいと思います。

0
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
0
2