上期讲解的拟合方法其共同点都是计算残差平方和函数,对每个系数求偏导,令偏导为0后得到的方程都是关于系数的线性方程,因此可以简单地运用线性代数知识求解。我们再来看这样一个函数。
y=eax+sinbx+cxy=e^{ax}+sinbx+cxy=eax+sinbx+cx
这个函数既不是线性函数,其系数之间也不是线性关系。如果我们依然重复之前的步骤,得出的方程组就会十分复杂。
设有N个点坐标为(xi,yi),i=1,2,...,N(x_i,y_i),i=1,2,...,N(xi,yi),i=1,2,...,N,则残差平方和为∑i=1N(eaxi+sinbxi+cxi−yi)2\sum_{i=1}^N(e^{ax_i}+sinbx_i+cx_i-y_i)^2∑i=1N(eaxi+sinbxi+cxi−yi)2,分别对a、b、c求偏导并令偏导为0得三个方程:
- ∑i=1N(eaxi+sinbxi+cxi−yi)xieaxi=0\sum_{i=1}^N(e^{ax_i}+sinbx_i+cx_i-y_i)x_ie^{ax_i}=0∑i=1N(eaxi+sinbxi+cxi−yi)xieaxi=0
- ∑i=1N(eaxi+sinbxi+cxi−yi)xicosbxi=0\sum_{i=1}^N(e^{ax_i}+sinbx_i+cx_i-y_i)x_icosbx_i=0∑i=1N(eaxi+sinbxi+cxi−yi)xicosbxi=0
- ∑i=1N(eaxi+sinbxi+cxi−yi)xi=0\sum_{i=1}^N(e^{ax_i}+sinbx_i+cx_i-y_i)x_i=0∑i=1N(eaxi+sinbxi+cxi−yi)xi=0
要解这三个方程构成的方程组就不得不运用求解多元非线性方程组的知识。
1.不动点迭代法
一个函数迭代(用x值算出的y值再作为x值代回)有限次后回到同一个值,称为一个迭代周期。不动点就是迭代周期为1的点。不动点存在意味着函数与y=x有交点。
对于N阶齐次线性方程组,将其每个方程中的一个互不相同未知元(共计N个)移到方程组的另一边,将该未知元作为因变量构成函数组。这样,如果一个x向量代入这个函数组时,得出的解向量依然是这个x向量,那么这个x向量就位于这个函数组的不动点。
假如这个函数组迭代收敛,那么给出任意一组x向量(并不一定是线性方程组的解)带入函数组,得到一个新的x向量,必定比原来的x向量更向结果收敛。而因为迭代收敛,在经过一定次数的迭代后x向量的变化会越来越小,最终趋于不动点,也就满足了一开始的不动点方程,这个结果就是方程组的解。
具体来说,对于方程组:
{f1(x1,x2,...,xN)=0f2(x1,x2,...,xN)=0⋮fN(x1,x2,...,xN)=0
\begin{cases}
f_1(x_1,x_2,...,x_N)=0\\
f_2(x_1,x_2,...,x_N)=0\\
\vdots\\
f_N(x_1,x_2,...,x_N)=0
\end{cases}
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧f1(x1,x2,...,xN)=0f2(x1,x2,...,xN)=0⋮fN(x1,x2,...,xN)=0
将其化为以下形式:
{φ1(x1,x2,...,xN)=x1φ2(x1,x2,...,xN)=x2⋮φN(x1,x2,...,xN)=xN
\begin{cases}
\varphi_1(x_1,x_2,...,x_N)=x_1\\
\varphi_2(x_1,x_2,...,x_N)=x_2\\
\vdots\\
\varphi_N(x_1,x_2,...,x_N)=x_N
\end{cases}
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧φ1(x1,x2,...,xN)=x1φ2(x1,x2,...,xN)=x2⋮φN(x1,x2,...,xN)=xN
写成向量形式就是φ(x)=x\varphi(x)=xφ(x)=x。这时候我们把独立出来的未知元设为因变量,也就是φ(x)=x(1)\varphi(x)=x^{(1)}φ(x)=x(1),右上角的小角标是迭代次数。我们随意选取一组x向量代入上式,再将得到的结果代回进行下一次迭代,这样就有φ(x(k))=x(k+1),k=1,2,...\varphi(x^{(k)})=x^{(k+1)},k=1,2,...φ(x(k))=x(k+1),k=1,2,...。我们先假设这个迭代是收敛的,在迭代足够多次后,这个x就会越来越趋近于不变,越来越符合φ(x)=x\varphi(x)=xφ(x)=x,越来越接近解,这种方法称为雅可比迭代法。如果我们把第一个方程迭代解出的新x1作为第二个方程的参数输入,再把第二个方程迭代解出的新x2作为第三个方程的参数输入,就能增加迭代的收敛速度,这种迭代方法称为高斯-赛德尔迭代法。
下面讨论迭代收敛的条件。迭代过程中有:
{φ(x(k))=x(k+1)φ(x(k+1))=x(k+2)
\begin{cases}
\varphi(x^{(k)})=x^{(k+1)}\\
\varphi(x^{(k+1)})=x^{(k+2)}
\end{cases}
{φ(x(k))=x(k+1)φ(x(k+1))=x(k+2)
两式相减并作如下变换:
φ(x(k))−φ(x(k+1))=x(k+1)−x(k+2)=>φ(x(k))−φ(x(k+1))x(k)−x(k+1)=x(k+1)−x(k+2)x(k)−x(k+1)\varphi(x^{(k)})-\varphi(x^{(k+1)})=x^{(k+1)}-x^{(k+2)}=>\frac{\varphi(x^{(k)})-\varphi(x^{(k+1)})}{x^{(k)}-x^{(k+1)}}=\frac{x^{(k+1)}-x^{(k+2)}}{x^{(k)}-x^{(k+1)}}φ(x(k))−φ(x(k+1))=x(k+1)−x(k+2)=>x(k)−x(k+1)φ(x(k))−φ(x(k+1))=x(k)−x(k+1)x(k+1)−x(k+2),因为迭代收敛,x^(k+1) 与x^(k+2) 的差距比x^(k) 与x^(k+1) 的差距更小,则有∣φ(x(k))−φ(x(k+1))x(k)−x(k+1)∣<1|\frac{\varphi(x^{(k)})-\varphi(x^{(k+1)})}{x^{(k)}-x^{(k+1)}}|<1∣x(k)−x(k+1)φ(x(k))−φ(x(k+1))∣<1,因此φ(x)满足在迭代区间上导数绝对值处处小于1。对于N阶函数组来说就是偏导矩阵行列式绝对值,也就是雅可比行列式绝对值:
∣∣∂φ1(x)∂x1∂φ1(x)∂x2...∂φ1(x)∂xN∂φ2(x)∂x1∂φ2(x)∂x2...∂φ2(x)∂xN⋮⋱⋮∂φN(x)∂x1∂φN(x)∂x2...∂φN(x)∂xN∣∣<1
\left|
\left|
\begin{matrix}
\frac{\partial \varphi_1(x)}{\partial x_1}&\frac{\partial \varphi_1(x)}{\partial x_2}&...&\frac{\partial \varphi_1(x)}{\partial x_N}\\
\frac{\partial \varphi_2(x)}{\partial x_1}&\frac{\partial \varphi_2(x)}{\partial x_2}&...&\frac{\partial \varphi_2(x)}{\partial x_N}\\
\vdots&&\ddots&\vdots\\
\frac{\partial \varphi_N(x)}{\partial x_1}&\frac{\partial \varphi_N(x)}{\partial x_2}&...&\frac{\partial \varphi_N(x)}{\partial x_N}
\end{matrix}
\right|
\right|<1
∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∂x1∂φ1(x)∂x1∂φ2(x)⋮∂x1∂φN(x)∂x2∂φ1(x)∂x2∂φ2(x)∂x2∂φN(x)......⋱...∂xN∂φ1(x)∂xN∂φ2(x)⋮∂xN∂φN(x)∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣∣<1
因此迭代收敛说明方程组在迭代区间上的雅可比行列式绝对值小于1,而我们选取的初始向量x也必须满足使雅可比行列式绝对值小于1才可以保证迭代收敛。
不动点迭代法较为简单,但局限性大,必须满足以下几个条件:
- 函数过y=x,也就是函数存在不动点
- 不动点容易求出
- 存在初始向量x使得迭代收敛
2.牛顿迭代法
如果已经给出方程组F(x)=0的一个近似根x(k)=(x1(k),x2(k),...,xn(k))Tx^{(k)}=(x_1^{(k)},x_2^{(k)},...,x_n^{(k)})^Tx(k)=(x1(k),x2(k),...,xn(k))T,则可以把函数F(x)的分量fi(x),i=1,2,...,nf_i(x),i=1,2,...,nfi(x),i=1,2,...,n在x(k)x^{(k)}x(k)处按多元函数泰勒公式展开,取其线性部分做近似,得F(x)=F(x(k))+F′(x(k))(x−x(k))F(x)=F(x^{(k)})+F'(x^{(k)})(x-x^{(k)})F(x)=F(x(k))+F′(x(k))(x−x(k)),方程组转化为F(x(k))+F′(x(k))(x−x(k))=0=>F′(x(k))(x−x(k))=−F(x(k))=>x=x(k)−F(x(k))F′−1(x(k))F(x^{(k)})+F'(x^{(k)})(x-x^{(k)})=0=>F'(x^{(k)})(x-x^{(k)})=-F(x^{(k)})=>x=x^{(k)}-F(x^{(k)})F'^{-1}(x^{(k)})F(x(k))+F′(x(k))(x−x(k))=0=>F′(x(k))(x−x(k))=−F(x(k))=>x=x(k)−F(x(k))F′−1(x(k)),用此式作为迭代式,有x(k+1)=x(k)−F(x(k))F′−1(x(k))x^{(k+1)}=x^{(k)}-F(x^{(k)})F'^{-1}(x^{(k)})x(k+1)=x(k)−F(x(k))F′−1(x(k)),其中F′−1(x(k))F'^{-1}(x^{(k)})F′−1(x(k))为方程组雅可比行列式的相反数。
牛顿迭代法是必定收敛的,这可以从几何意义上直观地看出。假设有一条曲线和x轴有交点,牛顿迭代法的做法就是作其任意一点的切线,用这条切线和x轴交点作为新根,再作新根对应函数图像上的点的切线,以此类推,逐渐逼近真实解。
3.一般曲线拟合实例
numpy自带的拟合功能只能实现多项式拟合。如果我们需要指定一个模板函数,计算这个函数中每个待定计算的值来拟合数据,就要运用到scipy库。
现有一家公司对本年度前十个月的销售量进行了统计,统计数据如表所示,该公司希望通过对统计数据进行分析找到数据内在的关系式,并对该年后两个月的销量进行预测:
月份 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
销售量 | 10 | 16 | 21 | 26 | 30 | 34 | 38 | 41 | 45 | 49 |
观察后决定使用y=ax+blnx+c来拟合,python代码如下:
import numpy as np
from scipy import optimize
def f(x,a,b,c):
return a*x+b*np.log(x)+c
y=[]
for i in range(0,10):
y.append(int(input()))
y=np.array(y)
x=np.arange(1,11)
fita,fitb=optimize.curve_fit(f,x,y,[1,1,1])
print(fita)
print(f(11,fita[0],fita[1],fita[2]))
print(f(12,fita[0],fita[1],fita[2]))
三次打印的结果分别是a、b、c的取值,11月的预测结果以及12月的预测结果。