[数值计算-14]:拉格朗日插值与Python代码实现

Posted 文火冰糖的硅基工坊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[数值计算-14]:拉格朗日插值与Python代码实现相关的知识,希望对你有一定的参考价值。

作者主页(文火冰糖的硅基工坊):https://blog.csdn.net/HiWangWenBing

本文网址:https://blog.csdn.net/HiWangWenBing/article/details/119967939


目录

第1章 案例与建模

1.1 案例说明

 1.2 建模与预测​

第2章 插值

2.1 什么是插值

2.2 插值的关键是如何构建插值函数!!!

第3章 拉格朗日插值

3.1 拉格朗日插值的基本思想

3.2 拉格朗日基函数

3.3 拉格朗日插值函数

3.3 拉格朗日2点插值公式拆解

3.4 拉格朗日3点插值公式

3.5 拉格朗日插值的优缺点

第4章 拉格朗日通用函数的Python实现

4.1 通用的基函数的定义

4.2 通用的插值函数的定义

4.3 拉格朗日2点插值代码示例

4.4 拉格朗日3点插值代码示例

4.5 拉格朗日4点插值代码示例




第1章 案例与建模

1.1 案例说明

 1.2 建模与预测

第2章 插值

2.1 什么是插值

 

 这里的插值条件是:插值函数要经过所有现有的样本点!!!

 这个插值条件的优点:在样本点的误差为0。

 这个插值条件的缺点:这个条件还是比较苛刻的,导致选用高次函数,且样本点的个数越多,函数的最高次的次数越高。

2.2 插值的关键是如何构建插值函数!!!

第3章 拉格朗日插值

有没有一种插值方法,不需要求解线性方程组,只需要对样本点数据进行数值计算,就可以获取插值函数,拉格朗日插值就是这样的一种插值方法。

3.1 拉格朗日插值的基本思想

假如有N+1个采样点,能否在每个采样点Xk处,都构建这样的一个n次多项式函数Lk(x),该该函数满足:

(1) 当i = k是,Lk(Xi) = Yi

(2) 当i != k是,Lk(Xi) = 0

这样,把所有点的n次多项式进行累加,这样就可以得到N+1个采样点的多项式插值函数。

其中Lk(x)为基函数,累计后的函数为插值函数

3.2 拉格朗日基函数

基函数的次数与采样点的个数有对应的关系,N+1点,基函数的次数就是N。

3.3 拉格朗日插值函数

 插值函数是基函数的简单的线性相加。

3.3 拉格朗日2点插值公式拆解

(1)公式描述

 (2)代码示例:2个采样点数据

#导入库
from math import *
import time
import numpy as np
import matplotlib.pyplot as plt
from pylab import mpl


print('两点插值的采样数据:')
x_samples_dot2 = [1, 2]#创建x列表存储数据x值
y_samples_dot2 = [4, 8]#创建y列表存储数据的y值
print("X:", x_samples_dot2)
print("Y:", y_samples_dot2)
plt.scatter(x_samples_dot2, y_samples_dot2, label="sample", color="black")
plt.plot   (x_samples_dot2, y_samples_dot2, label="sample", color="red")

mpl.rcParams['font.sans-serif'] = ['SimHei'] #设置中文字体
mpl.rcParams['axes.unicode_minus'] = False
plt.title("Dot2 采样数据")
plt.legend(loc="upper left")
plt.show()

 输出:

两点插值的采样数据:
X: [1, 2]
Y: [4, 8]

 (3)代码示例:两点插值的分解与叠加

# 插值基函数
#L0(x) = y0 * (x-x1)/(x0-x1)
def Dot2_L0(x, x_data,y_data):
    return (y_data[0] * (x-x_data[1])/(x_data[0]-x_data[1]))

#L1(x) = y1 * (x-x0)/(x1-x0)
def Dot2_L1(x, x_data,y_data):
    return (y_data[1] * (x-x_data[0])/(x_data[1]-x_data[0]))

# 插值函数:是基函数的线性叠加
def Dot2_F(x, x_data, y_data):
    return (Dot2_L0(x, x_data,y_data) + Dot2_L1(x, x_data,y_data))


