实数插值方法及其 python 实现

7 篇文章 3 订阅
7 篇文章 3 订阅

本文主要介绍两种常用的实数插值方法:拉格朗日(Lagrange)插值 以及 牛顿(Newton)插值 及其python实现。运行效果如下:

目录

1、拉格朗日插值

2、牛顿插值

3、python 实现


1、拉格朗日插值

拉格朗日(Lagrange)插值基函数:

 N次插值多项式:

拉格朗日插值多项式的推到如下:

2、牛顿插值

Lagrange插值多项式计算简单便于编程计算,但是如果要增加一个节点,Lagrange插值多项式除增加的一项外,原来的每一项都需要改变。而Newton插值多项式在增加一个节点时只需要在原来的插值多项式中增加一项,而不需要改变原来的项。引出牛顿插值多项式首先要了解差商的概念。

Newton插值多项式为: 

3、python 实现

import matplotlib.pyplot as plt
import numpy as np
import warnings


"""
 @功能:Lagrange 插值法 两点一次插值(线性插值)
 @参数:
    L1:需要进行插值的数据列表,待插值地方留空或置零
        如[0, 0, 1, 0, 0, 4, 0, 5], 代表第0, 1, 3、4、6个位置需要进行插值,其余位置为插值节点
        如果插值节点为0时,通过设置 nodeIndex 参数即可进行标定
    nodeIndex :list2inter 中代表插值节点的位置索引,接上例,nodeIndex=[2,5,7]
"""
def Lagrange1(L1=[], nodeIndex=[]):
    assert (nodeIndex[0] >= 0) and (nodeIndex[-1] < len(L1)), '输入节点索引越界'
    assert len(nodeIndex) >= 2, '输入节点数必须不小于2'
    # 两端位置直接赋边缘值
    if nodeIndex[0] != 0:
        for i in range(nodeIndex[0]):
            L1[i] = L1[nodeIndex[0]]
    if nodeIndex[-1] != len(L1)-1:
        for i in range(nodeIndex[-1], len(L1)):
            L1[i] = L1[nodeIndex[-1]]
    # 需要插值的缝隙数量
    n_inter_space = len(nodeIndex)-1
    for i in range(n_inter_space):
        for j in range(nodeIndex[i]+1, nodeIndex[i+1]):
            # 点斜式  L(x) = y0 + [(y1-y0)/(x1-x0)](x-x0)
            L1[j] = L1[nodeIndex[i]] + \
                            (L1[nodeIndex[i+1]] - L1[nodeIndex[i]]) / (nodeIndex[i+1] - nodeIndex[i]) * \
                            (j - nodeIndex[i])
    return L1


"""
 @功能:Lagrange 三点二次平滑插值,对两端不进行插值
 @参数:
    L2:需要进行插值的数据列表,待插值地方留空或置零
        如[0, 0, 1, 0, 0, 4, 0, 5], 代表第0, 1, 3、4、6个位置需要进行插值,其余位置为插值节点
        如果插值节点为0时,通过设置 nodeIndex 参数即可进行标定
    nodeIndex :list2inter 中代表插值节点的位置索引,接上例,nodeIndex=[2,5,7]
"""
def Lagrange2_smooth(L2=[], nodeIndex=[]):
    assert (nodeIndex[0] >= 0) and (nodeIndex[-1] < len(L2)), '输入节点索引越界'
    assert len(nodeIndex) >= 3, '输入节点数必须不小于3'
    # 两端位置直接赋边缘值
    if nodeIndex[0] != 0:
        for i in range(nodeIndex[0]):
            L2[i] = L2[nodeIndex[0]]
    if nodeIndex[-1] != len(L2)-1:
        for i in range(nodeIndex[-1], len(L2)):
            L2[i] = L2[nodeIndex[-1]]
    # 需要插值的缝隙数量
    n_inter_space = len(nodeIndex)-1
    for i in range(n_inter_space-1):
        for j in range(nodeIndex[i]+1, nodeIndex[i+2]):
            # 代入公式
            if i != 0 and j < nodeIndex[i+1]:
                L2[j] = 0.5 * \
                        (L2[j] + \
                        (j - nodeIndex[i+1]) * (j - nodeIndex[i+2]) / ((nodeIndex[i  ] - nodeIndex[i+1]) * (nodeIndex[i  ] - nodeIndex[i+2])) * L2[nodeIndex[i  ]] + \
                        (j - nodeIndex[i  ]) * (j - nodeIndex[i+2]) / ((nodeIndex[i+1] - nodeIndex[i  ]) * (nodeIndex[i+1] - nodeIndex[i+2])) * L2[nodeIndex[i+1]] + \
                        (j - nodeIndex[i  ]) * (j - nodeIndex[i+1]) / ((nodeIndex[i+2] - nodeIndex[i  ]) * (nodeIndex[i+2] - nodeIndex[i+1])) * L2[nodeIndex[i+2]] )
            else:
                L2[j] = (j - nodeIndex[i+1]) * (j - nodeIndex[i+2]) / ((nodeIndex[i  ] - nodeIndex[i+1]) * (nodeIndex[i  ] - nodeIndex[i+2])) * L2[nodeIndex[i  ]] + \
                        (j - nodeIndex[i  ]) * (j - nodeIndex[i+2]) / ((nodeIndex[i+1] - nodeIndex[i  ]) * (nodeIndex[i+1] - nodeIndex[i+2])) * L2[nodeIndex[i+1]] + \
                        (j - nodeIndex[i  ]) * (j - nodeIndex[i+1]) / ((nodeIndex[i+2] - nodeIndex[i  ]) * (nodeIndex[i+2] - nodeIndex[i+1])) * L2[nodeIndex[i+2]] 
    return L2


