我有一组数据,我想比较哪条线最能描述它(不同阶的多项式,指数或对数)。
我使用Python和Numpy和多项式拟合有一个函数polyfit()。但我没有发现这样的函数的指数和对数拟合。
有吗?或者如何解决这个问题?
我有一组数据,我想比较哪条线最能描述它(不同阶的多项式,指数或对数)。
我使用Python和Numpy和多项式拟合有一个函数polyfit()。但我没有发现这样的函数的指数和对数拟合。
有吗?或者如何解决这个问题?
当前回答
我们在解决这两个问题的同时演示了lmfit的特性。
鉴于
import lmfit
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
np.random.seed(123)
# General Functions
def func_log(x, a, b, c):
"""Return values from a general log function."""
return a * np.log(b * x) + c
# Data
x_samp = np.linspace(1, 5, 50)
_noise = np.random.normal(size=len(x_samp), scale=0.06)
y_samp = 2.5 * np.exp(1.2 * x_samp) + 0.7 + _noise
y_samp2 = 2.5 * np.log(1.2 * x_samp) + 0.7 + _noise
Code
方法1 - lmfit模型
拟合指数数据
regressor = lmfit.models.ExponentialModel() # 1
initial_guess = dict(amplitude=1, decay=-1) # 2
results = regressor.fit(y_samp, x=x_samp, **initial_guess)
y_fit = results.best_fit
plt.plot(x_samp, y_samp, "o", label="Data")
plt.plot(x_samp, y_fit, "k--", label="Fit")
plt.legend()
方法2 -自定义模型
拟合日志数据
regressor = lmfit.Model(func_log) # 1
initial_guess = dict(a=1, b=.1, c=.1) # 2
results = regressor.fit(y_samp2, x=x_samp, **initial_guess)
y_fit = results.best_fit
plt.plot(x_samp, y_samp2, "o", label="Data")
plt.plot(x_samp, y_fit, "k--", label="Fit")
plt.legend()
细节
选择一个回归类 提供命名的、尊重函数域的初始猜测
您可以从回归器对象确定推断出的参数。例子:
regressor.param_names
# ['decay', 'amplitude']
要进行预测,请使用ModelResult.eval()方法。
model = results.eval
y_pred = model(x=np.array([1.5]))
注意:ExponentialModel()遵循一个衰减函数,它接受两个参数,其中一个是负的。
请参见ExponentialGaussianModel(),它接受更多参数。
通过> pip Install lmfit安装库。
其他回答
我想你可以用:
np.log --> natural log
np.log10 --> base 10
np.log2 --> base 2
稍微修改一下IanVS的答案:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
def func(x, a, b, c):
#return a * np.exp(-b * x) + c
return a * np.log(b * x) + c
x = np.linspace(1,5,50) # changed boundary conditions to avoid division by 0
y = func(x, 2.5, 1.3, 0.5)
yn = y + 0.2*np.random.normal(size=len(x))
popt, pcov = curve_fit(func, x, yn)
plt.figure()
plt.plot(x, yn, 'ko', label="Original Noised Data")
plt.plot(x, func(x, *popt), 'r-', label="Fitted Curve")
plt.legend()
plt.show()
结果如下图所示:
要拟合y = A + B log x,只需将y与(log x)拟合。
>>> x = numpy.array([1, 7, 20, 50, 79])
>>> y = numpy.array([10, 19, 30, 35, 51])
>>> numpy.polyfit(numpy.log(x), y, 1)
array([ 8.46295607, 6.61867463])
# y ≈ 8.46 log(x) + 6.62
为了拟合y = AeBx,两边取对数得到log y = log A + Bx。把log y和x匹配起来。
请注意,拟合(log y)如果是线性的,将强调y的小值,导致大y的大偏差。这是因为polyfit(线性回归)通过最小化∑i (ΔY)2 =∑i (Yi−Ŷi)2来工作。当Yi = log Yi时,余数ΔYi = Δ(log Yi)≈Δyi / | Yi |。因此,即使多拟合对大y做出了非常糟糕的决定,“除以-|y|”因素也会补偿它,导致多拟合倾向于小值。
这可以通过给每个条目一个与y成比例的“权重”来缓解。polyfit通过w关键字参数支持加权最小二乘。
>>> x = numpy.array([10, 19, 30, 35, 51])
>>> y = numpy.array([1, 7, 20, 50, 79])
>>> numpy.polyfit(x, numpy.log(y), 1)
array([ 0.10502711, -0.40116352])
# y ≈ exp(-0.401) * exp(0.105 * x) = 0.670 * exp(0.105 * x)
# (^ biased towards small values)
>>> numpy.polyfit(x, numpy.log(y), 1, w=numpy.sqrt(y))
array([ 0.06009446, 1.41648096])
# y ≈ exp(1.42) * exp(0.0601 * x) = 4.12 * exp(0.0601 * x)
# (^ not so biased)
请注意,Excel、LibreOffice和大多数科学计算器通常使用未加权(有偏差)公式来计算指数回归/趋势线。如果您希望您的结果与这些平台兼容,即使它提供了更好的结果,也不要包含权重。
如果你可以使用scipy,你可以使用scipy。optimize。Curve_fit适合任何不需要转换的模型。
对于y = A + B log x,结果与变换方法相同:
>>> x = numpy.array([1, 7, 20, 50, 79])
>>> y = numpy.array([10, 19, 30, 35, 51])
>>> scipy.optimize.curve_fit(lambda t,a,b: a+b*numpy.log(t), x, y)
(array([ 6.61867467, 8.46295606]),
array([[ 28.15948002, -7.89609542],
[ -7.89609542, 2.9857172 ]]))
# y ≈ 6.62 + 8.46 log(x)
然而,对于y = AeBx,我们可以得到一个更好的拟合,因为它直接计算Δ(log y)。但是我们需要提供一个初始化的猜测,以便curve_fit能够达到所需的局部最小值。
>>> x = numpy.array([10, 19, 30, 35, 51])
>>> y = numpy.array([1, 7, 20, 50, 79])
>>> scipy.optimize.curve_fit(lambda t,a,b: a*numpy.exp(b*t), x, y)
(array([ 5.60728326e-21, 9.99993501e-01]),
array([[ 4.14809412e-27, -1.45078961e-08],
[ -1.45078961e-08, 5.07411462e+10]]))
# oops, definitely wrong.
>>> scipy.optimize.curve_fit(lambda t,a,b: a*numpy.exp(b*t), x, y, p0=(4, 0.1))
(array([ 4.88003249, 0.05531256]),
array([[ 1.01261314e+01, -4.31940132e-02],
[ -4.31940132e-02, 1.91188656e-04]]))
# y ≈ 4.88 exp(0.0553 x). much better.
Wolfram有一个封闭形式的解拟合指数。他们也有类似的解决方案拟合对数和幂律。
我发现这比scipy的curve_fit工作得更好。特别是当你没有“接近零”的数据时。这里有一个例子:
import numpy as np
import matplotlib.pyplot as plt
# Fit the function y = A * exp(B * x) to the data
# returns (A, B)
# From: https://mathworld.wolfram.com/LeastSquaresFittingExponential.html
def fit_exp(xs, ys):
S_x2_y = 0.0
S_y_lny = 0.0
S_x_y = 0.0
S_x_y_lny = 0.0
S_y = 0.0
for (x,y) in zip(xs, ys):
S_x2_y += x * x * y
S_y_lny += y * np.log(y)
S_x_y += x * y
S_x_y_lny += x * y * np.log(y)
S_y += y
#end
a = (S_x2_y * S_y_lny - S_x_y * S_x_y_lny) / (S_y * S_x2_y - S_x_y * S_x_y)
b = (S_y * S_x_y_lny - S_x_y * S_y_lny) / (S_y * S_x2_y - S_x_y * S_x_y)
return (np.exp(a), b)
xs = [33, 34, 35, 36, 37, 38, 39, 40, 41, 42]
ys = [3187, 3545, 4045, 4447, 4872, 5660, 5983, 6254, 6681, 7206]
(A, B) = fit_exp(xs, ys)
plt.figure()
plt.plot(xs, ys, 'o-', label='Raw Data')
plt.plot(xs, [A * np.exp(B *x) for x in xs], 'o-', label='Fit')
plt.title('Exponential Fit Test')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
还可以使用scipy.optimize中的curve_fit将一组数据适合于任何函数。例如,如果你想拟合一个指数函数(来自文档):
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
def func(x, a, b, c):
return a * np.exp(-b * x) + c
x = np.linspace(0,4,50)
y = func(x, 2.5, 1.3, 0.5)
yn = y + 0.2*np.random.normal(size=len(x))
popt, pcov = curve_fit(func, x, yn)
然后如果你想画出来,你可以这样做:
plt.figure()
plt.plot(x, yn, 'ko', label="Original Noised Data")
plt.plot(x, func(x, *popt), 'r-', label="Fitted Curve")
plt.legend()
plt.show()
(注意:当你绘图时,popt前面的*会将项展开为func所期望的a, b和c。)
我们在解决这两个问题的同时演示了lmfit的特性。
鉴于
import lmfit
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
np.random.seed(123)
# General Functions
def func_log(x, a, b, c):
"""Return values from a general log function."""
return a * np.log(b * x) + c
# Data
x_samp = np.linspace(1, 5, 50)
_noise = np.random.normal(size=len(x_samp), scale=0.06)
y_samp = 2.5 * np.exp(1.2 * x_samp) + 0.7 + _noise
y_samp2 = 2.5 * np.log(1.2 * x_samp) + 0.7 + _noise
Code
方法1 - lmfit模型
拟合指数数据
regressor = lmfit.models.ExponentialModel() # 1
initial_guess = dict(amplitude=1, decay=-1) # 2
results = regressor.fit(y_samp, x=x_samp, **initial_guess)
y_fit = results.best_fit
plt.plot(x_samp, y_samp, "o", label="Data")
plt.plot(x_samp, y_fit, "k--", label="Fit")
plt.legend()
方法2 -自定义模型
拟合日志数据
regressor = lmfit.Model(func_log) # 1
initial_guess = dict(a=1, b=.1, c=.1) # 2
results = regressor.fit(y_samp2, x=x_samp, **initial_guess)
y_fit = results.best_fit
plt.plot(x_samp, y_samp2, "o", label="Data")
plt.plot(x_samp, y_fit, "k--", label="Fit")
plt.legend()
细节
选择一个回归类 提供命名的、尊重函数域的初始猜测
您可以从回归器对象确定推断出的参数。例子:
regressor.param_names
# ['decay', 'amplitude']
要进行预测,请使用ModelResult.eval()方法。
model = results.eval
y_pred = model(x=np.array([1.5]))
注意:ExponentialModel()遵循一个衰减函数,它接受两个参数,其中一个是负的。
请参见ExponentialGaussianModel(),它接受更多参数。
通过> pip Install lmfit安装库。