#基函数的预测
#输入x数据序列
x_data_predict_dot2 = np.arange(0, 3, 0.2)

#基函数L0的预测序列
y_data_predict_dot2_L0 = Dot2_L0(x_data_predict_dot2, x_samples_dot2, y_samples_dot2)

#基函数L1的预测序列
y_data_predict_dot2_L1 = Dot2_L1(x_data_predict_dot2, x_samples_dot2, y_samples_dot2)

#插值函数的预测序列
y_data_predict_dot2_F = Dot2_F(x_data_predict_dot2, x_samples_dot2, y_samples_dot2)


#显示基函数与插值函数的图形
plt.scatter(x_samples_dot2, y_samples_dot2, label="sample", color="black")#画点
plt.plot   (x_data_predict_dot2, y_data_predict_dot2_L0, label="L0(x)", color="green")
plt.plot   (x_data_predict_dot2, y_data_predict_dot2_L1, label="L1(x)", color="blue")#画点
plt.plot   (x_data_predict_dot2, y_data_predict_dot2_F, label="f(x)", color="red")#画点

#设置属性
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
plt.title("Dot2 拉格朗日插值拟合过程")
plt.legend(loc="upper left")
plt.show()

输出结果:

 从上述图形可以看出:

  • 基函数L0(x) 是一条直线,且穿过(x0,y0)点。
  • 基函数L1(x) 是一条直线,且穿过(x1,y1)点。
  • 插值函数F(x) 是L0(x)和L1(x)的线性叠加,
  • 插值函数F(x) 也是一条直线,且同时穿过(x0,y0)点和(x1,y1)点。

3.4 拉格朗日3点插值公式

(1)公式描述

(2)代码示例:样本点图形

print('三点插值的采样数据:')
x_samples_dot3 = [1, 2, 3]#创建x列表存储数据x值
y_samples_dot3 = [4, 8, 6]#创建y列表存储数据的y值
print("X:", x_samples_dot3)
print("Y:", y_samples_dot3)
plt.scatter(x_samples_dot3, y_samples_dot3, label="sample", color="black")#画点
plt.plot   (x_samples_dot3, y_samples_dot3, label="sample", color="red")#画点

plt.title("Dot3 采样数据")
plt.legend(loc="upper left")
plt.show()

输出:

三点插值的采样数据:
X: [1, 2, 3]
Y: [4, 8, 6]

(3)代码示例:两点插值的分解与叠加

# 基函数
#L0(x) = y0 * ((x-x1)*(x-x2))/((x0-x1)*(x0-x2))
def Dot3_L0(x, x_data,y_data):
    return (y_data[0] * ((x-x_data[1]) * (x-x_data[2]))/((x_data[0]-x_data[1]) * (x_data[0]-x_data[2])))

#L1(x) = y1 * ((x-x0)*(x-x2))/((x1-x0)*(x1-x2))
def Dot3_L1(x, x_data,y_data):
    return (y_data[1] * ((x-x_data[0]) * (x-x_data[2]))/((x_data[1]-x_data[0]) * (x_data[1]-x_data[2])))

#L0(x) = y2 * ((x-x0)*(x-x1))/((x2-x0)*(x2-x1))
def Dot3_L2(x, x_data,y_data):
    return (y_data[2] * ((x-x_data[0]) * (x-x_data[1]))/((x_data[2]-x_data[0]) * (x_data[2]-x_data[1])))

#插值函数:是基函数的线性叠加
def Dot3_F(x, x_data, y_data):
    return (Dot3_L0(x, x_data,y_data) + Dot3_L1(x, x_data,y_data) + Dot3_L2(x, x_data,y_data))


##函数的预测:输入数据序列为x
x_data_predict_dot3 = np.arange(0, 4.2, 0.2)

#基函数L0的预测序列
y_data_predict_dot3_L0 = Dot3_L0(x_data_predict_dot3, x_samples_dot3, y_samples_dot3)

#基函数L1的预测序列
y_data_predict_dot3_L1 = Dot3_L1(x_data_predict_dot3, x_samples_dot3, y_samples_dot3)

