简体   繁体   English

拟合常微分方程的曲线

[英]curve fitting to an ordinary differential equation

I want to fit a curve to the ODE shown below-我想将曲线拟合到如下所示的 ODE -

dA/dt = k1*profit + k2

I have the observed time series of the variables A and profit and I would like to get the optimal values of k1 and k2 using a curve fitting technique in python.我有观察到的变量Aprofit的时间序列,我想在 python 中使用曲线拟合技术获得k1k2的最佳值。 I am able to write the code below for that, but the solutions do not fit well, or maybe my approach is wrong.我可以为此编写下面的代码,但是解决方案不太合适,或者我的方法可能是错误的。

import numpy as np
from scipy.optimize import curve_fit
from scipy.integrate import odeint

def fitfunc(t, k1, k2):
    'Function that returns A computed from an ODE for k1 and k2'
    def myode(area, t):
        profit = get_profit(t)
        return k1*profit + k2

    A0 = 200000    #initial value of A
    out = odeint(myode, A0, t)
    return out[:,0]

k_fit, kcov = curve_fit(fitfunc, time_span, obs_A)  #time span from 1999-2019 and obs_A is the observed values of A

modeled_A = fitfunc(time_span, k_fit[0], k_fit[1])

The profit and obs_A data for the 20 year period is: 20 年期间的利润和 obs_A 数据为:

profit = [ 7.65976374e+06, -6.13172279e+06,  1.03946093e+07,  2.59937877e+06,
       -7.88358386e+06, -1.38918115e+04, -3.13403157e+06, -4.74348806e+06,
        1.87296164e+07,  4.13680709e+07, -1.77191198e+07,  2.39249499e+06,
        1.38521564e+07,  6.52548348e+07, -5.78102494e+07, -5.72469988e+07,
       -5.99056006e+06, -1.72424523e+07,  1.78509987e+07,  9.27860105e+06,
       -9.96709853e+06]

obs_A = [200000., 165000., 150000., 180000., 190000., 195000., 200000.,
       165000., 280000., 235000., 250000., 250000., 250000., 295000.,
       295000., 285000., 245000., 315000., 235000., 245000., 305000.]

time_span = np.arange(1999,2020)

Here get_profit is a function that outputs the value of profit at a given t , its created using interpolating the observed profit data, as below-这里get_profit是一个输出给定t的利润值的函数,它是通过对观察到的profit数据进行插值创建的,如下所示 -

profit_fun = interp1d(t, profit.values, 1, fill_value="extrapolate")

def get_profit(t):
    return profit_fin(t)

I am not sure about how to use the profit variables here as it changes at each time step.我不确定如何在这里使用profit变量,因为它在每个时间步都会发生变化。 Is my approach correct?我的方法正确吗?

(As requested, here's the code) (根据要求,这是代码)

First, setting things up.首先,进行设置。 Only added fitfun2 , which modifies fitfunc removing the call to get_profit (and consequently doesn't interpolate the data).仅添加了fitfun2 ,它修改了fitfunc删除对get_profit的调用(因此不会插入数据)。

import numpy as np
from scipy.optimize import curve_fit
from scipy.integrate import odeint
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt

def fitfunc(t, k1, k2):  # Original
    'Function that returns A computed from an ODE for k1 and k2'
    def myode(area, t):
        profit = get_profit(t)
        return k1*profit + k2

    A0 = 20000    #initial value of A
    out = odeint(myode, A0, t)
    return out[:,0]

def fitfunc2(t, k1, k2): # Modified
    'Modified fitfunc, removing the call to `profit_fun`'
    def myode(area, t):
        return k1*t+k2

    A0 = 20000    #initial value of A
    out = odeint(myode, A0, t)
    return out[:,0]

profit = np.array([ 7.65976374e+06, -6.13172279e+06,  1.03946093e+07,  2.59937877e+06,
       -7.88358386e+06, -1.38918115e+04, -3.13403157e+06, -4.74348806e+06,
        1.87296164e+07,  4.13680709e+07, -1.77191198e+07,  2.39249499e+06,
        1.38521564e+07,  6.52548348e+07, -5.78102494e+07, -5.72469988e+07,
       -5.99056006e+06, -1.72424523e+07,  1.78509987e+07,  9.27860105e+06,
       -9.96709853e+06])

obs_A = np.array([200000., 165000., 150000., 180000., 190000., 195000., 200000.,
       165000., 280000., 235000., 250000., 250000., 250000., 295000.,
       295000., 285000., 245000., 315000., 235000., 245000., 305000.])

time_span = np.arange(1999,2020)

profit_fun = interp1d(time_span, profit, 1, fill_value="extrapolate")

def get_profit(t):
    return profit_fun(t)

Now, fitting and plotting the results现在,拟合并绘制结果

p0 = (1E-2, 1E4)
k_fit, kcov = curve_fit(fitfunc, time_span, obs_A, p0=p0)
k_fit2, kcov2 = curve_fit(fitfunc2, time_span, obs_A, p0=p0)

modeled_A = fitfunc(time_span, *k_fit)
guess_A = fitfunc(time_span, *p0)

modeled_A2 = fitfunc2(time_span, *k_fit2)
guess_A2 = fitfunc2(time_span, *p0)

plt.plot(time_span, obs_A, marker='o', lw=0, label='data')
plt.plot(time_span, modeled_A, label='model A (original)')
plt.plot(time_span, modeled_A2, label='model A (modified)')
plt.plot(time_span, guess_A, label='initial guess (original)')
plt.plot(time_span, guess_A2, label='initial guess (modified)')

plt.legend()

This is the graph:这是图表: 在此处输入图像描述

As I mentioned, modifying the parameters k does not affect the curve shape of the original model.正如我所提到的,修改参数k不会影响原始模型的曲线形状。 It still looks kinda 'stepwise'.它看起来仍然有点“逐步”。 Removing the call to get_profit , the curve becomes much smoother, but I don't know if it's what @Isr729 expected.删除对get_profit的调用,曲线变得更加平滑,但我不知道这是否是 @Isr729 所期望的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM