非線形最適化関数

ロジスティック回帰を解くには, ロジスティック回帰の形式的定義 の式(3)の非線形最適化問題を解く必要があります. ここでは,この最適化問題を scipy.optimize モジュールに含まれる関数 minimize() を用いて実装します. そこで,この節では minimize() などの最適化関数について俯瞰します. ロジスティック回帰モデルをあてはめるメソッドの実装については,次の 学習メソッドの実装 で述べます.

SciPy の非線形最適化関数

SciPy の非線形最適化関数には, minimize_scalar()minimize() があります. これらを順に紹介します.

sp.optimize.minimize_scalar(fun, args=(), method='brent')

Minimization of scalar function of one variable.

minimize_scalar() は,入力パラメータと出力が共にスカラーである目的関数 fun の最小値と,そのときのパラメータ値を求めます. 関数 fun に,最小化するパラメータ以外の引数がある場合には args で指定します. 最適化の方法は method で指定します. 通常は,最小化するパラメータの範囲に制約がないときは brent を,制約がある場合は bounded を指定します.

sp.optimize.minimize(fun, x0, args=(), method=None, jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, options=None)

Minimization of scalar function of one or more variables.

minimize() は入力パラメータがベクトルで出力はスカラーである目的関数 fun の最小値と,そのときのパラメータの値を求めるという非線形計画問題を解きます. x0 で指定したパラメータから解の探索を開始し,そこから到達できる局所解を見つけることができます [1]args にはパラメータ以外の関数 fun への入力,method ではあとで紹介する最適化手法を指定します. 以降の引数は,最適化手法によって指定が必要かどうかやその意味が変わります. jac は目的関数 fun の勾配ベクトル(ヤコビベクトル)すなわち,目的関数を入力パラメータの各変数での1次導関数を要素とするベクトル返す関数を与えます. hesshessp は2次導関数を要素とするヘシアンを指定します [2] . 制約付きの最適化手法で boundsconstraints はパラメータに対する制約条件を指定します. tol は終了条件の許容誤差で,必要な精度と計算時間のトレードオフを考慮して選びます [3]

minimize_scalar()minimize() のいずれも,最適化の結果を次のクラスで返す

class sp.optimize.OptimizeResult

Represents the optimization result.

変数:
  • fun – Values of objective function.
  • x – The solution of the optimization.
  • success – Whether or not the optimizer exited successfully.
  • nit – Number of iterations performed by the optimizer.

funx は,それぞれ関数の最小値と,そのときのパラメータの値です. success は最適化が成功したかどうか,nit は収束するまでの反復数です.

注釈

[1]

局所最適解を異なる初期値から探索することを何度も繰り返して大域最適解を求める関数として sp.optimize.basinhopping()sp.optimize.brute() が用意されています.

[2]hess は通常のヘシアン,すなわち \(f(\mathbf{x})\) の2次導関数が特定の値 \(\mathbf{a}\) をとったときの行列 \(\mathbf{H}(\mathbf{a}) = {\left[ \frac{\partial^2 f}{\partial x_i \partial x_j} \right]}_{ij}\bigg|_{\mathbf{x}=\mathbf{a}}\) を指定します. しかし,パラメータベクトル \(\mathbf{x}\) の次元数が大きいときは,ヘシアンを保持するためには次元数の2乗という多くの記憶領域を必要としてしまいます. そのような場合に, hessp はヘシアンと特定のベクトル \(\mathbf{p}\) との積 \(\mathbf{H}(\mathbf{a})\mathbf{p}\) を計算する関数を指定することで記憶領域を節約することができます.
[3]非常に小さな値を指定すると,浮動小数点のまるめ誤差などの影響で最適化関数が停止しない場合があります. 目安として \(10^{-6}\) より小さな値を指定するときは,この点に注意した方がよいでしょう.

各種の最適化手法

ロジスティック回帰への適用について述べる前に, minimize()method で指定できる最適化手法を一通り紹介します. 最適化手法は,パラメータの範囲に制約がない場合とある場合に用いるものに分けられます.

パラメータの範囲に制約がない手法は次のとおりです.

  1. 勾配ベクトルやヘシアンが不要
    • Nelder-Mead :Nelder-Mead法
    • Powell :Powell法
  2. 勾配ベクトルのみが必要
    • CG :共役勾配法 (conjugate gradient method)
    • BFGS :BFGS法 (Broyden–Fletcher–Goldfarb–Shanno method)
  3. 勾配ベクトルとヘシアンの両方が必要
    • Newton-CG :ニュートン共役勾配法 (Newton conjugate gradient method)
    • trust-ncg :信頼領域ニュートン共役勾配法 (Newton conjugate gradient trust-region method)
    • dogleg :信頼領域dog-leg法 (dog-leg trust-region method)

1 から 3 になるにつれ,勾配やヘシアンなど引数として与える関数は増えますが,収束するまでの反復数は減ります. 1 の Nelder-MeadPowell では,ほとんどの場合でPowell法が高速です. おおまかにいって,勾配を使う方法と比べて,1回の反復で必要になる目的関数の評価階数はパラメータ数倍になるため,これらの方法は遅いです. 勾配を解析的に計算出来ない場合にのみ使うべきでしょう.

勾配ベクトルのみを使う方法のうち, BFGS は近似計算したヘシアンを用いるニュートン法であるので,収束は CG に比べて速いです. しかし,ヘシアンの大きさはパラメータ数の2乗であるため,パラメータ数が多いときには多くの記憶領域と計算量が必要となるため, CG の方が速くなることが多いです.

3 の方法はヘシアンも必要なので,ヘシアンの実装の手間や,その計算に必要な計算量やメモリを考慮して採用してください.

パラメータの範囲に制約のある方法は次のとおりです.

  1. パラメータの範囲に制約がある場合
    • L-BFGS-B :範囲制約付きメモリ制限BFGS法
    • TNC :切断ニュートン共役勾配法
  2. パラメータの範囲の制約に加えて,等式・不等式制約がある場合
    • COBYLA :COBYLA法 (constrained optimization by linear approximation method)
    • SLSQP :sequential least squares programming

パラメータの範囲は bounds に,パラメータそれぞれの値の最小値と最大値の対の系列を指定します. 等式・不等式制約は, typefunjac の要素を含む辞書の系列で指定します. type には,等式制約なら文字列定数 eq を,不等式制約なら ineq を指定します. fun には制約式の関数を, jac にはその勾配を指定します.