具有相等数量的数据点和系数的多项式拟合
Polynomial fitting with equal number of data points and coefficients
我目前正在尝试使用 jupyter 进行多项式拟合。下面的函数 returns 给定 xs 中具有相应 ys 的数据点的 m 次最小二乘多项式。
from numpy import *
from matplotlib import pyplot as plt
def findas(m,xs,ys):
A = array([[0]*(m+1)]*(m+1))
b = array([0]*(m+1))
for k in range(m+1):
b[k] = sum(ys*xs**k)
for i in range(m+1):
A[k,i] = sum(xs**(k+i))
coefs = linalg.solve(A,b)
print(coefs)
def fit(x):
return sum(coefs*(x**array(range(len(coefs)))))
return fit
假设我有以下六个数据点并拟合一个 5 次多项式:
xs = array([1,2,3,4,5,6])
ys = array([-5.21659 ,2.53152 ,2.05687 ,14.1135 ,20.9673 ,33.5652])
ft = findas(5,xs,ys)
根据我的理解,生成的曲线应该准确地通过每个数据点(事实上,拉格朗日多项式应该是结果)。
xdense = arange(1,6.1,0.1)
ydense = [ft(x) for x in xdense]
plt.plot(xdense,ydense)
plt.plot(xs,ys,'rx')
plt.show()
示例输出:
然而,事实并非如此。曲线还差得很远!这里发生了什么?这与舍入误差有关吗?提前致谢!
您的代码看起来是正确的;你 re-discovered 试图用 finite-precision 算法反转 nearly-singular 矩阵的问题。矩阵 A 看起来像这样
[[ 6 21 91 441 2275 12201]
[ 21 91 441 2275 12201 67171]
[ 91 441 2275 12201 67171 376761]
[ 441 2275 12201 67171 376761 2142595]
[ 2275 12201 67171 376761 2142595 12313161]
[ 12201 67171 376761 2142595 12313161 71340451]]
请注意最大值和最小值之间的差异有多大。它的特征值由
给出
[7.35326515e+07 1.98781177e+04 5.75757797e+01 1.74921341e+00
5.89932892e-02 1.37532926e-04]
请注意,最大与最小之比约为 10^11。所以这个矩阵在理论上不是奇异的,但对于数值计算来说几乎是奇异的。它的反转会导致非常大的 round-off 错误,就像除以非常小的数字一样,最终结果的精度会大大降低。
更多详细信息here和相关链接
好像是截断错误!代码块
A = array([[0]*(m+1)]*(m+1))
b = array([0]*(m+1))
for k in range(m+1):
...
应改为:
A = array([[0.]*(m+1)]*(m+1))
b = array([0.]*(m+1))
for k in range(m+1):
...
即我们必须将零指定为浮点数。
此外,round-off 误差会在矩阵求逆过程中放大。当我们要求逆的矩阵的特征值在数量级上存在显着差异时,情况尤其如此。
我目前正在尝试使用 jupyter 进行多项式拟合。下面的函数 returns 给定 xs 中具有相应 ys 的数据点的 m 次最小二乘多项式。
from numpy import *
from matplotlib import pyplot as plt
def findas(m,xs,ys):
A = array([[0]*(m+1)]*(m+1))
b = array([0]*(m+1))
for k in range(m+1):
b[k] = sum(ys*xs**k)
for i in range(m+1):
A[k,i] = sum(xs**(k+i))
coefs = linalg.solve(A,b)
print(coefs)
def fit(x):
return sum(coefs*(x**array(range(len(coefs)))))
return fit
假设我有以下六个数据点并拟合一个 5 次多项式:
xs = array([1,2,3,4,5,6])
ys = array([-5.21659 ,2.53152 ,2.05687 ,14.1135 ,20.9673 ,33.5652])
ft = findas(5,xs,ys)
根据我的理解,生成的曲线应该准确地通过每个数据点(事实上,拉格朗日多项式应该是结果)。
xdense = arange(1,6.1,0.1)
ydense = [ft(x) for x in xdense]
plt.plot(xdense,ydense)
plt.plot(xs,ys,'rx')
plt.show()
示例输出:
然而,事实并非如此。曲线还差得很远!这里发生了什么?这与舍入误差有关吗?提前致谢!
您的代码看起来是正确的;你 re-discovered 试图用 finite-precision 算法反转 nearly-singular 矩阵的问题。矩阵 A 看起来像这样
[[ 6 21 91 441 2275 12201]
[ 21 91 441 2275 12201 67171]
[ 91 441 2275 12201 67171 376761]
[ 441 2275 12201 67171 376761 2142595]
[ 2275 12201 67171 376761 2142595 12313161]
[ 12201 67171 376761 2142595 12313161 71340451]]
请注意最大值和最小值之间的差异有多大。它的特征值由
给出[7.35326515e+07 1.98781177e+04 5.75757797e+01 1.74921341e+00
5.89932892e-02 1.37532926e-04]
请注意,最大与最小之比约为 10^11。所以这个矩阵在理论上不是奇异的,但对于数值计算来说几乎是奇异的。它的反转会导致非常大的 round-off 错误,就像除以非常小的数字一样,最终结果的精度会大大降低。
更多详细信息here和相关链接
好像是截断错误!代码块
A = array([[0]*(m+1)]*(m+1))
b = array([0]*(m+1))
for k in range(m+1):
...
应改为:
A = array([[0.]*(m+1)]*(m+1))
b = array([0.]*(m+1))
for k in range(m+1):
...
即我们必须将零指定为浮点数。
此外,round-off 误差会在矩阵求逆过程中放大。当我们要求逆的矩阵的特征值在数量级上存在显着差异时,情况尤其如此。