【机器学习】数值分析03 您所在的位置:网站首页 在线拟合曲线 【机器学习】数值分析03

【机器学习】数值分析03

2023-07-16 00:54| 来源: 网络整理| 查看: 265

数值分析——任意曲线拟合 全文目录

(博客园)机器学习

(Github)MachineLearning Math

万物皆是展开式

你是否想过这样一个问题,任何的函数,也许都能通过一个“大一统”理论将他们整合在一起。事实上对于任意一种对应关系,我们都能找到一个函数尽可能去贴合它,我们采取的是一种极限的思维,举个不恰当的例子来描述,如果一个东西看起来像牛粪,闻起来像牛粪,尝起来像牛粪,那么它就是牛粪。并且,更加一般的是,在一个微小的区间内,函数还可以写成一个幂函数的形式去大致的估算。

泰勒定理给了我们一个很通用的方法去研究函数:

设n是一个正整数。如果定义在一个包含a的区间上的函数\(f\)在a点处n+1次可导,那么对于这个区间上的任意x,都有:

\[f(x)=\sum^{n}_{i=0}\frac{f^{(i)}(a)}{i!}(x-1)^i+R_n(x) \]

其中,上式的\(R_n(x)\)是泰勒公式的估计余项,这在后续会进行详细的解释。

如果仅仅只是背下来,你就不能领略到泰勒展开的精妙之处了。我们用一些很精妙的手段,自然的推导出泰勒公式。首先我们先假定一个函数存在一阶导函数,来看一看一阶导数的定义

