多项式拟合问题的 numpy 实现及比较

174 阅读2分钟

我们尝试实现一个标准的多项式拟合程序,期间遇到一个无法理解的问题。下面是我们的代码,其中包含了样本数据 x 和 y,我们使用正规方程和 numpy 中的 polyfit 函数对数据进行拟合。

def mytest(N):
    print "\nPolynomial order (N): {}".format(N)
    mVals = [5, 10, 15, 20]
    a_orig = [198.764, 13.5, 0.523]
    for M in mVals:
        x = arange(-M, M+1)
        y = matrix(a_orig[0]+ a_orig[1]*x + a_orig[2]*x**2).T

        # Code implementing the solution from the normal equations
        nArray = arange(N+1)    
        A = matrix([[n**i for i in nArray] for n in x])
        B = (A.T*A).I
        a_myfit = B*(A.T*y)

        # numpy's polyfit    
        a_polyfit = polyfit(x, y, N)

        print "M: {}".format(M)
        print ["{0:0.3f}".format(i) for i in a_orig] 
        print ["{0:0.3f}".format(i) for i in array(a_myfit)[:,0]]
        print ["{0:0.3f}".format(i) for i in list(array(a_polyfit)[:,0])[::-1]]

mytest(N=5)
mytest(N=6)

以下是我们尝试使用 N=5 和 N=6 时得到的输出结果:

Polynomial order (N): 5
M: 5
['198.764', '13.500', '0.523']
['198.764', '13.500', '0.523', '0.000', '0.000', '-0.000']
['198.764', '13.500', '0.523', '-0.000', '0.000', '0.000']
M: 10
['198.764', '13.500', '0.523']
['198.764', '13.500', '0.523', '-0.000', '0.000', '-0.000']
['198.764', '13.500', '0.523', '0.000', '0.000', '0.000']
M: 15
['198.764', '13.500', '0.523']
['198.764', '13.500', '0.523', '0.000', '0.000', '-0.000']
['198.764', '13.500', '0.523', '-0.000', '-0.000', '0.000']
M: 20
['198.764', '13.500', '0.523']
['198.764', '13.500', '0.523', '0.000', '-0.000', '-0.000']
['198.764', '13.500', '0.523', '0.000', '0.000', '0.000']

Polynomial order (N): 6
M: 5
['198.764', '13.500', '0.523']
['198.764', '13.500', '0.523', '0.000', '0.000', '-0.000', '-0.000']
['198.764', '13.500', '0.523', '-0.000', '0.000', '0.000', '-0.000']
M: 10
['198.764', '13.500', '0.523']
['198.764', '13.500', '0.523', '-0.000', '-0.000', '-0.000', '-0.000']
['198.764', '13.500', '0.523', '0.000', '0.000', '-0.000', '-0.000']
M: 15
['198.764', '13.500', '0.523']
['294.451', '13.500', '-0.061', '0.000', '-0.001', '-0.000', '-0.000']
['198.764', '13.500', '0.523', '0.000', '0.000', '0.000', '-0.000']
M: 20
['198.764', '13.500', '0.523']
['369.135', '13.500', '-0.046', '0.000', '-0.000', '-0.000', '-0.000']
['198.764', '13.500', '0.523', '0.000', '0.000', '-0.000', '-0.000']

从输出中可以看到,当 N > 5 且 M > 13 时,多项式拟合的结果出现了错误。

2、解决方案

为了解决这个问题,我们需要检查代码中的问题并进行修改。主要需要注意以下几点:

  1. 确保矩阵 A 的数据类型能够处理较大的数值,以避免出现溢出。
  2. 检查数据类型是否一致,特别是当使用多个库或模块时,确保数据类型之间兼容。

通过检查代码,发现问题出现在矩阵 A 的数据类型上。在默认情况下,A 的数据类型是 int32,它只能表示有限范围的整数。当指数非常大时,n**i 的值可能会超出 int32 的表示范围,导致溢出并产生不正确的结果。

要解决这个问题,我们可以将 A 的数据类型更改为 float64,它能够表示更大的数值。修改后的代码如下:

A = np.matrix([[n**i for i in nArray] for n in x], dtype='float64')

修改后,我们使用相同的数据重新运行代码,得到了正确的结果:

Polynomial order (N): 5
M: 5
['198.764', '13.500', '0.523']
['198.764', '13.500', '0.523', '0.000', '0.000', '-0.000']
['198.764', '13.500', '0.523', '-0.000', '0.000', '0.000']
M: 10
['198.764', '13.500', '0.523']
['198.764', '13.500', '0.523', '-0.000', '0.000', '-0.000']
['198.764', '13.500', '0.523', '0.000', '0.000', '0.000']
M: 15
['198.764', '13.500', '0.523']
['198.764', '13.500', '0.523', '0.000', '0.0