使用Scipy曲线拟合的低效曲线拟合

时间:2019-10-22 13:20:50

标签: numpy curve-fitting scipy-optimize

我正在研究模型,使用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 FunctionAdstock 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()

您会注意到我使用的是受限方法,因为该功能在整个域中都是不可微的且连续的

此代码通常产生以下输出: enter image description here

如您所见,大多数变量表现良好,并且在真实值附近或多或少地正态分布。 Beta K 并非如此。对于curve_fit拟合这些特定参数的难度有“足够简单”的解释吗?无论如何,我可以提高代码性能吗?比curve_fit更好的方法来拟合这些参数?

什么是人工智能(或预期的输出): 所有拟合参数均具有正态(或准正态)分布,均值接近真实值,标准偏差为尽可能小。

PS: * Beta和K必须大于0,但从理论上讲,您可以松开上限。但是,如果这样做,curve_fit将无法适应和分散。还不知道为什么... *

编辑:根据Christian´s的建议,我还保留了协方差矩阵,这就是它们的样子:

平均值:

Average Covariance Matrix

中值:

Median Covariance Matrix

0 个答案:

没有答案