\[\lim_{x\to x_0}\frac{f(x)-f(x_0)}{x-x_0}=f^{'}(x_0) \]

其实从这里不难发现,导数定义上,给了我们一种当\(x\to x_0\)的时候,计算\(f(x)\)的手段,我们假定这个过程的无穷小为\(\alpha(x)(x\to x_0)\),那么我们可以把这个等式改写为如下形式

\[\lim_{x\to x_0} = f(x) = L \Leftrightarrow f(x) = L+\alpha(x) \]

\[\lim_{x\to x_0}f^{'}(x) = \frac{f(x)-f(x_0)}{x-x_0} = f^{'}(x)+\alpha(x) \]

\[f(x) = f(x_0)+f^{'}(x_0)(x-x_0)+\alpha(x)\times(x-x_0) \]

\[=f(x_0)+f^{'}(x_0)(x-x_0)+\omicron(x-x_0) \]

余项估计

从上面的推导规程很明显可以看出最后一项无穷小是\((x-x_0)\)的高阶无穷小,所以我们就很自然的得出了\(f(x)\)的一阶泰勒展开式。利用这个公式,我们可以去拟合任意可导的函数的任意函数点,再从点的绘制成函数曲线。

当然我们会认为,一阶导数所带来的那个余项无穷小是不够精确的,提高精确值的方法就是让这个无穷小的阶升高,那么我们可以继续考虑二阶展开,让这个无穷小的阶数升高。首先我们来单独的研究一下这个无穷小。

\[\omicron(x-x_0) = f(x)-f(x_0)-f^{'}(x_0)(x-x_0) \]

\[\lim_{x\to x_0}\frac{\omicron(x-x_0)}{(x-x_0)^2} = \lim_{x\to x_0}\frac{f(x)-f(x_0)-f^{'}(x_0)(x-x_0)}{(x-x_0)^2} \]

很明显,只要我们的函数二阶可导,那么上述式子就满足了0/0型的洛必达法则!那么我们直接开始洛必达!

\[\lim_{x\to x_0}\frac{f(x)-f(x_0)-f^{'}(x_0)(x-x_0)}{(x-x_0)^2} = \lim_{x\to x_0}\frac{f^{'}(x)-f^{'}(x_0)}{2(x-x_0)} \]

\[=\frac{1}{2}f^{''}(x_0) = \lim_{x\to x_0}\frac{\omicron(x-x_0)}{(x-x_0)^2} \Leftrightarrow \omicron(x-x_0) = \frac{1}{2}f^{''}(x_0)(x-x_0)^2 \]

\[\Leftrightarrow f(x) = f(x_0)+f^{'}(x_0)(x-x_0)+\frac{1}{2}f^{''}(x_0)(x-x_0)^2 +\omicron(x-x_0)^2 \]

这样,我们就得到了拥有二阶无穷小的泰勒公式!如法炮制,只要我们的\(f(x)\)在\(x_0\)满足n阶可导的情况,那么我们就可以一直用上面的方式得到n阶泰勒展开公式。

接下来我们来估计余项,也就是误差的大小。在上面的推断中,我们一直使用无穷小进行误差的估计,这种类型的余项叫做皮亚诺余项,这种好处是可以很直观的看出误差的阶数,但是并不算是一个特别容易计算的值,我们仅仅知道最大的误差不超过\(\omicron(x-x_0)^n\)。因此我们可以思考一下,假如我们展开到第n阶的时候,误差必然是比第n+1阶新引入的那一项更大,但比第n阶是更小的,那么我们可以用介值定理和拉格朗日微分中值定理进行推广,那么余项可以写成

\[R_n(x) = \frac{f^{(n+1)}(\theta)}{n!}(x-x_0)^{n+1} \]

利用泰勒公式,我们就可以将一个可导函数的任意点进行一个拟合,从而得到一个较为精确的结果,从函数图像上看,泰勒公式是一个级数累加不断前进逼近的过程。

多项式插值法

如果针对的是一个有穷数列,例如请你寻找以下数字的规律并填写接下来的数字

4、7、11、18、29、47、(__)

你的第一眼可能会发现这是一个类似 Fibonacci数列的规律数字,但实际上我们对于有穷离散型函数,也可以推出这样一个奇怪的对应关系

\[a_x=\frac {28579 x^9}{90720} - \frac{142847 x^8}{10080} + \frac{4140931 x^7}{15120} \]

\[- \frac{713627 x^6}{240} + \frac{17192243 x^5}{864} - \frac{40631363 x^4}{480} \]

\[+ \frac{644406697 x^3}{2835} - \frac{927568429 x^2}{2520} +\frac {101426987 x}{315} - 113739 \]

并且对于任何的有穷的数列,我们总是能使用一个通项公式进行数据的拟合计算。如果我们把上述拓展到函数领域,也就是对于任意有限多的\((x_i,y_i)\),且这些点符合函数的规则,每个x对应唯一的y,我们总能用一个连续的多项式组合的函数,保证这个函数经过上面所有的点,而计算这个多项式的过程,我们就称为插值。插值是求值的逆过程,利用已有的点,反推出曲线的大致模样。

插值的思想和泰勒很类似,就是说如果观测误差足够小的时候,那么就认为它就是准确的值。我们给定的点符合\(f(x_i)=y_i\),那么我们的插值构造函数就是\(g(x_i)=y_i\)。

通常我们采用累加的多项式进行插值计算,因为我们的计算都是建立在计算机之上,计算机对于特殊的运算是非常缓慢且复杂的,例如之前提到的泰勒展开,因此我们尽可能需要将计算变成四则运算,同时我们的插值函数还需要保证解的唯一性,因此我们通常将插值函数写成如下形式:

\[P(x) = \sum_{i=0}^{n}a_{i}x^{i} \]

利用多项式幂函数和作为插值函数的好处是,它是恒可微的,并不需要像泰勒展开一样,需要先确定可微分的函数才可以继续求解。同时至于这种方式的唯一性,我们可以做一个简单的推导。

假设给定了n+1个数据采样\((x_1,y_1),(x_2,y_2)\dotsb(x_{n+1},y_{n+1})\),根据插值法的规则,那么我们构造出的多项式必然满足下列方程组:

\[\left\{\begin{matrix} p(x_0) = a_0+a_1x_0+a_2x_{0}^2+\dotsb+a_nx_{0}^n = y_0 \\ p(x_1) = a_0+a_1x_1+a_2x_{1}^2+\dotsb+a_nx_{1}^n = y_1 \\ p(x_2) = a_0+a_1x_2+a_2x_{2}^2+\dotsb+a_nx_{2}^n = y_2\\ \vdots \\ p(x_n) = a_0+a_1x_n+a_2x_{n}^2+\dotsb+a_nx_{n}^n = y_n \end{matrix}\right. \]

如果熟悉线性代数,我们可以很清楚的发现这是一个非齐次线性方程组(a为未知数),我们可以得到该方程组的\(Vandermonde\)行列式

\[P = VA=Y \Leftrightarrow \begin{bmatrix} 1 & x_0&x_{0}^{2} &\cdots & x_{0}^{n} \\ 1 & x_1&x_{1}^{2} &\cdots & x_{1}^{n} \\ \vdots&\vdots&\vdots&\vdots&\vdots\\ 1 & x_n&x_{n}^{2} &\cdots & x_{n}^{n} \end{bmatrix} \begin{bmatrix} a_0\\ a_1\\ \vdots\\ a_n \end{bmatrix}= \begin{bmatrix} y_0\\ y_1\\ \vdots\\ y_n \end{bmatrix} \]

故有

\[\begin{vmatrix}V\end{vmatrix} = \begin{vmatrix} 1 & x_0&x_{0}^{2} &\cdots & x_{0}^{n} \\ 1 & x_1&x_{1}^{2} &\cdots & x_{1}^{n} \\ \vdots&\vdots&\vdots&\vdots&\vdots\\ 1 & x_n&x_{n}^{2} &\cdots & x_{n}^{n} \end{vmatrix} = \prod_{i=1}^{n}\prod_{j=0}^{n}(x_i-x_j) \]

因为我们取得采样点都是不同的点,因此可以保证有\(x_i \neq x_j\),那么根据\(Cramer\)法则,该\(Vandermonde\)行列式必有唯一解,从而保证了我们的插值函数是唯一的。不过多项式插值也不是全无缺点的,计算复杂度较高、在端点出容易出现龙格现象(一种函数值的剧烈振荡)。这些问题我们将在后面进行讨论。

拉格朗日插值法

拉格朗日插值是一种朴素拟合的手段,假设我们给定n个数据点\((x_1,y_1),(x_2,y_2)\dotsb(x_n,y_n)\),拉格朗日插值法,就是构造一条经过这些点的曲线(如果本身的数据就存在大量误差,则只需要靠近而不需经过),用这条线去模拟实际的曲线。这个方法和我们通过两点构造一条直线的方法有异曲同工之妙,当我们代入一个值\(x_1\)之后,所有不能得到\(y_1\)的多项式都将系数为0。

一次线性插值

我们先从最容易的一次线性插值来入手,假设我们有曲线\(f(x_i) = y_i\),取两个采样点\(x(x_0,y_0),(x_1,y_1)\),我们一次线性插值则是使用一条直线来近似替代,那么我们需要构建一个函数,使得\(p(x_0)=y_0,p(x_1)=y_1\),那么可以作出这样一条直线(直线对称式):

\[p(x) = \frac{x-x_0}{x_0-x_1}y_0+\frac{x - x_1}{x_1-x_0}y_1 \]

我们看一个简单的函数拟合,已知\(y=\sqrt{x}\)的两个采样点\((100,10),(121,11)\),求\(\sqrt{115}\),我们利用线性插值法,可以计算出结果是10.7142,精确值为10.724,可见利用线性插值也具备三位有效数字。但是如果将值偏离采样点,例如我们需要计算\(\sqrt{2}\),精确值为1.414,而插值法计算出的值为5.333,一位有效数字都没有。

实际上我们利用信息的角度去考虑,比如在警察办案过程中,往往会涉及到一个犯罪嫌疑人画像的制作,如果说目击者告诉警察的有效信息为:犯罪分子是一个高鼻梁,蓝眼睛。那么警察在绘制图像的时候,眼睛和鼻子或者周边的颧骨可能会相对精确不少,但是通过鼻子和眼睛的信息,你让警察去猜想他是否是秃顶或者升高体重,自然会不准确。所以这里面也涉及到了一部分信息熵的内容,因为信息过少而导致的数据不精确。

拉格朗日插值

通过一次插值的实践过程和之前对于多项式插值的,我们知道采样点很少导致的信息缺失,那么我们就应该找到更多的采样点进行构造更好的多项式。

根据观察,其实我们可以思考一下,之前多项式插值法中,我们最终是需要通过行列式解出各个多项式的系数,那么我们假定为这样的插值函数

\[p(x)=\sum_{i=0}^{n}l_i(x)y_i \]

我们将多项式系数写为\(l(x)\)我们称为拉格朗日插值基函数。这个基函数必然满足

\[p(x_i)=y_i \\ l_i(x_k) =\begin{cases} 0,& k\neq i\\ 1,& k=0 \end{cases} \]

通过这个我们很容易分析出插值基函数\(l_i(x)\)有零点\(x_i\),其他的均为非零点,那么我们假设插值基函数为:

\[l_i(x) = C\prod_{k=0,k\neq i}^n (x-x_k) \]

同时因为\(l_i(x_i)=1\)可以继续确定常系数

\[C = \frac{1}{\prod_{k=0,k\neq i}^n (x_i-x_k)} \]

因此我们得到了我们的插值基函数和我们的插值拟合函数

\[l_i(x)=\prod_{k=0,k\neq i}\frac{x-x_k}{x_i-x_k} \\ p_n(x) = \sum_{i=0}^{n}l_i(x)y_i = \sum_{i=0}^{n}(\prod_{k=0,k\neq i}^n\frac{x-x_k}{x_i-x_k})\times y_i \]

因此,我们可以编写出一程序,作为我们拉格朗日插值法的

double[] Lagrange(double[]x,double[] y,double[] xi) { double[] result = new double[xi.Length]; if (x.Length != y.Length) { throw new ArgumentException("dim x not equal dim y"); } int n = x.Length; for (int k = 0; k < xi.Length; k++) { double value = 0; for (int i = 0; i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有