如何使用来自 SciPy 的曲线拟合将某些点优先于其他点
How to prioritise some points over others using curve fit from SciPy
我想模拟以下曲线:
为了执行它,我使用 SciPy 中的 curve_fit,拟合指数函数。
def exponenial_func(x, a, b, c):
return a * b**(c*x)
popt, pcov = curve_fit(exponenial_func, x, y, p0=(1,2,2),
bounds=((0, 0, 0), (np.inf, np.inf, np.inf)))
当我第一次这样做时,我得到了这个:
这是最小化残差,每个点具有相同的重要性。
我想要的是获得一条曲线,它更重视曲线的最后一个值(例如,从 x 轴 30 开始)而不是第一个值,因此它更适合曲线的末尾而不是开始它的。
我知道从这里开始有很多方法可以解决这个问题(首先,定义我想赋予每个残差的重要性)。我的问题是想知道如何处理这个问题。
我的一个想法是更改 sigma 值以通过其倒数对每个数据点进行加权。
popt, pcov = curve_fit(exponenial_func, x, y, p0=(1,2,2),
bounds=((0, 0, 0), (np.inf, np.inf, np.inf)),
sigma=1/y)
在这种情况下,我得到了我正在寻找的东西:
看起来不错,但我正在寻找另一种方法,这样我就可以 "control" 每个数据点,比如以线性方式对每个残差进行加权,或指数,甚至手动选择它(而不是像前面的情况那样通过逆向选择它们)。
提前致谢
首先请注意,不需要三个系数。自
a * b**(c*x) = a * exp(log(b)*c*x).
我们可以定义k = log(b)*c
。
这里有一个建议,你可以如何 手动 使用 scipy.optimize.least_squares 和优先向量:
import numpy as np
from scipy.optimize import least_squares
def exponenial_func2(x, a, k):
return a * np.exp(k*x)
# returns the vector of residuals
def fitwrapper2(coeffs, *args):
xdata, ydata, prio = args
return prio*(exponenial_func2(xdata, *coeffs)-ydata)
# Data
n = 31
xdata = np.arange(n)
ydata = np.array([155.0,229,322,453,655,888,1128,1694,
2036,2502,3089,3858,4636,5883,7375,
9172,10149,12462,12462,17660,21157,
24747,27980,31506,35713,41035,47021,
53578,59138,63927,69176])
# The priority vector
prio = np.ones(n)
prio[-1] = 5
res = least_squares(fitwrapper2, x0=[1.0,2.0], bounds=(0,np.inf), args=(xdata,ydata,prio))
对于prio[-1] = 5
,我们将最后一点放在高优先级。
res.x
包含您的最佳系数。这里a, k = res.x
.
请注意,对于 prio = np.ones(n)
,这是一个正常的最小二乘拟合(就像 curve_fit 那样),其中所有点都具有相同的 优先级 .
您可以通过增加 prio
数组中每个点的值来控制每个点的优先级。比较这两个结果给我:
我想模拟以下曲线:
为了执行它,我使用 SciPy 中的 curve_fit,拟合指数函数。
def exponenial_func(x, a, b, c):
return a * b**(c*x)
popt, pcov = curve_fit(exponenial_func, x, y, p0=(1,2,2),
bounds=((0, 0, 0), (np.inf, np.inf, np.inf)))
当我第一次这样做时,我得到了这个:
这是最小化残差,每个点具有相同的重要性。 我想要的是获得一条曲线,它更重视曲线的最后一个值(例如,从 x 轴 30 开始)而不是第一个值,因此它更适合曲线的末尾而不是开始它的。
我知道从这里开始有很多方法可以解决这个问题(首先,定义我想赋予每个残差的重要性)。我的问题是想知道如何处理这个问题。
我的一个想法是更改 sigma 值以通过其倒数对每个数据点进行加权。
popt, pcov = curve_fit(exponenial_func, x, y, p0=(1,2,2),
bounds=((0, 0, 0), (np.inf, np.inf, np.inf)),
sigma=1/y)
在这种情况下,我得到了我正在寻找的东西:
看起来不错,但我正在寻找另一种方法,这样我就可以 "control" 每个数据点,比如以线性方式对每个残差进行加权,或指数,甚至手动选择它(而不是像前面的情况那样通过逆向选择它们)。
提前致谢
首先请注意,不需要三个系数。自
a * b**(c*x) = a * exp(log(b)*c*x).
我们可以定义k = log(b)*c
。
这里有一个建议,你可以如何 手动 使用 scipy.optimize.least_squares 和优先向量:
import numpy as np
from scipy.optimize import least_squares
def exponenial_func2(x, a, k):
return a * np.exp(k*x)
# returns the vector of residuals
def fitwrapper2(coeffs, *args):
xdata, ydata, prio = args
return prio*(exponenial_func2(xdata, *coeffs)-ydata)
# Data
n = 31
xdata = np.arange(n)
ydata = np.array([155.0,229,322,453,655,888,1128,1694,
2036,2502,3089,3858,4636,5883,7375,
9172,10149,12462,12462,17660,21157,
24747,27980,31506,35713,41035,47021,
53578,59138,63927,69176])
# The priority vector
prio = np.ones(n)
prio[-1] = 5
res = least_squares(fitwrapper2, x0=[1.0,2.0], bounds=(0,np.inf), args=(xdata,ydata,prio))
对于
prio[-1] = 5
,我们将最后一点放在高优先级。res.x
包含您的最佳系数。这里a, k = res.x
.请注意,对于
prio = np.ones(n)
,这是一个正常的最小二乘拟合(就像 curve_fit 那样),其中所有点都具有相同的 优先级 .
您可以通过增加 prio
数组中每个点的值来控制每个点的优先级。比较这两个结果给我: