我有两个变量x and y
,我试图使用curve_fit
中的scipy.optimize
。
适合数据的等式是 y=a(x^b)
形式的简单幂律。当 I set the x and y axis to log scale
,即ax.set_xscale('log')
和ax.set_yscale('log')
时,数据似乎很适合。
以下是代码:
def fitfunc(x,p1,p2):
y = p1*(x**p2)
return y
popt_1,pcov_1 = curve_fit(fitfunc,x,y,p0=(1.0,1.0))
p1_1 = popt_1[0]
p1_2 = popt_1[1]
residuals1 = (ngal_mstar_1) - fitfunc(x,p1_1,p1_2)
xi_sq_1 = sum(residuals1**2) #The chi-square value
curve_y_1 = fitfunc(x,p1_1,p1_2) #This is the fit line seen in the graph
fig = plt.figure(figsize=(14,12))
ax1 = fig.add_subplot(111)
ax1.scatter(x,y,c='r')
ax1.plot(y,curve_y_1,'y.',linewidth=1)
ax1.legend(loc='best',shadow=True,scatterpoints=1)
ax1.set_xscale('log') #Scale is set to log
ax1.set_yscale('log') #SCale is set to log
plt.show()
当我对x和y使用真正的log-log值时,幂律拟合变为 y=10^(a+b*log(x))
,即将右侧的幂提高到10,因为它是logbase 10。现在x和y值都是log(x)和log(y)。
适合上述情况似乎并不好。这是我用过的代码。
def fitfunc(x,p1,p2):
y = 10**(p1+(p2*x))
return y
popt_1,pcov_1 = curve_fit(fitfunc,np.log10(x),np.log10(y),p0=(1.0,1.0))
p1_1 = popt_1[0]
p1_2 = popt_1[1]
residuals1 = (y) - fitfunc((x),p1_1,p1_2)
xi_sq_1 = sum(residuals1**2)
curve_y_1 = fitfunc(np.log10(x),p1_1,p1_2) #The fit line uses log(x) here itself
fig = plt.figure(figsize=(14,12))
ax1 = fig.add_subplot(111)
ax1.scatter(np.log10(x),np.log10(y),c='r')
ax1.plot(np.log10(y),curve_y_1,'y.',linewidth=1)
plt.show()
两幅图之间的唯一区别是拟合方程,而第二幅图的价值已经独立记录。我在这里做错了,因为我想要一个log(x)vs log(y)图和相应的拟合参数(斜率和截距)
答案 0 :(得分:3)
您将幂律模型转换为对数日志是错误的,即您的第二次拟合实际上适合不同的模型。采用原始模型y=a*(x^b)
并在两侧应用对数,您将获得log(y) = log(a) + b*log(x)
。因此,您在log-scale中的模型应该只读取y' = a' + b*x'
,其中素数表示对数比例的变量。该模型现在是一个线性函数,这是众所周知的结果,所有幂律成为log-log中的线性函数。
也就是说,你仍然可以期待两个版本的拟合中存在一些细微差别,因为curve_fit
将优化最小二乘问题。因此,在对数刻度中,拟合将最小化拟合和数据之间的相对误差,而在线性刻度中,拟合将最小化绝对误差。因此,为了确定哪种方式实际上是适合您的更好的域,您将不得不估计数据中的错误。您显示的数据肯定没有对数刻度的恒定不确定性,因此在线性刻度上您的拟合可能更忠实。如果已知有关每个数据点中的错误的详细信息,则可以考虑使用sigma
参数。如果使用得当,两种方法应该没有太大区别。在这种情况下,我更喜欢对数尺度拟合,因为模型更简单,因此可能更加数值稳定。