"""
 @功能:Lagrange 三点二次平滑插值,对两端也进行插值
 @参数:
    L2:需要进行插值的数据列表,待插值地方留空或置零
        如[0, 0, 1, 0, 0, 4, 0, 5], 代表第0, 1, 3、4、6个位置需要进行插值,其余位置为插值节点
        如果插值节点为0时,通过设置 nodeIndex 参数即可进行标定
    nodeIndex :list2inter 中代表插值节点的位置索引,接上例,nodeIndex=[2,5,7]
"""
def Lagrange2_smooth_padding(L2=[], nodeIndex=[]):
    assert (nodeIndex[0] >= 0) and (nodeIndex[-1] < len(L2)), '输入节点索引越界'
    assert len(nodeIndex) >= 3, '输入节点数必须不小于3'
    # 需要插值的缝隙数量
    n_inter_space = len(nodeIndex)-1
    for i in range(n_inter_space-1):
        # 处理开头空白处的数据
        if nodeIndex[0] != 0 and i == 0:
            for j in range(nodeIndex[0]):
                L2[j] = (j - nodeIndex[1]) * (j - nodeIndex[2]) / ((nodeIndex[0] - nodeIndex[1]) * (nodeIndex[0] - nodeIndex[2])) * L2[nodeIndex[0]] + \
                        (j - nodeIndex[0]) * (j - nodeIndex[2]) / ((nodeIndex[1] - nodeIndex[0]) * (nodeIndex[1] - nodeIndex[2])) * L2[nodeIndex[1]] + \
                        (j - nodeIndex[0]) * (j - nodeIndex[1]) / ((nodeIndex[2] - nodeIndex[0]) * (nodeIndex[2] - nodeIndex[1])) * L2[nodeIndex[2]] 
        # 处理结尾空白处的数据
        if nodeIndex[-1] != len(L2)-1 and i == n_inter_space-2:
            for j in range(nodeIndex[-1], len(L2)):
                L2[j] = (j - nodeIndex[n_inter_space-1]) * (j - nodeIndex[n_inter_space  ]) / ((nodeIndex[n_inter_space-2] - nodeIndex[n_inter_space-1]) * (nodeIndex[n_inter_space-2  ] - nodeIndex[n_inter_space  ])) * L2[nodeIndex[n_inter_space-2]] + \
                        (j - nodeIndex[n_inter_space-2]) * (j - nodeIndex[n_inter_space  ]) / ((nodeIndex[n_inter_space-1] - nodeIndex[n_inter_space-2]) * (nodeIndex[n_inter_space-2+1] - nodeIndex[n_inter_space  ])) * L2[nodeIndex[n_inter_space-1]] + \
                        (j - nodeIndex[n_inter_space-2]) * (j - nodeIndex[n_inter_space-1]) / ((nodeIndex[n_inter_space  ] - nodeIndex[n_inter_space-2]) * (nodeIndex[n_inter_space-2+2] - nodeIndex[n_inter_space-1])) * L2[nodeIndex[n_inter_space  ]] 
        # 处理一般位置的数据
        for j in range(nodeIndex[i]+1, nodeIndex[i+2]):
            # 代入公式
            if i != 0 and j < nodeIndex[i+1]:
                L2[j] = 0.5 * \
                        (L2[j] + \
                        (j - nodeIndex[i+1]) * (j - nodeIndex[i+2]) / ((nodeIndex[i  ] - nodeIndex[i+1]) * (nodeIndex[i  ] - nodeIndex[i+2])) * L2[nodeIndex[i  ]] + \
                        (j - nodeIndex[i  ]) * (j - nodeIndex[i+2]) / ((nodeIndex[i+1] - nodeIndex[i  ]) * (nodeIndex[i+1] - nodeIndex[i+2])) * L2[nodeIndex[i+1]] + \
                        (j - nodeIndex[i  ]) * (j - nodeIndex[i+1]) / ((nodeIndex[i+2] - nodeIndex[i  ]) * (nodeIndex[i+2] - nodeIndex[i+1])) * L2[nodeIndex[i+2]] )
            else:
                L2[j] = (j - nodeIndex[i+1]) * (j - nodeIndex[i+2]) / ((nodeIndex[i  ] - nodeIndex[i+1]) * (nodeIndex[i  ] - nodeIndex[i+2])) * L2[nodeIndex[i  ]] + \
                        (j - nodeIndex[i  ]) * (j - nodeIndex[i+2]) / ((nodeIndex[i+1] - nodeIndex[i  ]) * (nodeIndex[i+1] - nodeIndex[i+2])) * L2[nodeIndex[i+1]] + \
                        (j - nodeIndex[i  ]) * (j - nodeIndex[i+1]) / ((nodeIndex[i+2] - nodeIndex[i  ]) * (nodeIndex[i+2] - nodeIndex[i+1])) * L2[nodeIndex[i+2]] 
    return L2

