Pythonで最適化問題入門

# 背景
第三弾になりますが、タイトル通り入門編として記載します。

# 最適化問題とは
簡単に言うと、ある定義された関数の最小を導く問題です。

# 定義関数例
簡単な2次関数にします。

```py
def f(x):
    return x**2
```
分かりやすく描画します。

```py
import matplotlib.pyplot as plt
import numpy
x = numpy.arange(-5, 5.1, 0.1)
plt.plot(x, f(x))
plt.show()
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/88552/74283514-dc3f-555d-2802-22eccebf88fa.png)

はい、とってもシンプルな例です。

# 定義注意
最適化問題の関数はscipyに含まれています（事前にインストールしてください）

ここで一点注意、普通にimport定義すると怒られます。

```py
import scipy
scipy.optimize
```

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'module' object has no attribute 'optimize'

scipy.optimizeを使うには、[公式サイト](https://docs.scipy.org/doc/scipy/reference/tutorial/general.html#scipy-organization)にも書いてありますが

```py
from scipy import optimize
```
と定義しましょう。

# 最適化
一般的な滑降シンプレックス法、Nelder–Mead法で行います。
こちらはscipyではscipy.optimize.fmin関数が該当します。

この関数何だっけ？使い方どうするんだっけ？という場合はnumpy.infoで確認できます。

```py
import numpy
from scipy import optimize
numpy.info(optimize.fmin)
```

     fmin(func, x0, args=(), xtol=0.0001, ftol=0.0001, maxiter=None, maxfun=None,
          full_output=0, disp=1, retall=0, callback=None, initial_simplex=None)
    
    Minimize a function using the downhill simplex algorithm.
    
    This algorithm only uses function values, not derivatives or second
    derivatives.
    
    Parameters
    ----------
    func : callable func(x,*args)
        The objective function to be minimized.
    x0 : ndarray
        Initial guess.
    args : tuple, optional
        Extra arguments passed to func, i.e. ``f(x,*args)``.
    xtol : float, optional
        Absolute error in xopt between iterations that is acceptable for
        convergence.
    ftol : number, optional
        Absolute error in func(xopt) between iterations that is acceptable for
        convergence.
    maxiter : int, optional
        Maximum number of iterations to perform.
    maxfun : number, optional
        Maximum number of function evaluations to make.
    full_output : bool, optional
        Set to True if fopt and warnflag outputs are desired.
    disp : bool, optional
        Set to True to print convergence messages.
    retall : bool, optional
        Set to True to return list of solutions at each iteration.
    callback : callable, optional
        Called after each iteration, as callback(xk), where xk is the
        current parameter vector.
    initial_simplex : array_like of shape (N + 1, N), optional
        Initial simplex. If given, overrides `x0`.
        ``initial_simplex[j,:]`` should contain the coordinates of
        the j-th vertex of the ``N+1`` vertices in the simplex, where
        ``N`` is the dimension.
    
    Returns
    -------
    xopt : ndarray
        Parameter that minimizes function.
    fopt : float
        Value of function at minimum: ``fopt = func(xopt)``.
    iter : int
        Number of iterations performed.
    funcalls : int
        Number of function calls made.
    warnflag : int
        1 : Maximum number of function evaluations made.
        2 : Maximum number of iterations reached.
    allvecs : list
        Solution at each iteration.

こんな形で引数や出力、この関数の意味など詳細が確認できます。

では最適化します。

```py
optimize.fmin(f, 1)
```

    Optimization terminated successfully.
             Current function value: 0.000000
             Iterations: 18
             Function evaluations: 36
    array([-1.77635684e-15])


最小値は-1.77635684e-15と算出されました。
他の内容はその時の関数の値、最適化時のイテレーション回数や関数の回数等です。

# 補足
「ある範囲内」という場合はoptimize.fminboundという関数もあります。

```py
optimize.fminbound(f, 2, 3, full_output=1)
```

    (2.000005960860986, 4.000023843479476, 0, 25)


そもそもですが、一次関数程度ならoptimize.brentという関数も存在します。

```py
optimize.brent(f, brack=(1,2), full_output=1)
```

    (0.0, 0.0, 4, 5)

もっともっというと、optimize.minimizeという関数が存在します。

```py
optimize.minimize(f, 1.0, method='Nelder-Mead')
```

    final_simplex: (array([[-8.8817842e-16],
           [ 9.7656250e-05]]), array([7.88860905e-31, 9.53674316e-09]))
               fun: 7.888609052210118e-31
           message: 'Optimization terminated successfully.'
              nfev: 34
               nit: 17
            status: 0
           success: True
                 x: array([-8.8817842e-16])

[minimizeの公式ドキュメント](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html)を見ると、他にも様々な手法が可能です。

以上で最適化問題の入門編ということで終わりにします。