我正在研究模型,使用scipy.optimize.curve_fit查找更适合数据的参数。为了调查该功能是否正常工作,我开始按照文档中的建议对随机输入进行拟合以增加噪声。
功能:
def mom(x, alpha=.5, theta=1, k=1, s=.5, beta=1):
# Weight Function
w_ = np.array([alpha ** ((l - theta) ** 2) for l in range(13)])
# Adstock Function
X_ = np.array([(sum(w_ * np.array([x[i - l]
if ((i - l) >= 0)
else 0
for l in range(13)]
)
)
) / sum(w_)
for i in range(len(x))
]
)
return np.array([beta-(((k**s)*beta)/((x**s)+(k**s))) for x in X_])
如您所见,该函数是非线性的,其偏导数相当复杂。此处实现的功能是将Hill Function与Adstock Function(等式3)结合起来:
然后我迭代运行curve_fit并使用以下代码将拟合参数的分布测量为其真实值:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.optimize import curve_fit
from statsmodels.tools.eval_measures import rmse, meanabs, maxabs
def get_default_args(func):
import inspect
signature = inspect.signature(func)
return {
k: v.default
for k, v in signature.parameters.items()
if v.default is not inspect.Parameter.empty
}
true_params = get_default_args(mom)
model_res = []
for i in range(100):
X = np.random.random_sample((36,))
ydata = mom(X)
y_noise = 0.02 * np.random.normal(size=X.size)
Y = ydata + y_noise
popt, pcov = curve_fit(mom, X, Y,
method='trf',
bounds=([0, 0, 0, 0, -2], [1, 12, 5, 5, 2]),
maxfev=10000)
acc = rmse(ydata, mom(X, popt[0], popt[1], popt[2], popt[3], popt[4]))
mae = meanabs(ydata, mom(X, popt[0], popt[1], popt[2], popt[3], popt[4]))
maxe = maxabs(ydata, mom(X, popt[0], popt[1], popt[2], popt[3], popt[4]))
model_res.append({'alpha': popt[0],
'theta': popt[1],
'k': popt[2],
's': popt[3],
'beta': popt[4],
'rmse': acc,
'mae': mae,
'max_error': maxe})
# appending covariance matrix
cov.append(pcov)
print("{0} of 100".format(i), end='\r', flush=True)
df = pd.DataFrame.from_dict(model_res)
fig = plt.figure(figsize=(30, 30))
axs = []
for i in range(1, 9):
axs.append(fig.add_subplot(4, 2, i))
for col, ax in zip(df.select_dtypes(include="float64").columns, axs):
if col in true_params.keys():
ax.axvline(true_params[col], linewidth=4, color='r')
ax.legend(labels=["True {0}".format(col)], loc='upper right')
else:
ax.axvline(df[col].mean(), linewidth=4, color='r')
ax.axvline(df[col].median(), linewidth=4, color='g')
ax.legend(labels=["Mean", "Median"], loc='upper right')
sns.distplot(a=df[col], ax=ax)
plt.show()
您会注意到我使用的是受限方法,因为该功能在整个域中都是不可微的且连续的
如您所见,大多数变量表现良好,并且在真实值附近或多或少地正态分布。 Beta 和 K 并非如此。对于curve_fit拟合这些特定参数的难度有“足够简单”的解释吗?无论如何,我可以提高代码性能吗?比curve_fit更好的方法来拟合这些参数?
什么是人工智能(或预期的输出): 所有拟合参数均具有正态(或准正态)分布,均值接近真实值,标准偏差为尽可能小。
PS: * Beta和K必须大于0,但从理论上讲,您可以松开上限。但是,如果这样做,curve_fit将无法适应和分散。还不知道为什么... *
编辑:根据Christian´s的建议,我还保留了协方差矩阵,这就是它们的样子:
平均值:
中值: