9.1 牛顿插值

  牛顿插值是两大多项式插值法interpolation的一种。所谓的多项式插值,直白了讲,就是从一堆 x , y x,y x,y的数据对中,回归出一个多项式函数,这样就可以预测不在数据对中的x的取值。我举个例子:
x 0 = 0 , y 0 = 1 x 1 = 2 , y 1 = 5 x 2 = 4 , y 2 = 17 x_0=0,y_0=1\\ x_1=2,y_1=5\\ x_2=4,y_2=17 x0=0,y0=1x1=2,y1=5x2=4,y2=17
  我们经过多项式插值,从这三对数据中推导出这三对数据符合如下方程:
y = x 2 + 1 y=x^2+1 y=x2+1
  于是我们就可以预测x等于其他值的时候,y等于多少了。之所以叫插值,是要求x在数据集的范围内,比如上述数据x的范围是 0 ≤ x ≤ 4 0\le x\le 4 0x4,那么我们只能预测x在这个范围内y的取值了。范围外的取值就是外推法extrapolation研究的内容了。
  牛顿插值分为两种,等距与不等距。等距是特殊情况,不等距才是一般情况。
  牛顿插值的一般公式如下:
P n ( x ) = ∑ j = 0 n α j e j ( x ) = α ( 0 ) + α 1 ( x − x 0 ) + α 2 ( x − x 0 ) ( x − x 1 ) + ⋯ + α n ( x − x 0 ) ( x − x 1 ) … ( x − x n − 1 ) P_n(x)=\sum_{j=0}^n \alpha_je_j(x)=\alpha(0)+\alpha_1(x-x_0)+\alpha_2(x-x_0)(x-x_1)\\ +\dots+\alpha_n(x-x_0)(x-x_1)\dots(x-x_{n-1}) Pn(x)=j=0nαjej(x)=α(0)+α1(xx0)+α2(xx0)(xx1)++αn(xx0)(xx1)(xxn1)
  这里的e比较容易得到:
e 0 = 1 e 1 = x − x 0 e 2 = ( x − x 0 ) ( x − x 1 ) e 3 = ( x − x 0 ) ( x − x 1 ) ( x − x 2 ) ⋮ e n = ( x − x 0 ) ( x − x 1 ) … ( x − x n − 1 ) e_0=1\\ e_1=x-x_0\\ e_2=(x-x_0)(x-x_1)\\ e_3=(x-x_0)(x-x_1)(x-x_2)\\ \vdots\\ e_n=(x-x_0)(x-x_1)\dots(x-x_{n-1})\\ e0=1e1=xx0e2=(xx0)(xx1)e3=(xx0)(xx1)(xx2)en=(xx0)(xx1)(xxn1)
  而难的是α,而α,是根据差商得到的。
α k = f [ x 1 , … , x k ] − f [ x 1 , … , x k − 1 ] x k − x 0 = f [ x 0 , … , x k ] \alpha_k=\frac{f[x_1,\dots,x_k]-f[x_1,\dots,x_{k-1}]}{x_k-x_0}=f[x_0,\dots,x_k] αk=xkx0f[x1,,xk]f[x1,,xk1]=f[x0,,xk]
  这是个递归公式:
α 0 = y 0 α 1 = f [ x 1 ] − f [ x 0 ] x 1 − x 0 = f [ x 0 , x 1 ] α k = f [ x 1 , … , x k ] − f [ x 0 , … , x k − 1 ] x k − x 0 = f [ x 0 , … , x k ] f [ i , j ] = f [ j ] − f [ i ] x j − x i α_0=y_0\\ \alpha_1=\frac{f[x_1]-f[x_0]}{x_1-x_0}=f[x_0,x_1]\\ \alpha_k=\frac{f[x_1,\dots,x_k]-f[x_0,\dots,x_{k-1}]}{x_k-x_0}=f[x_0,\dots,x_k]\\ f[i,j]=\frac{f[j]-f[i]}{x_j-x_i} α0=y0α1=x1x0f[x1]f[x0]=f[x0,x1]αk=xkx0f[x1,,xk]f[x0,,xk1]=f[x0,,xk]f[i,j]=xjxif[j]f[i]
  而递归就可以用动态规范的思想,缓存已有的数据来实现。
  所以基本算法是
  1 计算出e的多项式数组
  2 建立一个二维数组,缓存差商,然后全部计算出来
  3 将整个多项式建立起来,并且化简
  对于e这个多项式数组,n个数据,数组长度就是n。最后一项是n-1次幂。
  但是为了对齐,要将其变成同样长度的数组,所以整体是一个n*n的矩阵。
  建立差商二维数组时,可以按这样的规则
