暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

scipy的minimize优化目标函数求解最小参数

漫谈大数据与数据分析 2020-04-28
3157

最小化函数minimize 函数Rosenbrock 函数优化方法BFGS 算法Nelder-Mead Simplex 算法Powell 算法

最小化函数

minimize 函数

%pylab inline
set_printoptions(precision=3, suppress=True)

plt.rcParams["font.family"] = "SimHei"
plt.rcParams["axes.unicode_minus"] = False

Populating the interactive namespace from numpy and matplotlib

已知斜抛运动的水平飞行距离公式:

  • 水平飞行距离

  • 初速度大小

  • 重力加速度

  • 抛出角度

希望找到使 最大的角度 

定义距离函数:

def dist(theta, v0):
    """计算以V0(m/s)初速度在θ度发射的弹丸的飞行距离"""
    g = 9.8
    theta_rad = pi * theta / 180
    return 2 * v0**2 / g * sin(theta_rad) * cos(theta_rad)

print("optimal dist:", dist(451.))

optimal dist: 0.1020408163265306

theta = linspace(09090)
v0 = 1.2
optimal_dist = dist(45, v0)
print("optimal dist:", optimal_dist)
p = plot(theta, dist(theta, v0))
plt.xlabel(r'抛出角度$\theta (^{\circ})$')
plt.xticks(np.arange(0955))
plt.ylabel('水平飞行距离')
plt.hlines(optimal_dist, xmin=35, xmax=55, colors="b")
plt.axvline(45, ymin=0, ymax=1, color="r", ls="--")
plt.show()

optimal dist: 0.14693877551020407


因为 Scipy
 提供的是最小化方法,所以最大化距离就相当于最小化距离的负数:

def neg_dist(theta, v0):
    return -1 * dist(theta, v0)

导入 scipy.optimize.minimize

from scipy.optimize import minimize
result = minimize(neg_dist, x0=50, args=(1, ))
print(f"optimal angle = {result.x[0]:.1f} degrees")

optimal angle = 45.0 degrees

minimize
 接受三个参数:第一个是要优化的函数,第二个是初始猜测值,第三个则是优化函数的附加参数,默认 minimize
 将优化函数的第一个参数作为优化变量,所以第三个参数输入的附加参数从优化函数的第二个参数开始。

查看返回结果:

print(result)

      fun: -0.10204080675612252
 hess_inv: array([[8095.275]])
      jac: array([-0.])
  message: 'Optimization terminated successfully.'
     nfev: 27
      nit: 3
     njev: 9
   status0
  success: True
        x: array([44.988])

Rosenbrock 函数

Rosenbrock 函数是一个用来测试优化函数效果的一个非凸函数:

导入该函数:

from scipy.optimize import rosen
from mpl_toolkits.mplot3d import Axes3D

使用 N = 2
 的 Rosenbrock 函数:

x, y = meshgrid(np.linspace(-2,2,25), np.linspace(-0.5,3.5,25),sparse=True)
# x, y
z = rosen([x,y])
# 图像和最低点 (1,1):
rosen([1,1])

0.0

图像和最低点 (1,1)

fig = figure(figsize=(125.5))
ax = fig.gca(projection="3d")
ax.azim = 70
ax.elev = 48
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlim((01000))
p = ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap=cm.jet)
# 图像和最低点 (1,1):
rosen_min = ax.plot([1], [1], [0], "ro", zorder=9999, markersize=8)


传入初始值:

x0 = [1.31.6-0.5-1.80.8]
result = minimize(rosen, x0)
print(result.x)

[-0.962  0.936  0.881  0.778  0.605]

随机给定初始值:

x0 = np.random.randn(10)
result = minimize(rosen, x0)
print(x0)
print(result.x)

0.374  1.879 -0.407 -0.989 -1.432  1.893  0.339 -0.322 -1.716 -1.614]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]

对于 N > 3
,函数的最小值为 ,不过有一个局部极小值点 ,所以随机初始值如果选的不好的话,有可能返回的结果是局部极小值点:

优化方法

BFGS 算法

minimize
 函数默认根据问题是否有界或者有约束,使用 'BFGS', 'L-BFGS-B', 'SLSQP'
 中的一种。

可以查看帮助来得到更多的信息:

minimize?

默认没有约束时,使用的是 BFGS 方法。

利用 callback
 参数查看迭代的历史:

x0 = [-1.54.5]
xi = [x0]
result = minimize(rosen, x0, callback=xi.append)
xi = np.asarray(xi)
print(xi.shape)
print(result.x)
print("in {} function evaluations.".format(result.nfev))

(48, 2)
[1. 1.]
in 252 function evaluations.

绘图显示轨迹:

x, y = meshgrid(np.linspace(-2.31.7525),
                np.linspace(-0.54.525),
                sparse=True)
z = rosen([x, y])
fig = figure(figsize=(125.5))
ax = fig.gca(projection="3d")
ax.azim = 70
ax.elev = 75
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlim((01000))
p = ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap=cm.jet)
intermed = ax.plot(xi[:, 0], xi[:, 1], rosen(xi.T), "g-o", zorder=99)
rosen_min = ax.plot([1], [1], [0], "ro", zorder=100)


BFGS
 需要计算函数的 Jacobian 矩阵:

给定 

在我们的例子中

导入 rosen
 函数的 Jacobian
 函数 rosen_der

from scipy.optimize import rosen_der

此时,我们将 Jacobian
 矩阵作为参数传入:

x0 = [-1.54.5]
xi = [x0]
result = minimize(rosen, x0, jac=rosen_der, callback=xi.append)
xi = np.asarray(xi)
print(xi.shape)
print(result.x)
print("in {} function evaluations and {} jacobian evaluations.".format(result.nfev, result.njev))

(482)
[1. 1.]
in 62 function evaluations and 62 jacobian evaluations.

可以看到,函数计算的开销大约减少了一半,迭代路径与上面的基本吻合:

x, y = meshgrid(np.linspace(-2.3,1.75,25), np.linspace(-0.5,4.5,25))
z = rosen([x,y])
fig = figure(figsize=(12,5.5))
ax = fig.gca(projection="3d"); ax.azim = 70; ax.elev = 75
ax.set_xlabel("X"); ax.set_ylabel("Y"); ax.set_zlim((0,1000))
p = ax.plot_surface(x, y, z, rstride=1, cstride=1, cmap=cm.jet)
intermed = ax.plot(xi[:, 0], xi[:, 1], rosen(xi.T), "g-o", zorder=99)
rosen_min = ax.plot([1], [1], [0], "ro", zorder=100)


Nelder-Mead Simplex 算法

改变 minimize
 使用的算法,使用 Nelder–Mead 单纯形算法:

x0 = [-1.54.5]
xi = [x0]
result = minimize(rosen, x0, method="nelder-mead", callback = xi.append)
xi = np.asarray(xi)
print(xi.shape)
print("Solved the Nelder-Mead Simplex method with {} function evaluations.".format(result.nfev))

(1202)
Solved the Nelder-Mead Simplex method with 226 function evaluations.

x, y = meshgrid(np.linspace(-1.9,1.75,25), np.linspace(-0.5,4.5,25))
z = rosen([x,y])
fig = figure(figsize=(12,5.5))
ax = fig.gca(projection="3d"); ax.azim = 70; ax.elev = 75
ax.set_xlabel("X"); ax.set_ylabel("Y"); ax.set_zlim((0,1000))
p = ax.plot_surface(x,y,z,rstride=1, cstride=1, cmap=cm.jet)
intermed = ax.plot(xi[:,0], xi[:,1], rosen(xi.T), "g-o", zorder=99)
rosen_min = ax.plot([1],[1],[0],"ro", zorder=100)


Powell 算法

使用 Powell 算法

x0 = [-1.54.5]
xi = [x0]
result = minimize(rosen, x0, method="powell", callback=xi.append)
xi = np.asarray(xi)
print(xi.shape)
print("Solved Powell's method with {} function evaluations.".format(result.nfev))

(312)
Solved Powell's method with 855 function evaluations.

x, y = meshgrid(np.linspace(-2.3,1.75,25), np.linspace(-0.5,4.5,25))
z = rosen([x,y])
fig = figure(figsize=(12,5.5))
ax = fig.gca(projection="3d"); ax.azim = 70; ax.elev = 75
ax.set_xlabel("X"); ax.set_ylabel("Y"); ax.set_zlim((0,1000))
p = ax.plot_surface(x,y,z,rstride=1, cstride=1, cmap=cm.jet)
intermed = ax.plot(xi[:,0], xi[:,1], rosen(xi.T), "g-o", zorder=99)
rosen_min = ax.plot([1],[1],[0],"ro", zorder=100)



文章转载自漫谈大数据与数据分析,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论