python多项式方程曲线_最小二乘法 多项式曲线拟合 原理公式理解 Python 实现

概念

最小二乘法多项式曲线拟合,根据给定的m个点,并不要求这条曲线精确地经过这些点,而是曲线y=f(x)的近似曲线y= φ(x)。

原理

给定数据点pi(xi,yi),其中i=1,2,…,m。求近似曲线y= φ(x)。并且使得近似曲线与y=f(x)的偏差最小。近似曲线在点pi处的偏差δi= φ(xi)-y,i=1,2,...,m。

常见的曲线拟合方法:

1.使偏差绝对值之和最小

2.使偏差绝对值最大的最小

3.使偏差平方和最小

按偏差平方和最小的原则选取拟合曲线,并且采取二项式方程为拟合曲线的方法,称为最小二乘法。喎�"/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjwvcD4NCjxoMSBpZD0="推导过程">推导过程:

设拟合多项式为:

各点到这条曲线的距离之和,即偏差平方和如下:

为了求得符合条件的a值,对等式右边求ai偏导数:

注意每个变量仍有下标i,且[]外的x也有被∑累加(sum)

.......

将等式左边进行一下化简,然后应该可以得到下面的等式:

.......

把这些等式表示成矩阵的形式,就可以得到下面的矩阵:

将这个范德蒙得矩阵化简后可得到:

也就是说X*A=Y,那么A = (X’*X)-1*X’*Y,便得到了系数矩阵A,同时,我们也就得到了拟合曲线

数据集:征兵抽签1-366号(y),366个不同的人抽(x)。结果表明生日靠后的人易抽到小号

# coding=utf-8

'''

多项式曲线拟合算法

'''

import matplotlib.pyplot as plt

from math import *

import numpy

import random

fig = plt.figure()

ax = fig.add_subplot(111)

'阶数为9阶 n=9=k'

order=9

'被拟合的点'

xa = []

ya = []

'画图时,点的取值范围和点的密度。根据源数据点进行推断'

start = 1 # -1

end = 367 # 1

step = (start + end)/200.0

# 实验得步长不影响图形的弯曲程度

# 此概念与KDE核密度的宽度不同

# 因为系数a0,a1,a2...已经得到,此处步长只影响画图质量,可随意设置

#生成样例曲线上的各个点 100个

x = numpy.arange(start, end, step)

# y = [((a*a-1)*(a*a-1)*(a*a-1)+0.5)*numpy.sin(a*2) for a in x]

y = [((a*a-1)**3 + 0.5)*sin(2*a) for a in x]

#print x

#print y

# print z

# 生成的原曲线

#ax.plot(x,y,color='r',linestyle='-',marker='.')

#,label="(a*a-1)*(a*a-1)*(a*a-1)+0.5"

#生成的曲线上的各个点随机偏移一下,并放入到xa,ya中去

i = 0

##############################

#生成xa ya的源数据点

##############################

'''

for xx in x:

yy = y[i]

# 偏移宽度(-40%,+40%)

d = float(random.randint(60,140))/100

#ax.plot([xx*d],[yy*d],color='m',linestyle='',marker='.')

i += 1

xa.append(xx*d)

ya.append(yy*d)

'''

d = []

ya = [i for i in range(start, end)]

random.shuffle(ya)

xa = range(start, end)

#d = tuple(zip(xa, ya))

for i in range(len(xa)):

d.append([xa[i],ya[i]])

# print d

nd = numpy.array(d)

ax.plot(nd[:, 0], nd[:, 1], 'o', color="white", markersize=7, linewidth=3)

# 偏移之后的点图

#ax.plot(xa,ya,color='m',linestyle='',marker='.')

#进行曲线拟合

matA=[] #整个多项式矩阵

for i in range(0,order+1):

matA1=[] # 每一行

for j in range(0,order+1):

tx=0.0 # 每一列

for k in range(0,len(xa)):

dx = 1.0 # 表示初始

for l in range(0,j+i):

# l为次数,对应一行的不同次的变量

# 本区域(重复)运行次数越多次数越高

# 第一次不运行此区域 表示n=dx

# 最后一次运行 2order次 即为x^2k(或n^2次)

dx = dx*xa[k]

tx += dx

# 运行n次(len(xa)次)后,tx为sum(x[i]^2k) 或 n (dx=1运行n次)

matA1.append(tx)

matA.append(matA1)

#print(len(xa))

#print(matA[0][0])

# 转化为ndarray

matA = numpy.array(matA)

matB = []

for k in range(0,order+1):

ty = 0.0

# 加和n个

for i in range(0,len(xa)):

dy = 1.0

# 对于从i=1->n 求 (x[i])^(k-1)

for l in range(0, k):

dy = dy * xa[i] #dy即为公式中 (x[i])^k

ty += ya[i] * dy # 先乘完再加和

matB.append(ty)

matB = numpy.array(matB)

# 多元一次 x^k为系数 a为未知数 求线性的a

matAA = numpy.linalg.solve(matA,matB)

#得到系数矩阵

# 下面画出拟合后的曲线

# a0 + a1*x + a2*x^2 +...+ ak*x^k

#print(matAA)

xxa = numpy.arange(start, end, step)

yya = []

for i in range(0,len(xxa)):

yy = 0.0

for j in range(0,order+1):

dy = 1.0

for k in range(0,j):

dy *= xxa[i] # x^k

# ak*x^k

dy *= matAA[j] # matAA[j]即为系数a

yy += dy

yya.append(yy)

ax.plot(xxa,yya,color='g',linestyle='-',marker='')

ax.legend()

plt.show()

遇到的问题:

将一维数组变成二维

zip返回列表内的元组:[(a,b), (c,d)]

x = range(25)

y = zip(*[iter(x)]*5)

print y

[(0,1,2,3,4),

(5,6,7,8,9),

(10,11,12,13,14),

(15,16,17,18,19),

(20,21,22,23,24)

]

最小二乘法多项式曲线拟合原理

在线拟合工具

利用python搞机器学习——最小二乘法

leastsq-wiki

leastsq函数

最小二乘法以及leastsq函数

你可能感兴趣的:(python多项式方程曲线)