如何在SciPy中定量测量拟合优度?

7

我正在尝试找到最适合给定数据的模型。我的做法是通过循环各种n值,并利用公式((y_fit - y_actual) / y_actual) x 100计算每个p处的残差。然后对于每个n,计算这个残差的平均值,找到最小残差均值和相应的n值,并使用该值进行拟合。以下是可重现的代码:

import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize   

x = np.array([12.4, 18.2, 20.3, 22.9, 27.7, 35.5, 53.9])
y = np.array([1, 50, 60, 70, 80, 90, 100])
y_residual = np.empty(shape=(1, len(y)))
residual_mean = []

n = np.arange(0.01, 10, 0.01)

def fit(x, a, b):
    return a * x + b
for i in range (len(n)):
    x_fit = 1 / np.log(x) ** n[i]
    y_fit = y
    fit_a, fit_b = optimize.curve_fit(fit, x_fit, y_fit)[0]
    y_fit = (fit_a * x_fit) + fit_b
    y_residual = (abs(y_fit - y) / y) * 100
    residual_mean = np.append(residual_mean, np.mean(y_residual[np.isfinite(y_residual)]))
p = n[np.where(residual_mean == residual_mean.min())]
p = p[0]
print p
x_fit = 1 / np.log(x) ** p
y_fit = y
fit_a, fit_b = optimize.curve_fit(fit, x_fit, y_fit)[0]
y_fit = (fit_a * x_fit) + fit_b
y_residual = (abs(y_fit - y) / y) * 100

fig = plt.figure(1, figsize=(5, 5))
fig.clf()
plot = plt.subplot(111)
plot.plot(x, y, linestyle = '', marker='^')
plot.plot(x, y_fit, linestyle = ':')
plot.set_ylabel('y')
plot.set_xlabel('x')
plt.show()

fig_1 = plt.figure(2, figsize=(5, 5))
fig_1.clf()
plot_1 = plt.subplot(111)
plot_1.plot(1 / np.log(x) ** p, y, linestyle = '-')
plot_1.set_xlabel('pow(x, -p)' )
plot_1.set_ylabel('y' )
plt.show()

fig_2 = plt.figure(2, figsize=(5, 5))
fig_2.clf()
plot_2 = plt.subplot(111)
plot_2.plot(n, residual_mean, linestyle = '-')
plot_2.set_xlabel('n' )
plot_2.set_ylabel('Residual mean')
plt.show()

通过 n 绘制残差均值,我得到了以下结果:

enter image description here

我需要知道这种方法是否正确用于确定最佳拟合,并且是否可以使用 SciPy 或其他包中的其他函数实现。本质上,我想要定量地知道哪种拟合最好。我已经看过 SciPy 中适合度检验 但并没有对我很有帮助。


1
一个典型的拟合优度量是R^2值(决定系数)。 - ali_m
在这种情况下,该如何计算? - Tom Kurushingal
1个回答

20

可能最常用的拟合优度测量指标是决定系数(也称R2值)。

公式如下:

enter image description here

其中:

enter image description here

enter image description here

在此,yi指的是您的输入y值,fi指的是拟合的y值,̅y指的是输入y值的平均值。

计算起来非常容易:

# residual sum of squares
ss_res = np.sum((y - y_fit) ** 2)

# total sum of squares
ss_tot = np.sum((y - np.mean(y)) ** 2)

# r-squared
r2 = 1 - (ss_res / ss_tot)

从统计角度来看,使用这种方法有什么需要注意的地方吗? - tommy.carstensen
1
@tommy.carstensen 我唯一看到的缺点是r平方值并没有严格的界限。一些函数可以完全拟合曲线的一部分,但是在其他部分出现偏差可能会导致COD大于1.0。但这只是一个解释问题。如果你正在寻找一个误差测量值,那么你需要将其解释为函数r平方值与1.0之间的距离。 - Cerin
从统计学的角度来看,使用这种方法需要注意以下几点 https://www.r-bloggers.com/2021/03/the-r-squared-and-nonlinear-regression-a-difficult-marriage/ - Idiot Tom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接