"""
 @功能:Lagrange 三点二次插值, 对两侧也进行插值
 @参数:
    L2:需要进行插值的数据列表,待插值地方留空或置零
        如[0, 0, 1, 0, 0, 4, 0, 5], 代表第0, 1, 3、4、6个位置需要进行插值,其余位置为插值节点
        如果插值节点为0时,通过设置 nodeIndex 参数即可进行标定
    nodeIndex :list2inter 中代表插值节点的位置索引,接上例,nodeIndex=[2,5,7]
"""
def Lagrange2_padding(L2=[], nodeIndex=[]):
    assert (nodeIndex[0] >= 0) and (nodeIndex[-1] < len(L2)), '输入节点索引越界'
    assert len(nodeIndex) >= 3, '输入节点数必须不小于3'
    # 需要插值的缝隙数量
    n_inter_space = len(nodeIndex)-1
    for i in range(n_inter_space-1):
        # 处理开头空白处的数据
        if nodeIndex[0] != 0 and i == 0:
            for j in range(nodeIndex[0]):
                L2[j] = (j - nodeIndex[1]) * (j - nodeIndex[2]) / ((nodeIndex[0] - nodeIndex[1]) * (nodeIndex[0] - nodeIndex[2])) * L2[nodeIndex[0]] + \
                        (j - nodeIndex[0]) * (j - nodeIndex[2]) / ((nodeIndex[1] - nodeIndex[0]) * (nodeIndex[1] - nodeIndex[2])) * L2[nodeIndex[1]] + \
                        (j - nodeIndex[0]) * (j - nodeIndex[1]) / ((nodeIndex[2] - nodeIndex[0]) * (nodeIndex[2] - nodeIndex[1])) * L2[nodeIndex[2]] 
        # 处理结尾空白处的数据
        if nodeIndex[-1] != len(L2)-1 and i == n_inter_space-2:
            for j in range(nodeIndex[-1], len(L2)):
                L2[j] = (j - nodeIndex[n_inter_space-1]) * (j - nodeIndex[n_inter_space  ]) / ((nodeIndex[n_inter_space-2] - nodeIndex[n_inter_space-1]) * (nodeIndex[n_inter_space-2  ] - nodeIndex[n_inter_space  ])) * L2[nodeIndex[n_inter_space-2]] + \
                        (j - nodeIndex[n_inter_space-2]) * (j - nodeIndex[n_inter_space  ]) / ((nodeIndex[n_inter_space-1] - nodeIndex[n_inter_space-2]) * (nodeIndex[n_inter_space-2+1] - nodeIndex[n_inter_space  ])) * L2[nodeIndex[n_inter_space-1]] + \
                        (j - nodeIndex[n_inter_space-2]) * (j - nodeIndex[n_inter_space-1]) / ((nodeIndex[n_inter_space  ] - nodeIndex[n_inter_space-2]) * (nodeIndex[n_inter_space-2+2] - nodeIndex[n_inter_space-1])) * L2[nodeIndex[n_inter_space  ]] 

        for j in range(nodeIndex[i]+1, nodeIndex[i+2]):
            # 代入公式
            L2[j] = (j - nodeIndex[i+1]) * (j - nodeIndex[i+2]) / ((nodeIndex[i  ] - nodeIndex[i+1]) * (nodeIndex[i  ] - nodeIndex[i+2])) * L2[nodeIndex[i  ]] + \
                            (j - nodeIndex[i  ]) * (j - nodeIndex[i+2]) / ((nodeIndex[i+1] - nodeIndex[i  ]) * (nodeIndex[i+1] - nodeIndex[i+2])) * L2[nodeIndex[i+1]] + \
                            (j - nodeIndex[i  ]) * (j - nodeIndex[i+1]) / ((nodeIndex[i+2] - nodeIndex[i  ]) * (nodeIndex[i+2] - nodeIndex[i+1])) * L2[nodeIndex[i+2]] 
    return L2



