Python 如何使用scipy.integrate.odeint和时间相关变量求解ODE系统

Python 如何使用scipy.integrate.odeint和时间相关变量求解ODE系统,python,scipy,ode,Python,Scipy,Ode,我正在使用scipy cookbook中的僵尸启示录来学习如何用python解决ODE系统 在这个模型中,有一个方程式根据出生率、死亡率和初始人口提供每天的人口。然后根据人口计算出有多少僵尸被创造和杀死 我感兴趣的是用一系列数据来代替人口微分方程,这些数据告诉我们每个时间步的人口数量。我得到以下错误: TypeError: can't multiply sequence by non-int of type 'float' 正如人们所指出的,这是因为用一个列表乘以单个数字是没有意义的。我不知道

我正在使用scipy cookbook中的僵尸启示录来学习如何用python解决ODE系统

在这个模型中,有一个方程式根据出生率、死亡率和初始人口提供每天的人口。然后根据人口计算出有多少僵尸被创造和杀死

我感兴趣的是用一系列数据来代替人口微分方程,这些数据告诉我们每个时间步的人口数量。我得到以下错误:

TypeError: can't multiply sequence by non-int of type 'float'
正如人们所指出的,这是因为用一个列表乘以单个数字是没有意义的。我不知道如何在每次T时从列表中为微分方程提供一个数字

下面是两次尝试的代码

# solve the system dy/dt = f(y, t)
def f(y, t):
    Si = [345, 299, 933, 444, 265, 322] # replaced an equation with list
    Zi = y[0]
    Ri = y[1]
    # the model equations (see Munz et al. 2009)
    f0 = B*Si*Zi + G*Ri - A*Si*Zi
    f1 = d*Si + A*Si*Zi - G*Ri
    return [f0, f1]
我也试过了

numbers = [345, 299, 933, 444, 265, 322]
for t in [0, 5]:
    Si = numbers

# solve the system dy/dt = f(y, t)
def f(y, t):

    Zi = y[0]
    Ri = y[1]
    # the model equations (see Munz et al. 2009)
    f0 = B*Si*Zi + G*Ri - A*Si*Zi
    f1 = d*Si + A*Si*Zi - G*Ri
    return [f0, f1]

这两种尝试都有相同的问题,将整个列表提供给
f0
f1
,而不是从列表中迭代提供1个数字。

您无法事先知道数值积分器在什么点计算ODE函数。积分器(
odeint
和其他未明确“固定步长”的积分器)动态生成点的内部列表,这些点的步长可能小于或有时也大于给定的采样点列表。输出值从内部列表中插值


如果要用函数替换ODE的一部分,则必须将示例数据转换为函数。这可以通过插值实现。使用该函数生成函数对象,然后您可以像使用任何其他标量函数一样使用。

据我从您问题下面的评论中了解,您尝试合并可能有噪声的测量数据。您可以使用这些数据来适应您的时间进程,而不是直接插入数据。这里我显示变量
S
的结果:

绿点
是从您提供的ODE系统的解决方案中采样的。为了模拟测量误差,我在这些数据中添加了一些噪声(
蓝点
)。然后,您可以调整ODE系统以尽可能好地重现这些数据(
红线

对于这些任务,您可以使用。复制绘图的代码如下所示(可以在内联注释中找到一些解释):


为了具体实现我在问题中提出的要求,即使用值代替一个ODE,您需要使用一个循环,在该循环中,您使用odesolver求解系统1秒,然后将输出作为循环下一次迭代的初始条件。下面是这种方法的代码。然而,正如许多人所指出的,在大多数情况下,最好使用Cleb和其他人所描述的插值

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

Si = [345, 299, 933, 444, 265, 322] # replaced an equation with list

#Parameters
P = 0           # birth rate
d = 0.0001  # natural death percent (per day)
B = 0.0095  # transmission percent  (per day)
G = 0.0001  # resurect percent (per day)
A = 0.0001  # destroy percent  (per day)

# solve the system dy/dt = f(y, t)
def f(y, t):
    Zi = y[0]
    Ri = y[1]
    # the model equations (see Munz et al. 2009)
    f0 = B*Si*Zi + G*Ri - A*Si*Zi
    f1 = d*Si + A*Si*Zi - G*Ri
    return [f0, f1]

# initial conditions
Z0 = 0                      # initial zombie population
R0 = 0                      # initial death population
y0 = [Z0, R0]   # initial condition vector
# a timestep of 1 forces the odesolve to use your inputs at the beginning and provide outputs at the end of the timestep. 
# In this way the problem that LutzL has described is avoided.
t  = np.linspace(0, 1, 2)       
Si =np.array(Si).T

#create a space for storing your outputdata
dataZ =[]
dataR =[]
#use a for loop to use your custom inputs for Si
for Si in Si:
    y0 = [Z0, R0]
    soln = odeint(f, y0, t)
    Z = soln[:, 0]
    R = soln[:, 1]
    #define your outputs as the initial conditions for the next iteration of the loop
    Z_0 = Z[1]
    R_0 = R[1]
    #store your outputs 
    dataZ.append(Z[1])
    dataR.append(R[1])


print (dataZ)
print (dataR)

对于我正在做的一个实际问题,我需要用实际数据列表替换系统中的一个微分方程。我也尝试在Y函数定义之外定义Si,但是得到了相同的错误
code
numbers=[345299933444265322]
code
对于[0,5]中的t:
code
Si=numbers而不是谈论用数字列表替换微分方程(这对我来说没有意义),试着从一开始就用你掌握的信息来解释这个问题。例如,“我有一个数字列表。这些数字的含义是[…]。我想模拟一个过程,在这个过程中,这些数字被用来[…]”你是对的,我用一种特别愚蠢的方式表达了我的问题,我道歉。我确实理解你的观点和蟒蛇的错误,我不能用列表乘以我的数字。我试图理解如何在每个时间步t向f0和f1方程提供列表中的一项。谢谢你花时间来帮助我。我没有清楚地表达我想做什么。我是一名生物学家,我有一个共同的ODE系统,它模拟一种蛋白质如何被激活,然后与其他几种蛋白质相互作用。我现在有了给定时间跨度内激活蛋白水平的真实数据,我想用实时序列数据替换模型中表示该蛋白激活的方程。在僵尸启示录模型的类比中,我想用不同时间点的人类流行列表来代替描述人口出生率和死亡率的方程式。我编辑了问题标题和问题。谢谢你的时间。谢谢你的回答。它清晰易懂。不幸的是Interpollate不适合我,我的数据非常嘈杂,它基本上是一个云。是否有一种替代odeint的方法可以使用固定的步长?如果不是,我需要使用一个循环来明确地指定步长为1吗?@BobbyM:噪音其实并不重要;您仍然可以尝试调整您的数据(我在下面添加了代码)。非常感谢您花时间做出此响应。我会学习的&我相信我会学到很多。我应该更清楚我的犹豫(我正在学习编码,甚至谈论编码都需要非常精确)。问题在于,绿点和蓝点都会产生类似的拟合方程。我的目标是找出生物过程中每一步对输出噪声的相对贡献。通过将真实数据强制到模型中,我希望看到它在最终输出中产生了多少噪声。我可能需要重新考虑我的计划approach@BobbyM:绿色圆点未用于配合。它们代表“真实”数据,即没有任何测量误差的数据。在现实生活中,这是不现实的,你总是会有测量误差,生物变异(基因表达是随机的)。为了模拟这一点,我在用蓝点表示的真实数据中添加了噪声。红线仅通过将蓝色圆点放入
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

Si = [345, 299, 933, 444, 265, 322] # replaced an equation with list

#Parameters
P = 0           # birth rate
d = 0.0001  # natural death percent (per day)
B = 0.0095  # transmission percent  (per day)
G = 0.0001  # resurect percent (per day)
A = 0.0001  # destroy percent  (per day)

# solve the system dy/dt = f(y, t)
def f(y, t):
    Zi = y[0]
    Ri = y[1]
    # the model equations (see Munz et al. 2009)
    f0 = B*Si*Zi + G*Ri - A*Si*Zi
    f1 = d*Si + A*Si*Zi - G*Ri
    return [f0, f1]

# initial conditions
Z0 = 0                      # initial zombie population
R0 = 0                      # initial death population
y0 = [Z0, R0]   # initial condition vector
# a timestep of 1 forces the odesolve to use your inputs at the beginning and provide outputs at the end of the timestep. 
# In this way the problem that LutzL has described is avoided.
t  = np.linspace(0, 1, 2)       
Si =np.array(Si).T

#create a space for storing your outputdata
dataZ =[]
dataR =[]
#use a for loop to use your custom inputs for Si
for Si in Si:
    y0 = [Z0, R0]
    soln = odeint(f, y0, t)
    Z = soln[:, 0]
    R = soln[:, 1]
    #define your outputs as the initial conditions for the next iteration of the loop
    Z_0 = Z[1]
    R_0 = R[1]
    #store your outputs 
    dataZ.append(Z[1])
    dataR.append(R[1])


print (dataZ)
print (dataR)