python 三次样条曲线(cubic)的自己实现

    在使用三次样条的时候,我想得到三次函数的参数(a,b,c,d),但是查遍了所有的文档,几乎都是使用pytho内置的函数,只好去搜推导公式自己实现。

三次函数的基本概念和推导,可以看知乎  

三次样条(cubic spline)插值 - 知乎 (zhihu.com)

下面是实现的代码  已经和内置三次样条函数的比较

import numpy as np
from matplotlib import pyplot as plt
from scipy.linalg import solve

x=[0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0,28.0,29.0,30.0]


y=[]
files=open("../pred_npz_to_ture_dist/data/txt/dist.txt")
lines=files.readlines()
line=lines[1]
probs=line.split()
for i in range(len(probs)):
    if(i==0 or i==1):
        pass
        continue
    y.append(float(probs[i]))

#得到x值和y值

c=np.zeros((31,31))
for i in range(len(x)):
    for j in range(len(x)):
        if i==0 :
            if j==0:
                c[i][j]=1
            else:
                c[i][j]=0

        if i==len(y)-1:
            if j==len(y)-1:
                c[i][j]=1
            else:
                c[i][j]=0
        else:
            if(i==j):
                c[i][j]=4
            elif(j==i-1 or j==i+1):
                c[i][j]=1
            else:
                c[i][j]=0
c[0][0]=1
c[0][1]=0
#创建对应的矩阵

kkk=np.ones(31)
for k in range(len(y)):
    if(k==0 or k==len(y)-1):
        kkk[k]=0
    else:
        result=(y[k+1]-y[k])-(y[k]-y[k-1])
        kkk[k]=6*result

print(kkk)

m=solve(c,kkk)                                              #求解方程 得m方程
#得到m矩阵

a_total=[]
b_total=[]
c_total=[]
d_total=[]
for i in range(len(x)-1):
    a=y[i]
    b=((y[i+1]-y[i])/1)-0.5*m[i]-(1/6)*(m[i+1]-m[i])
    c=m[i]/2
    d=(m[i+1]-m[i])/6                                    #公式求解参数
#
    a_total.append(a)
    b_total.append(b)
    c_total.append(c)
    d_total.append(d)
                                           #参数集合
# #
# # y=a+b(x-xi)+c(x-xi)2+d(x-xi)3

x1_total=[]
y1_total=[]
for i in range(len(x)-1):
    X_X = [x[i], x[i + 1]]

    x1 = np.linspace(X_X[0], X_X[1], 20)

    Y1=a_total[i]+b_total[i]*(x1-x[i])+c_total[i]*(x1-x[i])**2+d_total[i]*(x1-x[i])**3        #计算过程

    for x0 in x1:
        x1_total.append(x0)
    for y0 in Y1:
        y1_total.append(y0)
#
print("正在画图")
plt.plot(x1_total, y1_total)
plt.show()
y的值是: [0.00049061846 0.023643503 0.004797904 0.3206229 0.05861377 0.11541684 0.0033507212 0.0033047465 0.0033289748 0.0017445018 0.017181963 0.00016493196 0.00464136 0.07718892 0.13565202 0.011754939 0.006294483 0.00086491555 0.0023149562 0.032812975 0.000511408 0.018652624 0.002821648 0.00465417 0.028194392 0.0034546787 0.013121516 0.06579209 0.0031712933 0.019626947 0.015813315 ]

附上python内置的三次样条

# -*-coding:utf-8 -*-
import numpy as np
from scipy import interpolate
import pylab as pl

# x=[1.75,2.25,2.75,3.25,3.75,4.25,4.75,5.25,5.75,6.25,6.75,7.25,7.75,8.25,8.75,9.25,9.75,10.25,10.75,11.25,11.75,12.25,12.75,13.25,13.75,14.25,14.75,15.25,15.75,16.25,16.75]
x=[0,0.5,1.5,2.5,3.5,4.5,5.5,6.5,7.5,8.5,9.5,10.5,11.5,12.5,13.5,14.5,15.5,16.5,17.5,18.5,19.5,20.5,21.5,22.5,23.5,24.5,25.5,26.5,27.5,28.5,29.5]

print(len(x))

y=[]
files=open("../pred_npz_to_ture_dist/data/txt/dist.txt")
lines=files.readlines()
line=lines[1]
probs=line.split()
for i in range(len(probs)):
    if(i==0 or i==1):
        pass
        continue
    y.append(float(probs[i]))
print(y)


print(len(y))

# x = [1, 5, 9, 13]
# y = [1, 5, 1, 5]

xnew=np.linspace(0,29,1000)
pl.plot(x,y,"ro")
# for kind in ["slinear","cubic"]:
for kind in ["cubic"]:#插值方式
    #"nearest","zero"为阶梯插值
    #slinear 线性插值
    #"quadratic","cubic" 为2阶、3阶B样条曲线插值
    f=interpolate.interp1d(x,y,kind=kind)
    # ‘slinear’, ‘quadratic’ and ‘cubic’ refer to a spline interpolation of first, second or third order)
    ynew=f(xnew)
    # print(xnew)
    # print(ynew)
    pl.plot(xnew,ynew,label=str(kind))
pl.legend(loc="lower right")
pl.show()

两者画图的比较:前者为自己写的,后者为内置函数

python 三次样条曲线(cubic)的自己实现_第1张图片

python 三次样条曲线(cubic)的自己实现_第2张图片

有细微差别,可能原因在于边值条件的不同(猜测,还没有去验证)

这样,我即可以得到我想要的三次函数的参数解决问题

 

 

你可能感兴趣的:(python,开发语言,后端)