"""
 @功能:Lagrange 三点二次插值
 @参数:
    L2:需要进行插值的数据列表,待插值地方留空或置零
        如[1, 0, 0, 4, 0, 5], 代表第2、3、5个位置需要进行插值,其余位置为插值节点
        如果插值节点为0时,通过设置 nodeIndex 参数即可进行标定
    nodeIndex :list2inter 中代表插值节点的位置索引,接上例,nodeIndex=[0,3,5]
"""
def Lagrange2(L2=[], nodeIndex=[]):
    assert (nodeIndex[0] >= 0) and (nodeIndex[-1] < len(L2)), '输入节点索引越界'
    assert len(nodeIndex) >= 3, '输入节点数必须不小于3'
    # 两端位置直接赋边缘值
    if nodeIndex[0] != 0:
        for i in range(nodeIndex[0]):
            L2[i] = L2[nodeIndex[0]]
    if nodeIndex[-1] != len(L2)-1:
        for i in range(nodeIndex[-1], len(L2)):
            L2[i] = L2[nodeIndex[-1]]
    # 需要插值的缝隙数量
    n_inter_space = len(nodeIndex)-1
    for i in range(n_inter_space-1):
        for j in range(nodeIndex[i]+1, nodeIndex[i+2]):
            # 代入公式
            L2[j] = (j - nodeIndex[i+1]) * (j - nodeIndex[i+2]) / ((nodeIndex[i  ] - nodeIndex[i+1]) * (nodeIndex[i  ] - nodeIndex[i+2])) * L2[nodeIndex[i  ]] + \
                            (j - nodeIndex[i  ]) * (j - nodeIndex[i+2]) / ((nodeIndex[i+1] - nodeIndex[i  ]) * (nodeIndex[i+1] - nodeIndex[i+2])) * L2[nodeIndex[i+1]] + \
                            (j - nodeIndex[i  ]) * (j - nodeIndex[i+1]) / ((nodeIndex[i+2] - nodeIndex[i  ]) * (nodeIndex[i+2] - nodeIndex[i+1])) * L2[nodeIndex[i+2]] 
    return L2


"""
 @功能:计算 n 次差商
 @参数:
    list2inter:需要进行插值的数据列表,待插值地方留空或置零
                如[1, 0, 0, 4, 0, 5], 代表第2、3、5个位置需要进行插值,其余位置为插值节点
                如果插值节点为0时,通过设置 nodeIndex 参数即可进行标定
    nodeIndex :list2inter 中代表插值节点的位置索引,接上例,nodeIndex=[0,3,5]
           n  :差商的次数,需要 nodeIndex 中至少包含 n+1 个节点,多余的节点会自动忽略掉
                只计算前 n+1 个节点位置的差商值
"""
def difference_quotient(list2inter=[], nodeIndex=[], n=1):
    if n >= 7:
        warnings.warn("高次插值可能出现 Runge 现象")
    assert (nodeIndex[0] >= 0) and (nodeIndex[-1] < len(list2inter)), '输入节点索引越界'
    assert len(nodeIndex) != 0 or len(list2inter) != 0, '输入节点不能为空'
    # 只截取 n+1 个参数进行计算
    nodeIndex = nodeIndex[:n+1]
    def iter_body(nodeIndex=[]):
        if len(nodeIndex) == 1:
            return list2inter[nodeIndex[0]]
        left = nodeIndex[:-1]  # 取左边 n-1 个值
        right = nodeIndex[1:]  # 取右边 n-1 个值
        return (iter_body(left) - iter_body(right)) / (left[0] - right[-1])

    return iter_body(nodeIndex)


