Простая динамическая модель в PyMC3
Я пытаюсь собрать модель динамической системы в PyMC3, чтобы вывести два параметра. Модель является основным SIR, обычно используемым в эпидемиологии:
дс / дт = - г0 * г * с * я
dI/dt = g * I ( r * S - 1)
где r0 и g - параметры, которые будут выведены. До сих пор я не могу пройти очень далеко. Единственные примеры, которые я видел, собирая цепочку Маркова, подобную этой, дают ошибки о слишком глубокой рекурсии. Вот мой пример кода.
# Time
t = np.linspace(0, 8, 200)
# Simulated observation
def SIR(y, t, r0, gamma) :
S = - r0 * gamma * y[0] * y[1]
I = r0 * gamma * y[0] * y[1] - gamma * y[1]
return [S, I]
# Currently no noise, we just want to infer params r0 = 16 and g = 0.5
solution = odeint(SIR, [0.99, 0.01, 0], t, args=(16., 0.5))
with pymc.Model() as model :
r0 = pymc.Normal("r0", 15, sd=10)
gamma = pymc.Uniform("gamma", 0.3, 1.)
# Use forward Euler to solve
dt = t[1] - t[0]
# Initial conditions
S = [0.99]
I = [0.01]
for i in range(1, len(t)) :
S.append(pymc.Normal("S%i" % i, \
mu = S[-1] + dt * (-r0 * gamma * S[-1] * I[-1]), \
sd = solution[:, 0].std()))
I.append(pymc.Normal("I%i" % i, \
mu = I[-1] + dt * ( r0 * gamma * S[-1] * I[-1] - gamma * I[-1]), \
sd = solution[:, 1].std()))
Imcmc = pymc.Normal("Imcmc", mu = I, sd = solution[:, 1].std(), observed = solution[:, 1])
#start = pymc.find_MAP()
trace = pymc.sample(2000, pymc.NUTS())
Любая помощь приветствуется. Спасибо!
1 ответ
Я бы попробовал определить новый дистрибутив. Что-то вроде следующего. Тем не менее, это не совсем работает, и я не совсем уверен, что я сделал не так.
class SIR(Distribution):
def __init__(self, gamma, r0,dt, std):
self.gamma = gamma
self.r0 = r0
self.std = std
self.dt = dt
def logp(self, SI):
r0 = self.r0
std = self.std
gamma = self.gamma
dt = self.dt
S=SI[:,0]
I=SI[:,1]
Si = S[1:]
Si_m1 = S[:-1]
Ii = I[1:]
Ii_m1 = I[:-1]
Sdelta = (Si - Si_m1)
Idelta = (Ii - Ii_m1)
Sexpected_delta = dt* (-r0 * gamma * Si_m1 * Ii_m1)
Iexpected_delta = dt * gamma * Ii_m1 *( r0 * Si_m1 - 1 )
return (Normal.dist(Sexpected_delta, sd=std).logp(Sdelta) +
Normal.dist(Iexpected_delta, sd=std).logp(Idelta))
with Model() as model:
r0 = pymc.Normal("r0", 15, sd=10)
gamma = pymc.Normal("gamma", 0.3, 1.)
std = .5
dt = t[1]-t[0]
SI = SIR('SI', gamma, r0, std,dt, observed=solution[:,:2])
#start = pymc.find_MAP(start={'gamma' : .45, 'r0' : 17})
trace = pymc.sample(2000, pymc.NUTS())