#基函数L2的预测序列
y_data_predict_dot3_L2 = Dot3_L2(x_data_predict_dot3, x_samples_dot3, y_samples_dot3)

#插值函数的预测序列
y_data_draw_dot3_F     = Dot3_F (x_data_predict_dot3, x_samples_dot3, y_samples_dot3)


#显示基函数与插值函数的关系
plt.scatter(x_samples_dot3, y_samples_dot3, label="sample", color="black")
plt.plot   (x_data_predict_dot3, y_data_predict_dot3_L0, label="L0(x)", color="green")
plt.plot   (x_data_predict_dot3, y_data_predict_dot3_L1, label="L1(x)", color="blue")
plt.plot   (x_data_predict_dot3, y_data_predict_dot3_L2, label="L2(x)", color="Orange")
plt.plot   (x_data_predict_dot3, y_data_draw_dot3_F, label="f(x)", color="red")

#设置属性
#mpl.rcParams['font.sans-serif'] = ['SimHei']
#mpl.rcParams['axes.unicode_minus'] = False
plt.title("Dot3 拉格朗日插值拟合过程")
plt.legend(loc="upper left")
plt.show()

输出结果:

从上述图形可以看出:

  • 基函数L0(x) 是一条抛物线,且穿过(x0,y0)点。
  • 基函数L1(x) 是一条抛物线,且穿过(x1,y1)点。
  • 基函数L2(x) 是一条抛物线,且穿过(x2,y2)点。
  • 插值函数F(x) 是L0(x)、L1(x)、L2(x)的线性叠加
  • 插值函数F(x)也是一条抛物线,且同时穿过(x0,y0),(x1,y1),(x2,y2)三个采样点。

3.5 拉格朗日插值的优缺点

(1)优点

  • 不需要用矩阵求解线性方程组,只需要简单的循环计算就可以得到插值函数。
  • 基函数的次数与采样点的个数有对应的关系,N+1点,基函数的次数就是N。
  • 插值函数是基函数的简单的线性相加。

(2)缺点

  • 当增加一个点或减少一个点时,需要全部重新计算,每个点的个数决定了每个点处的基函数的次数,当采样点的个数发生变化的时候,每个点处的基函数也发生了变化。因此所有的基函数都需要重选计算。

第4章 拉格朗日通用函数的Python实现

4.1 通用的基函数的定义

# 通用的基函数的定义
def LagrangeInterpolationDotN_Li(x, x_data, y_data, k):
    size = len(x_data)
    i = 0
    
    Ly = y_data[k]  # 初值为Yk
    
    while( i < size):
        if(i != k):
            Ly = Ly * (x-x_data[i])/(x_data[k]-x_data[i])
        i += 1
    return (Ly)

4.2 通用的插值函数的定义

# 通用的插值函数的定义
def LagrangeInterpolationDotN_F(x, x_data, y_data):
    size = len(x_data)
    k = 0
    sum = 0  # 初值为0

    while(k < size):
        sum = sum + LagrangeInterpolationDotN_Li(x, x_data, y_data, k)
        k += 1
    return (sum)

4.3 拉格朗日2点插值代码示例

(1)采样点

print('两点插值的采样数据:')
x_samples_dot2 = [1, 2]#创建x列表存储数据x值
y_samples_dot2 = [4, 8]#创建y列表存储数据的y值
print("X:", x_samples_dot2)
print("Y:", y_samples_dot2)
plt.scatter(x_samples_dot2, y_samples_dot2, label="sample", color="black")#画点
plt.plot   (x_samples_dot2, y_samples_dot2, label="sample", color="red")#画点

mpl.rcParams['font.sans-serif'] = ['SimHei'] #设置中文字体
mpl.rcParams['axes.unicode_minus'] = False
plt.title("LagrangeInterpolation Dot2 采样数据")
plt.legend(loc="upper left")
plt.show()

 (2)插值过程

#输入序列x
x_data_predict_dot2 = np.arange(0, 3, 0.2)

