2.scipy Optimize
title: "f计算方程组的误差,[1,1,1]是未知数的初始值" date: 2026-05-24T14:11:06Z
1import pylab as pl
2import numpy as np
1import matplotlib as mpl
2mpl.rcParams['font.sans-serif'] = ['SimHei']
拟合与优化-optimize
非线性方程组求解
1from math import sin, cos
2from scipy import optimize
3
4def f(x): #❶
5 x0, x1, x2 = x.tolist() #❷
6 return [
7 5*x1+3,
8 4*x0*x0 - 2*sin(x1*x2),
9 x1*x2 - 1.5
10 ]
11
12# f计算方程组的误差,[1,1,1]是未知数的初始值
13result = optimize.fsolve(f, [1,1,1]) #❸
14print (result)
15print (f(result))
[-0.70622057 -0.6 -2.5 ]
[0.0, -9.126033262418787e-14, 5.329070518200751e-15]
1def j(x): #❶
2 x0, x1, x2 = x.tolist()
3 return [[0, 5, 0],
4 [8 * x0, -2 * x2 * cos(x1 * x2), -2 * x1 * cos(x1 * x2)],
5 [0, x2, x1]]
6
7
8result = optimize.fsolve(f, [1, 1, 1], fprime=j) #❷
9print(result)
10print(f(result))
[-0.70622057 -0.6 -2.5 ]
[0.0, -9.126033262418787e-14, 5.329070518200751e-15]
最小二乘拟合
1import numpy as np
2from scipy import optimize
3
4X = np.array([ 8.19, 2.72, 6.39, 8.71, 4.7 , 2.66, 3.78])
5Y = np.array([ 7.01, 2.78, 6.47, 6.71, 4.1 , 4.23, 4.05])
6
7def residuals(p): #❶
8 "计算以p为参数的直线和原始数据之间的误差"
9 k, b = p
10 return Y - (k*X + b)
11
12# leastsq使得residuals()的输出数组的平方和最小,参数的初始值为[1,0]
13r = optimize.leastsq(residuals, [1, 0]) #❷
14k, b = r[0]
15print ("k =",k, "b =",b)
k = 0.6134953491930442 b = 1.794092543259387
1#%figonly=最小化正方形面积之和(左),误差曲面(右)
2scale_k = 1.0
3scale_b = 10.0
4scale_error = 1000.0
5
6def S(k, b):
7 "计算直线y=k*x+b和原始数据X、Y的误差的平方和"
8 error = np.zeros(k.shape)
9 for x, y in zip(X, Y):
10 error += (y - (k * x + b)) ** 2
11 return error
12
13ks, bs = np.mgrid[k - scale_k:k + scale_k:40j, b - scale_b:b + scale_b:40j]
14error = S(ks, bs) / scale_error
15
16from mpl_toolkits.mplot3d import Axes3D
17from matplotlib.patches import Rectangle
18
19fig = pl.figure(figsize=(12, 5))
20
21ax1 = pl.subplot(121)
22
23ax1.plot(X, Y, "o")
24X0 = np.linspace(2, 10, 3)
25Y0 = k*X0 + b
26ax1.plot(X0, Y0)
27
28for x, y in zip(X, Y):
29 y2 = k*x+b
30 rect = Rectangle((x,y), abs(y-y2), y2-y, facecolor="red", alpha=0.2)
31 ax1.add_patch(rect)
32
33ax1.set_aspect("equal")
34
35
36ax2 = fig.add_subplot(122, projection='3d')
37
38ax2.plot_surface(
39 ks, bs / scale_b, error, rstride=3, cstride=3, cmap="jet", alpha=0.5)
40ax2.scatter([k], [b / scale_b], [S(k, b) / scale_error], c="r", s=20)
41ax2.set_xlabel("$k$")
42ax2.set_ylabel("$b$")
43ax2.set_zlabel("$error$");
1#%fig=带噪声的正弦波拟合
2def func(x, p): #❶
3 """
4 数据拟合所用的函数: A*sin(2*pi*k*x + theta)
5 """
6 A, k, theta = p
7 return A * np.sin(2 * np.pi * k * x + theta)
8
9
10def residuals(p, y, x): #❷
11 """
12 实验数据x, y和拟合函数之间的差,p为拟合需要找到的系数
13 """
14 return y - func(x, p)
15
16
17x = np.linspace(0, 2 * np.pi, 100)
18A, k, theta = 10, 0.34, np.pi / 6 # 真实数据的函数参数
19y0 = func(x, [A, k, theta]) # 真实数据
20# 加入噪声之后的实验数据
21np.random.seed(0)
22y1 = y0 + 2 * np.random.randn(len(x)) #❸
23
24p0 = [7, 0.40, 0] # 第一次猜测的函数拟合参数
25
26# 调用leastsq进行数据拟合
27# residuals为计算误差的函数
28# p0为拟合参数的初始值
29# args为需要拟合的实验数据
30plsq = optimize.leastsq(residuals, p0, args=(y1, x)) #❹
31
32print(u"真实参数:", [A, k, theta])
33print(u"拟合参数", plsq[0]) # 实验数据拟合后的参数
34
35pl.plot(x, y1, "o", label=u"带噪声的实验数据")
36pl.plot(x, y0, label=u"真实数据")
37pl.plot(x, func(x, plsq[0]), label=u"拟合数据")
38pl.legend(loc="best")
真实参数: [10, 0.34, 0.5235987755982988]
拟合参数 [10.25218748 0.3423992 0.50817423]
<matplotlib.legend.Legend at 0x1a3531df940>
1def func2(x, A, k, theta):
2 return A*np.sin(2*np.pi*k*x+theta)
3
4popt, _ = optimize.curve_fit(func2, x, y1, p0=p0)
5print (popt)
[10.25218748 0.3423992 0.50817425]
1popt, _ = optimize.curve_fit(func2, x, y1, p0=[10, 1, 0])
2
3print(u"真实参数:", [A, k, theta])
4
5print(u"拟合参数", popt)
真实参数: [10, 0.34, 0.5235987755982988]
拟合参数 [ 0.71093469 1.02074585 -0.12776742]
计算函数局域最小值
1def target_function(x, y):
2 return (1 - x)**2 + 100 * (y - x**2)**2
3
4
5class TargetFunction(object):
6 def __init__(self):
7 self.f_points = []
8 self.fprime_points = []
9 self.fhess_points = []
10
11 def f(self, p):
12 x, y = p.tolist()
13 z = target_function(x, y)
14 self.f_points.append((x, y))
15 return z
16
17 def fprime(self, p):
18 x, y = p.tolist()
19 self.fprime_points.append((x, y))
20 dx = -2 + 2 * x - 400 * x * (y - x**2)
21 dy = 200 * y - 200 * x**2
22 return np.array([dx, dy])
23
24 def fhess(self, p):
25 x, y = p.tolist()
26 self.fhess_points.append((x, y))
27 return np.array([[2 * (600 * x**2 - 200 * y + 1), -400 * x],
28 [-400 * x, 200]])
29
30
31def fmin_demo(method):
32 target = TargetFunction()
33 init_point = (-1, -1)
34 res = optimize.minimize(
35 target.f,
36 init_point,
37 method=method,
38 jac=target.fprime,
39 hess=target.fhess)
40 return res, [
41 np.array(points) for points in (target.f_points, target.fprime_points,
42 target.fhess_points)
43 ]
44
45
46methods = ("Nelder-Mead", "Powell", "CG", "BFGS", "Newton-CG", "L-BFGS-B")
47for method in methods:
48 res, (f_points, fprime_points, fhess_points) = fmin_demo(method)
49 print(
50 "{:12s}: min={:12g}, f count={:3d}, fprime count={:3d}, fhess count={:3d}"
51 .format(method, float(res["fun"]), len(f_points), len(fprime_points),
52 len(fhess_points)))
Nelder-Mead : min= 5.30934e-10, f count=125, fprime count= 0, fhess count= 0
Powell : min= 0, f count= 52, fprime count= 0, fhess count= 0
CG : min= 9.63056e-21, f count= 39, fprime count= 39, fhess count= 0
BFGS : min= 1.84992e-16, f count= 40, fprime count= 40, fhess count= 0
Newton-CG : min= 5.22666e-10, f count= 60, fprime count= 97, fhess count= 38
L-BFGS-B : min= 6.5215e-15, f count= 33, fprime count= 33, fhess count= 0
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:415: RuntimeWarning: Method Nelder-Mead does not use gradient information (jac).
RuntimeWarning)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:420: RuntimeWarning: Method Nelder-Mead does not use Hessian information (hess).
RuntimeWarning)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:415: RuntimeWarning: Method Powell does not use gradient information (jac).
RuntimeWarning)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:420: RuntimeWarning: Method Powell does not use Hessian information (hess).
RuntimeWarning)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:420: RuntimeWarning: Method CG does not use Hessian information (hess).
RuntimeWarning)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:420: RuntimeWarning: Method BFGS does not use Hessian information (hess).
RuntimeWarning)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:420: RuntimeWarning: Method L-BFGS-B does not use Hessian information (hess).
RuntimeWarning)
1#%figonly=各种优化算法的搜索路径
2def draw_fmin_demo(f_points, fprime_points, ax):
3 xmin, xmax = -3, 3
4 ymin, ymax = -3, 3
5 Y, X = np.ogrid[ymin:ymax:500j,xmin:xmax:500j]
6 Z = np.log10(target_function(X, Y))
7 zmin, zmax = np.min(Z), np.max(Z)
8 ax.imshow(Z, extent=(xmin,xmax,ymin,ymax), origin="bottom", aspect="auto", cmap="gray")
9 ax.plot(f_points[:,0], f_points[:,1], lw=1)
10 ax.scatter(f_points[:,0], f_points[:,1], c=range(len(f_points)), s=50, linewidths=0)
11 if len(fprime_points):
12 ax.scatter(fprime_points[:, 0], fprime_points[:, 1], marker="x", color="w", alpha=0.5)
13 ax.set_xlim(xmin, xmax)
14 ax.set_ylim(ymin, ymax)
15
16fig, axes = pl.subplots(2, 3, figsize=(9, 6))
17methods = ("Nelder-Mead", "Powell", "CG", "BFGS", "Newton-CG", "L-BFGS-B")
18for ax, method in zip(axes.ravel(), methods):
19 res, (f_points, fprime_points, fhess_points) = fmin_demo(method)
20 draw_fmin_demo(f_points, fprime_points, ax)
21 ax.set_aspect("equal")
22 ax.set_title(method)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:415: RuntimeWarning: Method Nelder-Mead does not use gradient information (jac).
RuntimeWarning)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:420: RuntimeWarning: Method Nelder-Mead does not use Hessian information (hess).
RuntimeWarning)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:415: RuntimeWarning: Method Powell does not use gradient information (jac).
RuntimeWarning)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:420: RuntimeWarning: Method Powell does not use Hessian information (hess).
RuntimeWarning)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:420: RuntimeWarning: Method CG does not use Hessian information (hess).
RuntimeWarning)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:420: RuntimeWarning: Method BFGS does not use Hessian information (hess).
RuntimeWarning)
C:\ProgramData\Anaconda3\lib\site-packages\scipy\optimize\_minimize.py:420: RuntimeWarning: Method L-BFGS-B does not use Hessian information (hess).
RuntimeWarning)
计算全域最小值
1def func(x, p):
2 A, k, theta = p
3 return A*np.sin(2*np.pi*k*x+theta)
4
5def func_error(p, y, x):
6 return np.sum((y - func(x, p))**2)
7
8x = np.linspace(0, 2*np.pi, 100)
9A, k, theta = 10, 0.34, np.pi/6
10y0 = func(x, [A, k, theta])
11np.random.seed(0)
12y1 = y0 + 2 * np.random.randn(len(x))
1result = optimize.basinhopping(func_error, (1, 1, 1),
2 niter = 10,
3 minimizer_kwargs={"method":"L-BFGS-B",
4 "args":(y1, x)})
5print (result.x)
[10.25218676 -0.34239909 2.63341581]
1#%figonly=用`basinhopping()`拟合正弦波
2pl.plot(x, y1, "o", label=u"带噪声的实验数据")
3pl.plot(x, y0, label=u"真实数据")
4pl.plot(x, func(x, result.x), label=u"拟合数据")
5pl.legend(loc="best");