"""
 @功能:计算(x-x0)(x-x1)(x-x2)...(x-xn-1)
 @参数:
    nodeIndex :list2inter 中代表插值节点的位置索引,接上例,nodeIndex=[0,3,5]
            x :插值节点的索引值(变量值)
            n :乘法的次数 如:n=3,则结果为 (x-x0)(x-x1)(x-x2)
"""
def mul_n(nodeIndex=[], x=0, n=0):
    assert len(nodeIndex) >= n, "输入节点数量达不到目标乘法次数的要求"
    result = 1
    for i in range(n):
        result = result * (x - nodeIndex[i])
    return result


"""
 @功能:计算 Newton 插值 建议最高使用 5 次差商,次数太高可能会出现 Runge 现象
 @参数:
    list2inter:需要进行插值的数据列表,待插值地方留空或置零
                如[1, 0, 0, 4, 0, 5], 代表第2、3、5个位置需要进行插值,其余位置为插值节点
                如果插值节点为0时,通过设置 nodeIndex 参数即可进行标定
    nodeIndex :list2inter 中代表插值节点的位置索引,接上例,nodeIndex=[0,3,5]
           n  :插值的次数,需要 nodeIndex 中至少包含 n+1 个节点,多余的节点会自动忽略掉
                只计算前 n+1 个节点位置的差商值
"""
def Newton_inter(list2inter=[], nodeIndex=[], n=1):
    assert len(nodeIndex) >= n+1, "输入节点数量达不到目标插值次数的要求"
    # 如果节点数大于插值所需,则取插值到第一个多余节点的前一个数值
    if len(nodeIndex) > n+1:
        num = nodeIndex[n+1]
    else:
        num = len(list2inter)

    dq = [0 for i in range(n+1)]
    for i in range(n+1):
        dq[i] = difference_quotient(list2inter, nodeIndex, i)

    for x in range(num):
        if x in nodeIndex:
            continue
        for j in range(n+1):
            list2inter[x] += dq[j] * mul_n(nodeIndex, x, j)

    return list2inter


L =         [0, 1, 0, 0, 0, 0, 8, 0, 0, 0, 0, 6, 0, 0, 18, 0, 0, 0, 12, 0, 0, 0]
nodeIndex = [   1,             6,            11,       14,          18]

temp = L.copy()
temp1 = L.copy()
temp2 = L.copy()
temp3 = L.copy()
temp4 = L.copy()

plt.figure()
plt.plot(nodeIndex, np.array(L)[nodeIndex], 'mo', label='L0')

inter1 = Lagrange1(L, nodeIndex=nodeIndex)
inter2 = Lagrange2(temp, nodeIndex=nodeIndex)
inter3 = Lagrange2_padding(temp4, nodeIndex=nodeIndex)
inter4 = Lagrange2_smooth(temp1, nodeIndex=nodeIndex)
inter5 = Lagrange2_smooth_padding(temp3, nodeIndex=nodeIndex)
inter6 = Newton_inter(temp2, nodeIndex=nodeIndex, n=4)

plt.plot(range(len(L)), inter1, 'r-', label='L1')
plt.plot(range(len(L)), inter2, 'c:', label='L2')
plt.plot(range(len(L)), inter3, 'g<', label='L2_padding')
plt.plot(range(len(L)), inter4, 'k-.', label='L2_smooth')
plt.plot(range(len(L)), inter5, 'r:', label='L2_smooth_padding')
plt.plot(range(len(L)), inter6, 'b--', label='Newton')

plt.legend(loc='best')
plt.show()

运行结果在文章开头已展示。 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

地球被支点撬走啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值