#基函数L0预测序列
y_data_predict_dot2_L0 = LagrangeInterpolationDotN_Li(x_data_predict_dot2, x_samples_dot2, y_samples_dot2, 0)

#基函数L1预测序列
y_data_predict_dot2_L1 = LagrangeInterpolationDotN_Li(x_data_predict_dot2, x_samples_dot2, y_samples_dot2, 1)

#插值函数预测序列
y_data_predict_dot2_F  = LagrangeInterpolationDotN_F (x_data_predict_dot2, x_samples_dot2, y_samples_dot2)


#显示图形
plt.scatter(x_samples_dot2, y_samples_dot2, label="sample", color="black")#画点
plt.plot   (x_data_predict_dot2, y_data_predict_dot2_L0, label="L0(x)", color="green")
plt.plot   (x_data_predict_dot2, y_data_predict_dot2_L1, label="L1(x)", color="blue")#画点
plt.plot   (x_data_predict_dot2, y_data_predict_dot2_F, label="f(x)", color="red")#画点

#设置属性
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
plt.title("Dot2 拉格朗日插值拟合过程")
plt.legend(loc="upper left")
plt.show()

输出:

 从上述图形可以看出:

  • 基函数L0(x) 是一条直线,且穿过(x0,y0)点。
  • 基函数L1(x) 是一条直线,且穿过(x1,y1)点。
  • 插值函数F(x) 是L0(x)和L1(x)的线性叠加,
  • 插值函数F(x) 也是一条直线,且同时穿过(x0,y0)点和(x1,y1)点。

4.4 拉格朗日3点插值代码示例

(1)采样点数据

print('三点插值的采样数据:')
x_samples_dot3 = [1, 2, 3]#创建x列表存储数据x值
y_samples_dot3 = [4, 8, 6]#创建y列表存储数据的y值
print("X:", x_samples_dot3)
print("Y:", y_samples_dot3)
plt.scatter(x_samples_dot3, y_samples_dot3, label="sample", color="black")#画点
plt.plot   (x_samples_dot3, y_samples_dot3, label="sample", color="red")#画点

plt.title("Dot3 采样数据")
plt.legend(loc="upper left")
plt.show()
三点插值的采样数据:
X: [1, 2, 3]
Y: [4, 8, 6]

(2)插值过程 

#输入序列x
x_data_predict_dot3 = np.arange(0, 4.2, 0.2)

#基函数L0预测序列
y_data_predict_dot3_L0 = LagrangeInterpolationDotN_Li(x_data_predict_dot3, x_samples_dot3, y_samples_dot3, 0)

#基函数L1预测序列
y_data_predict_dot3_L1 = LagrangeInterpolationDotN_Li(x_data_predict_dot3, x_samples_dot3, y_samples_dot3, 1)

#基函数L2预测序列
y_data_predict_dot3_L2 = LagrangeInterpolationDotN_Li(x_data_predict_dot3, x_samples_dot3, y_samples_dot3, 2)

#基函数L3预测序列
y_data_predict_dot3_F  = LagrangeInterpolationDotN_F (x_data_predict_dot3, x_samples_dot3, y_samples_dot3)


#图形显示
plt.scatter(x_samples_dot3, y_samples_dot3, label="sample", color="black")
plt.plot   (x_data_predict_dot3, y_data_predict_dot3_L0, label="L0(x)", color="green")
plt.plot   (x_data_predict_dot3, y_data_predict_dot3_L1, label="L1(x)", color="blue")
plt.plot   (x_data_predict_dot3, y_data_predict_dot3_L2, label="L2(x)", color="Orange")
plt.plot   (x_data_predict_dot3, y_data_draw_dot3_F, label="f(x)", color="red")

#设置属性
#mpl.rcParams['font.sans-serif'] = ['SimHei']
#mpl.rcParams['axes.unicode_minus'] = False
plt.title("Dot3 拉格朗日插值拟合过程")
plt.legend(loc="upper left")
plt.show()

 从上述图形可以看出:

  • 基函数L0(x) 是一条抛物线,且穿过(x0,y0)点。
  • 基函数L1(x) 是一条抛物线,且穿过(x1,y1)点。
  • 基函数L2(x) 是一条抛物线,且穿过(x2,y2)点。
  • 插值函数F(x) 是L0(x)、L1(x)、L2(x)的线性叠加
  • 插值函数F(x)也是一条抛物线,且同时穿过(x0,y0),(x1,y1),(x2,y2)三个采样点。