f [ i   j ] = f [ i ] [ j − i ] f[i~j] = f[i][j-i] f[i j]=f[i][ji]
  例如 f [ 2 , 3 , 4 , 5 ] = f [ 2 ] [ 3 ] f[2,3,4,5]=f[2][3] f[2,3,4,5]=f[2][3],所以 f [ 0 ] [ k ] = f [ 1 ] [ k − 1 ] − f [ 0 ] [ k − 1 ] / ( x k − x 0 ) f[0][k]=f[1][k-1]-f[0][k-1]/(x_k-x_0) f[0][k]=f[1][k1]f[0][k1]/(xkx0)
  在循环时,我们可以利用递归公式设置这个二维数组的值
  比如取到 x 3 , y 3 x_3,y_3 x3,y3时,可以设置 f [ 3 ] [ 0 ] = y 3 f[3][0]=y_3 f[3][0]=y3
  那同时 f [ 0 ] [ 3 ] , f [ 1 ] [ 2 ] , f [ 2 ] [ 1 ] f[0][3],f[1][2],f[2][1] f[0][3],f[1][2],f[2][1]的值也可以计算出来。
x 0 → f [ x 0 ] x 1 → f [ x 1 ] , f [ x 0 , x 1 ] x 2 → f [ x 2 ] , f [ x 1 , x 2 ] , f [ x 0 , x 1 , x 2 ] x 3 → f [ x 3 ] , f [ x 2 , x 3 ] , f [ x 1 , x 2 , x 3 ] , f [ x 0 , x 1 , x 2 , x 3 ] x_0 \to f [ x_0 ] \\ x_1 \to f [ x_1] ,f [ x_0 , x_1] \\ x_2\to f [ x_2] , f [ x_1 , x_2 ] , f [x_0 , x_1 , x_2] \\ x_3 \to f [ x_3 ] ,f [ x_2 , x_3 ] , f [x_1 , x_2 , x_3 ] , f [x_0 , x_1 , x_2 , x_3 ] x0f[x0]x1f[x1],f[x0,x1]x2f[x2],f[x1,x2],f[x0,x1,x2]x3f[x3],f[x2,x3],f[x1,x2,x3],f[x0,x1,x2,x3]
  所以:
  第一次循环计算出了 f [ 0 ] [ 0 ] f[0][0] f[0][0]
  第二次循环计算出了 f [ 1 ] [ 0 ] , f [ 0 ] [ 1 ] f[1][0] ,f[0][1] f[1][0],f[0][1]
  第三次循环计算出了 f [ 2 ] [ 0 ] , f [ 1 ] [ 1 ] , f [ 0 ] [ 2 ] f[2][0] ,f[1][1] ,f[0][2] f[2][0],f[1][1],f[0][2]
  第四次循环计算出了 f [ 3 ] [ 0 ] , f [ 2 ] [ 1 ] , f [ 1 ] [ 2 ] , f [ 0 ] [ 3 ] f[3][0] ,f[2][1] ,f[1][2] ,f[0][3] f[3][0],f[2][1],f[1][2],f[0][3]
  第五次循环计算出了 f [ 4 ] [ 0 ] , f [ 3 ] [ 1 ] , f [ 2 ] [ 2 ] , f [ 1 ] [ 3 ] , f [ 0 ] [ 4 ] f[4][0] ,f[3][1] ,f[2][2] ,f[1][3] ,f[0][4] f[4][0],f[3][1],f[2][2],f[1][3],f[0][4]
  记住这个小楼梯,每一个等于左边相邻的减去左上角相邻的
  但是小循环要反过来
  以第四次循环为例子,先得到:
f [ 3 ] [ 0 ] = y 3 f [ 2 ] [ 1 ] = f [ 2 , 3 ] = ( f [ 3 ] [ 0 ] − f [ 2 ] [ 0 ] ) / ( x 3 − x 2 ) f [ 1 ] [ 2 ] = f [ 1 , 2 , 3 ] = ( f [ 2 , 3 ] − f [ 1 , 2 ] ) / ( x 3 − x 1 ) = ( f [ 2 ] [ 1 ] − f [ 1 ] [ 1 ] ) / ( x 3 − x 1 ) f [ 0 ] [ 3 ] = f [ 0 , 1 , 2 , 3 ] = ( f [ 1 , 2 , 3 ] − f [ 0 , 1 , 2 ] ) / ( x 3 − x 0 ) = ( f [ 1 ] [ 2 ] − f [ 0 ] [ 2 ] ) / ( x 3 − x 0 ) f[3][0]=y_3\\ f[2][1]=f[2,3]=( f[3][0]-f[2][0])/(x_3-x_2)\\ f[1][2]=f[1,2,3]= (f[2,3]-f[1,2])/(x_3-x_1)=(f[2][1]-f[1][1])/(x_3-x_1)\\ f[0][3]=f[0,1,2,3]=(f[1,2,3]-f[0,1,2])/(x_3-x_0)=(f[1][2]-f[0][2])/(x_3-x_0)\\ f[3][0]=y3f[2][1]=f[2,3]=(f[3][0]f[2][0])/(x3x2)f[1][2]=f[1,2,3]=(f[2,3]f[1,2])/(x3x1)=(f[2][1]f[1][1])/(x3x1)f[0][3]=f[0,1,2,3]=(f[1,2,3]f[0,1,2])/(x3x0)=(f[1][2]f[0][2])/(x3x0)
  所以核心python代码如下:

# _*_ coding:utf-8 _*_
# 牛顿多项式
from com.youngthing.mathalgorithm.polynomial import polynomial_simplify
from com.youngthing.mathalgorithm.interpolation.horner_polynominal import HornerPolynomial


def get_polynomial(data, n):
    arr = [0 for _ in data]
    if n == 0:
        arr[len(data) - 1] = 1
        return arr
    matrix = [[1, -data[i][0]] for i in range(0, n)]
    # 造一个多项式矩阵
    p = polynomial_simplify(matrix)
    # 不足的在前面补0
    r = [0] * (len(data) - len(p))
    r.extend(p)
    return r


def interpolate(data: list):
    # 首先定义数组e
    e = [get_polynomial(data, i) for i, datum in enumerate(data)]
    # 再次是定义两个差商数组
    # 差商应该是一个二维数组吧
    size = len(data)
    f = [[0] * (size - index) for index, datum in enumerate(data)]
    for i in range(0, size):
        for j in range(0, i + 1):
            yi = data[i][1]
            xi = data[i][0]
            f[i - j][j] = yi if j == 0 else (f[i - j + 1][j - 1] - f[i - j][j - 1]) / (xi - data[i - j][0])
    # 差商数组完成
    # 最后把多项式求和 如果数组长度为s,那么多项式最高s-1次,有s项
    polynomial = [0] * size
    print(e)
    for i in range(0, size):
        # i代表每个相加项
        # 每一项都是同幂项系数相加
        # j代表多项式从高到低的幂次
        for j in range(0, size):
            polynomial[j] += f[0][i] * e[i][j]
    return HornerPolynomial(polynomial)

  而霍纳多项式的代码,我就不写出来了
  测试代码:

from com.youngthing.mathalgorithm.interpolation import newton

if __name__ == '__main__':

    #测试数据
    data=[[0,1],[2,5],[4,17]]
    polynomial = newton.interpolate(data)
    print(polynomial(0),polynomial(2),polynomial(4))
    print(polynomial(1),polynomial(3),polynomial(5))
    print(polynomial)
    print(polynomial.polynomial)

  测试结果

1.0 5.0 17.0
2.0 10.0 26.0
x**2+1
[1.0, 0.0, 1.0]

你可能感兴趣的:(数学算法【更新中】,算法)