因此,我试图通过二次回归拟合一些x,y数据对,可以在node property override找到示例公式。 以下是我的代码,该代码使用该显式公式和numpy内置函数进行回归,
import numpy as np
x = [6.230825,6.248279,6.265732]
y = [0.312949,0.309886,0.306639472]
toCheck = x[2]
def evaluateValue(coeff,x):
c,b,a = coeff
val = np.around( a+b*x+c*x**2,9)
act = 0.306639472
error= np.abs(act-val)*100/act
print "Value = {:.9f} Error = {:.2f}%".format(val,error)
###### USing numpy######################
coeff = np.polyfit(x,y,2)
evaluateValue(coeff, toCheck)
################# Using explicit formula
def determinant(a,b,c,d,e,f,g,h,i):
# the matrix is [[a,b,c],[d,e,f],[g,h,i]]
return a*(e*i - f*h) - b*(d*i - g*f) + c*(d*h - e*g)
a = b = c = d = e = m = n = p = 0
a = len(x)
for i,j in zip(x,y):
b += i
c += i**2
d += i**3
e += i**4
m += j
n += j*i
p += j*i**2
det = determinant(a,b,c,b,c,d,c,d,e)
c0 = determinant(m,b,c,n,c,d,p,d,e)/det
c1 = determinant(a,m,c,b,n,d,c,p,e)/det
c2 = determinant(a,b,m,b,c,n,c,d,p)/det
evaluateValue([c2,c1,c0], toCheck)
######Using another explicit alternative
def determinantAlt(a,b,c,d,e,f,g,h,i):
return a*e*i - a*f*h - b*d*i +b*g*f + c*d*h - c*e*g # <- barckets removed
a = b = c = d = e = m = n = p = 0
a = len(x)
for i,j in zip(x,y):
b += i
c += i**2
d += i**3
e += i**4
m += j
n += j*i
p += j*i**2
det = determinantAlt(a,b,c,b,c,d,c,d,e)
c0 = determinantAlt(m,b,c,n,c,d,p,d,e)/det
c1 = determinantAlt(a,m,c,b,n,d,c,p,e)/det
c2 = determinantAlt(a,b,m,b,c,n,c,d,p)/det
evaluateValue([c2,c1,c0], toCheck)
此代码给出了此输出
Value = 0.306639472 Error = 0.00%
Value = 0.308333580 Error = 0.55%
Value = 0.585786477 Error = 91.03%
作为,您可以看到它们彼此不同,并且第三个完全错误。现在我的问题是:
1.为什么显式公式给出的结果略有错误,以及如何改进呢?
2. numpy如何给出如此准确的结果?
3.在第三种情况下,仅通过打开括号,结果如何发生如此大的变化?
答案 0 :(得分:1)
因此,不幸的是,这里发生的一些事情困扰着您的做事方式。看一下这段代码:
for i,j in zip(x,y):
b += i
c += i**2
d += i**3
e += i**4
m += j
n += j*i
p += j*i**2
您正在构建功能,使得x
值不仅是平方,而且是三次方和四次幂。
如果在将这些值放入3 x 3矩阵中进行求解之前先打印出每个值,则
In [35]: a = b = c = d = e = m = n = p = 0
...: a = len(x)
...: for i,j in zip(xx,y):
...: b += i
...: c += i**2
...: d += i**3
...: e += i**4
...: m += j
...: n += j*i
...: p += j*i**2
...: print(a, b, c, d, e, m, n, p)
...:
...:
3 18.744836 117.12356813829001 731.8283056811686 4572.738547313946 0.9294744720000001 5.807505391292503 36.28641270376207
在处理浮点运算时,尤其是对于小数值时,运算的顺序确实很重要。这里发生的是,偶然的是,已经计算出的小值和大值的混合导致一个非常小的值。因此,在使用分解形式和扩展形式计算行列式时,请注意如何获得略有不同的结果,但还要看一下值的精度:
In [36]: det = determinant(a,b,c,b,c,d,c,d,e)
In [37]: det
Out[37]: 1.0913403514223319e-10
In [38]: det = determinantAlt(a,b,c,b,c,d,c,d,e)
In [39]: det
Out[39]: 2.3283064365386963e-10
行列式为10 -10 !之所以存在差异,是因为使用浮点算法,理论上两种行列式方法都应产生相同的结果,但不幸的是,实际上它们给出的结果略有不同,这是由于错误传播引起的。由于可以表示浮点数的位数有限,因此操作顺序会更改错误的传播方式,因此,即使您删除括号并且公式基本匹配,操作顺序也可以得出。现在的结果有所不同。对于定期处理浮点算术的任何软件开发人员,本文都是必读的文章:What Every Computer Scientist Should Know About Floating-Point Arithmetic。
因此,当您尝试使用Cramer规则求解系统时,不可避免地会用代码中的主要行列式除以偶数,即使更改约为10 -10 ,两种方法之间的变化可以忽略不计,但是您会得到非常不同的结果,因为求解系数时要用该数字除。
NumPy不存在此问题的原因是因为它们通过最小二乘和pseudo-inverse而不是使用Cramer规则来求解系统。我不建议使用Cramer法则来找到回归系数,主要是因为经验丰富,并且有更强大的方法可以做到这一点。
但是,要解决您的特定问题,最好对数据进行规范化,以使动态范围现在位于0的中心。因此,用于构造系数矩阵的特征更加合理,因此计算过程可以更轻松地处理数据。在您的情况下,应该可以执行一些简单的操作,例如用x
的平均值减去数据即可。这样,如果您要预测新的数据点,则必须在进行预测之前先减去x
数据的平均值。
因此,在代码开头,请对该数据执行均值减和回归。我已经向您展示了我在上面给出的源代码中修改代码的位置:
import numpy as np
x = [6.230825,6.248279,6.265732]
y = [0.312949,0.309886,0.306639472]
# Calculate mean
me = sum(x) / len(x)
# Make new dataset that is mean subtracted
xx = [pt - me for pt in x]
#toCheck = x[2]
# Data point to check is now mean subtracted
toCheck = x[2] - me
def evaluateValue(coeff,x):
c,b,a = coeff
val = np.around( a+b*x+c*x**2,9)
act = 0.306639472
error= np.abs(act-val)*100/act
print("Value = {:.9f} Error = {:.2f}%".format(val,error))
###### USing numpy######################
coeff = np.polyfit(xx,y,2) # Change
evaluateValue(coeff, toCheck)
################# Using explicit formula
def determinant(a,b,c,d,e,f,g,h,i):
# the matrix is [[a,b,c],[d,e,f],[g,h,i]]
return a*(e*i - f*h) - b*(d*i - g*f) + c*(d*h - e*g)
a = b = c = d = e = m = n = p = 0
a = len(x)
for i,j in zip(xx,y): # Change
b += i
c += i**2
d += i**3
e += i**4
m += j
n += j*i
p += j*i**2
det = determinant(a,b,c,b,c,d,c,d,e)
c0 = determinant(m,b,c,n,c,d,p,d,e)/det
c1 = determinant(a,m,c,b,n,d,c,p,e)/det
c2 = determinant(a,b,m,b,c,n,c,d,p)/det
evaluateValue([c2,c1,c0], toCheck)
######Using another explicit alternative
def determinantAlt(a,b,c,d,e,f,g,h,i):
return a*e*i - a*f*h - b*d*i +b*g*f + c*d*h - c*e*g # <- barckets removed
a = b = c = d = e = m = n = p = 0
a = len(x)
for i,j in zip(xx,y): # Change
b += i
c += i**2
d += i**3
e += i**4
m += j
n += j*i
p += j*i**2
det = determinantAlt(a,b,c,b,c,d,c,d,e)
c0 = determinantAlt(m,b,c,n,c,d,p,d,e)/det
c1 = determinantAlt(a,m,c,b,n,d,c,p,e)/det
c2 = determinantAlt(a,b,m,b,c,n,c,d,p)/det
evaluateValue([c2,c1,c0], toCheck)
运行此命令后,我们会得到:
In [41]: run xor
Value = 0.306639472 Error = 0.00%
Value = 0.306639472 Error = 0.00%
Value = 0.306639472 Error = 0.00%
作为对您的最终阅读,这是我在他们的问题Fitting a quadratic function in python without numpy polyfit中解决的其他人遇到的类似问题。总结是,我建议他们不要使用Cramer规则,而应通过伪逆使用最小二乘法。我向他们展示了如何在不使用numpy.polyfit
的情况下获得完全相同的结果。另外,使用最小二乘可概括出如果您拥有3个以上点的地方,则仍然可以对所有点进行二次拟合,以使模型具有最小的误差。