按照this answer中的建议,我使用了beta0值的几种组合,如此处所示,是polyfit的值。
此示例已更新,以显示X与Y的相对比例值的影响:
from random import random, seed
from scipy import polyfit
from scipy import odr
import numpy as np
from matplotlib import pyplot as plt
seed(1)
X = np.array([random() for i in range(1000)])
Y = np.array([i + random()**2 for i in range(1000)])
for num in xrange(1, 5):
plt.subplot(2, 2, num)
plt.title('X range is %.1f times Y' % (float(100 / max(X))))
X *= 10
z = np.polyfit(X, Y, 1)
plt.plot(X, Y, 'k.', alpha=0.1)
# Fit using odr
def f(B, X):
return B[0]*X + B[1]
linear = odr.Model(f)
mydata = odr.RealData(X, Y)
myodr = odr.ODR(mydata, linear, beta0=z)
myodr.set_job(fit_type=0)
myoutput = myodr.run()
a, b = myoutput.beta
sa, sb = myoutput.sd_beta
xp = np.linspace(plt.xlim()[0], plt.xlim()[1], 1000)
yp = a*xp+b
plt.plot(xp, yp, label='ODR')
yp2 = z[0]*xp+z[1]
plt.plot(xp, yp2, label='polyfit')
plt.legend()
plt.ylim(-1000, 2000)
plt.show()
似乎没有beta0的组合有帮助...使polyfit和ODR拟合相似的唯一方法是交换X和Y,或者如此处所示,以增加X相对于Y的值范围,但仍然没有真的是一个解决方案:)
===编辑===
我不希望ODR与polyfit相同。我展示polyfit只是为了强调ODR拟合是错误的,这不是数据问题。
===解决方案===
感谢@ norok2答案:
from random import random, seed
from scipy import polyfit
from scipy import odr
import numpy as np
from matplotlib import pyplot as plt
seed(1)
X = np.array([random() / 1000 for i in range(1000)])
Y = np.array([i + random()**2 for i in range(1000)])
plt.figure(figsize=(12, 12))
for num in xrange(1, 10):
plt.subplot(3, 3, num)
plt.title('Y range is %.1f times X' % (float(100 / max(X))))
X *= 10
z = np.polyfit(X, Y, 1)
plt.plot(X, Y, 'k.', alpha=0.1)
# Fit using odr
def f(B, X):
return B[0]*X + B[1]
linear = odr.Model(f)
mydata = odr.RealData(X, Y,
sy=min(1/np.var(Y), 1/np.var(X))) # here the trick!! :)
myodr = odr.ODR(mydata, linear, beta0=z)
myodr.set_job(fit_type=0)
myoutput = myodr.run()
a, b = myoutput.beta
sa, sb = myoutput.sd_beta
xp = np.linspace(plt.xlim()[0], plt.xlim()[1], 1000)
yp = a*xp+b
plt.plot(xp, yp, label='ODR')
yp2 = z[0]*xp+z[1]
plt.plot(xp, yp2, label='polyfit')
plt.legend()
plt.ylim(-1000, 2000)
plt.show()
答案 0 :(得分:2)
polyfit()
与正交距离回归(ODR)拟合之间的主要区别在于,在x
的误差可忽略的假设下,多边形拟合有效。如果违反了此假设(就像您的数据中那样),则不能期望这两种方法会产生相似的结果。
特别是,ODR()
对您指定的错误非常敏感。
如果您未指定任何错误/权重,它将为1
和x
分配一个y
值,这意味着x
和{{1 }}将影响结果(所谓的数值条件)。
相反,y
在计算拟合度之前,对数据进行了某种形式的白化处理(请参见其source code的第577行),以提供更好的数值条件。
因此,如果您希望polyfit()
与ODR()
匹配,则可以简单地微调polyfit()
上的错误以更改数值条件。
我测试了此方法适用于您Y
的{{1}}和1e-10
之间的任何数值条件(在您的示例中为1e10
或Y
)。
/ 10.
收件人:
1e-1
(编辑:请注意,上面一行有错字)
我测试了它适用于mydata = odr.RealData(X, Y)
# equivalent to: odr.RealData(X, Y, sx=1, sy=1)
的{{1}}和mydata = odr.RealData(X, Y, sx=1, sy=1/np.var(Y))
之间的任何数值条件(在您的示例中为1e-10
或1e10
)。
请注意,这仅适用于条件良好的拟合。
答案 1 :(得分:0)
我无法在注释中设置源代码的格式,因此请将其放在此处。该代码使用ODR来计算拟合统计量,请注意具有“ odr的参数顺序”的行,以便我对我的“实际”函数的ODR调用使用包装函数。
from scipy.optimize import curve_fit
import numpy as np
import scipy.odr
import scipy.stats
x = np.array([5.357, 5.797, 5.936, 6.161, 6.697, 6.731, 6.775, 8.442, 9.861])
y = np.array([0.376, 0.874, 1.049, 1.327, 2.054, 2.077, 2.138, 4.744, 7.104])
def f(x,b0,b1):
return b0 + (b1 * x)
def f_wrapper_for_odr(beta, x): # parameter order for odr
return f(x, *beta)
parameters, cov= curve_fit(f, x, y)
model = scipy.odr.odrpack.Model(f_wrapper_for_odr)
data = scipy.odr.odrpack.Data(x,y)
myodr = scipy.odr.odrpack.ODR(data, model, beta0=parameters, maxit=0)
myodr.set_job(fit_type=2)
parameterStatistics = myodr.run()
df_e = len(x) - len(parameters) # degrees of freedom, error
cov_beta = parameterStatistics.cov_beta # parameter covariance matrix from ODR
sd_beta = parameterStatistics.sd_beta * parameterStatistics.sd_beta
ci = []
t_df = scipy.stats.t.ppf(0.975, df_e)
ci = []
for i in range(len(parameters)):
ci.append([parameters[i] - t_df * parameterStatistics.sd_beta[i], parameters[i] + t_df * parameterStatistics.sd_beta[i]])
tstat_beta = parameters / parameterStatistics.sd_beta # coeff t-statistics
pstat_beta = (1.0 - scipy.stats.t.cdf(np.abs(tstat_beta), df_e)) * 2.0 # coef. p-values
for i in range(len(parameters)):
print('parameter:', parameters[i])
print(' conf interval:', ci[i][0], ci[i][1])
print(' tstat:', tstat_beta[i])
print(' pstat:', pstat_beta[i])
print()