4.5 拉格朗日4点插值代码示例

(1)样本数据

print('四点插值的采样数据:')
x_samples_dot4 = [1, 2, 3, 4]#创建x列表存储数据x值
y_samples_dot4 = [4, 8, 6, 7]#创建y列表存储数据的y值
print("X:", x_samples_dot4)
print("Y:", y_samples_dot4)
plt.scatter(x_samples_dot4, y_samples_dot4, label="sample", color="black")#画点
plt.plot   (x_samples_dot4, y_samples_dot4, label="sample", color="red")#画点

plt.title("Dot4 采样数据")
plt.legend(loc="upper left")
plt.show()

输出:
四点插值的采样数据:
X: [1, 2, 3, 4]
Y: [4, 8, 6, 7]

(2)插值过程 

#输入序列x
x_data_predict_dot4 = np.arange(0, 5, 0.2)

#基函数L0预测序列
y_data_predict_dot4_L0 = LagrangeInterpolationDotN_Li(x_data_predict_dot4, x_samples_dot4, y_samples_dot4, 0)
#基函数L1预测序列
y_data_predict_dot4_L1 = LagrangeInterpolationDotN_Li(x_data_predict_dot4, x_samples_dot4, y_samples_dot4, 1)
#基函数L2预测序列
y_data_predict_dot4_L2 = LagrangeInterpolationDotN_Li(x_data_predict_dot4, x_samples_dot4, y_samples_dot4, 2)
#基函数L3预测序列
y_data_predict_dot4_L3 = LagrangeInterpolationDotN_Li(x_data_predict_dot4, x_samples_dot4, y_samples_dot4, 3)

#插值函数预测序列
y_data_predict_dot4_F  = LagrangeInterpolationDotN_F (x_data_predict_dot4, x_samples_dot4, y_samples_dot4)


#图形显示
plt.scatter(x_samples_dot4, y_samples_dot4, label="sample", color="black")
plt.plot   (x_data_predict_dot4, y_data_predict_dot4_L0, label="L0(x)", color="green")
plt.plot   (x_data_predict_dot4, y_data_predict_dot4_L1, label="L1(x)", color="blue")
plt.plot   (x_data_predict_dot4, y_data_predict_dot4_L2, label="L2(x)", color="Orange")
plt.plot   (x_data_predict_dot4, y_data_predict_dot4_L3, label="L3(x)", color="Purple")
plt.plot   (x_data_predict_dot4, y_data_predict_dot4_F, label="f(x)", color="red")

#设置属性
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
plt.title("Dot4 拉格朗日插值拟合过程")
plt.legend(loc="upper left")
plt.show()

 从上述图形可以看出:

  • 基函数L0(x) 是一条3次曲线,且穿过(x0,y0)点。
  • 基函数L1(x) 是一条3次曲线,且穿过(x1,y1)点。
  • 基函数L2(x) 是一条3次曲线,且穿过(x2,y2)点。
  • 插值函数F(x) 是L0(x)、L1(x)、L2(x)、L3(x)的线性叠加
  • 插值函数F(x)也是一条3次曲线,且同时穿过(x0,y0),(x1,y1),(x2,y2), (x3,y3) 四个采样点。


 作者主页(文火冰糖的硅基工坊):https://blog.csdn.net/HiWangWenBing

本文网址:https://blog.csdn.net/HiWangWenBing/article/details/119967939

以上是关于[数值计算-14]:拉格朗日插值与Python代码实现的主要内容,如果未能解决你的问题,请参考以下文章

[计算机数值分析]拉格朗日插值公式

《数值分析》-- 拉格朗日插值

拉格朗日插值Python代码实现

拉格朗日插值与牛顿插值

python拉格朗日插值

拉格朗日(Lagrange)插值算法