2.7.4 特殊案例: 非线性最小二乘
2.7.4.1 最小化向量函数的基准
最小二乘法,向量函数基准值的最小化,有特定的结构可以用在scipy.optimize.leastsq()中实现的Levenberg–Marquardt 算法。
让我们试一下最小化下面向量函数的基准:
In [5]:
def f(x):
return np.arctan(x) - np.arctan(np.linspace(0, 1, len(x)))
x0 = np.zeros(10)
optimize.leastsq(f, x0)
Out[5]:
(array([ 0\. , 0.11111111, 0.22222222, 0.33333333, 0.44444444,
0.55555556, 0.66666667, 0.77777778, 0.88888889, 1\. ]), 2)
这用了67次函数评估(用'full_output=1'试一下)。如果我们自己计算基准并且使用一个更好的通用优化器(BFGS)会怎么样:
In [6]:
def g(x):
return np.sum(f(x)**2)
optimize.fmin_bfgs(g, x0)
Optimization terminated successfully.
Current function value: 0.000000
Iterations: 11
Function evaluations: 144
Gradient evaluations: 12
Out[6]:
array([ -7.44987291e-09, 1.11112265e-01, 2.22219893e-01,
3.33331914e-01, 4.44449794e-01, 5.55560493e-01,
6.66672149e-01, 7.77779758e-01, 8.88882036e-01,
1.00001026e+00])
BFGS需要更多的函数调用,并且给出了一个并不精确的结果。
注意只有当输出向量的维度非常大,比需要优化的函数还要大,leastsq
与BFGS相类比才是有趣的。
如果函数是线性的,这是一个线性代数问题,应该用scipy.linalg.lstsq()解决。
2.7.4.2 曲线拟合
最小二乘问题通常出现在拟合数据的非线性拟合时。当我们自己构建优化问题时,scipy提供了这种目的的一个帮助函数: scipy.optimize.curve_fit():
In [7]:
def f(t, omega, phi):
return np.cos(omega * t + phi)
x = np.linspace(0, 3, 50)
y = f(x, 1.5, 1) + .1*np.random.normal(size=50)
optimize.curve_fit(f, x, y)
Out[7]:
(array([ 1.50600889, 0.98754323]), array([[ 0.00030286, -0.00045233],
[-0.00045233, 0.00098838]]))
练习
用omega = 3来进行相同的练习。困难是什么?