有没有一种方法可以使用R中的optim来优化ODE的初始值



我想使用optim优化R中的值(numcaseswk0(。然而,该值不是ODE的参数,只是一个初始值。

下面显示的代码试图做到这一点,但优化过程不断失败,只产生用户提供的上限。我怀疑这可能是由于numcaseswk0不是ODE的参数之一。如果有人能告诉我如何解决这个问题,我会很高兴。谢谢


library(deSolve)
### ODE FUNCTION
HAVODE <- function(t, states, parameters){
with(as.list(c(states,parameters)),
{
N    <- S + L + Z + I + R
dS <- -beta * S * (I/N) 
dL <-  beta * S * (I/N) - (1/durL)*L
dI <-  (1/durL)*L +(1/durRel)*R - (1/durI)*I             
dZ <- (1-propRelapse)*(1/durI)*I
dR <- propRelapse*(1/durI)*I - (1/durRel)*R 
return(list(c(dS, dL, dI, dZ, dR)))
})
}
### COST FUNCTION
calib_function <- function(x, parameters,observed.){
## Variable to be optimized
numcaseswk0 <- x
initpop = parameters[1]
durL = parameters[2]
durI = parameters[3]
fracImmune = parameters[4]
durRel = parameters[5]
propRelapse = parameters[6]
probdetec = parameters[7]
beta  = parameters[8]
## Starting values for states 
S. = (1-fracImmune)*initpop
L. = numcaseswk0              # ***  I want this value to be optimized
I. = 0
Z. = fracImmune*initpop
R. = 0  
states = c(S=S., L= L. , I=I.,  Z=Z.,   R=R.)
## Parameters to be fed into ODE solver
parameters1 = c(durL = durL, durI = durI,durRel = durRel, propRelapse = propRelapse,  beta = beta  )                 
tspan = seq(0, length(observed.)+10); 
# Run the ODE solver
result <- data.frame(ode(y = states, times = tspan,  func = HAVODE,  parms = parameters1))
# Calculating model response (number of detected incident cases)
IncDetec <- probdetec *((1/durL)*result[, 3] + (1/durRel)*result[, 6])
model_response <- IncDetec[-1][1:length(observed.)]     # exclude initial week

# Calculate negative log likelihood of model responses
NLLK <- -sum(dpois(x = floor(model_response), lambda = observed., log = TRUE ))
if (NLLK == Inf){
NLLK = 999999    # if NLLK is infinity, replace by a large number
}
return(NLLK)  
}
## vector of starting values
x0 <- 2
## set lower and upper bounds for these variables
upper <- 10
lower <- 1
## Call the cost function with optim
calib_parameters <- c(135722, 9.2088, 2.6047, 0.47, 3.930, 7.21, 0.094, 0.517)
optimization_results <- optim(par=x0, lower = lower,  upper = upper, method = 'Brent', fn = calib_function, parameters = calib_parameters,  observed. =  abs(rnorm(50, mean=6, sd=3)))

运行上面的代码给出:

> optimization_results
$par
[1] 1.000001
$value
[1] 113463174144
$counts
function gradient 
NA       NA 
$convergence
[1] 0
$message
NULL

optim产生的估计是所提供的下界的值(lower=1(。您可能还注意到,没有功能评估。为什么优化不适用于numcaseswk0

正如Ben已经指出的,代码示例是不可复制的。如果我发布一个教程示例中的代码片段,也许会对你有所帮助http://desolve.r-forge.r-project.org/user2014/examples/FME/fit_twocomp.svg

该示例使用包FME,它封装optim(和其他优化器(并提供一些额外的支持。

### ============================================================================
### code snippet from the useR!2014 (Los Angeles) tutorial
###
### Copyright tpetzoldt, license: GPL >= 2.0
### more see: 
###   http://desolve.r-forge.r-project.org/user2014/examples/FME/fit_twocomp.svg
### ============================================================================
library(deSolve)
library(FME)
## A two compartment pharmacokinetic model
twocomp <- function (time, y, parms, ...) {
with(as.list(c(parms, y)), {
dCL <- kFL * CF - kLF * CL - ke * CL  # concentration in liver
dCF <-    kLF * CL  - kFL * CF        # concentration in fat
list(c(dCL, dCF))
})
}
parms <- c(ke = 0.2,    kFL = 0.1,  kLF = 0.05)
times <- seq(0, 40, length=200)
y0      <-  c(CL = 1, CF = 0)
out <- ode(y0, times, twocomp, parms)
## -----------------------------------------------------------------------------
## data in database format
## -----------------------------------------------------------------------------
dat2 <- data.frame(
label = rep(c("CL", "CF"), each=8),  # must be the first column
time = rep(seq(0, 28, 4), 2),
value = c(1.31,  0.61,  0.49,  0.41,  0.20,  0.12,  0.16,  0.21,
0.001, 0.041, 0.050, 0.039, 0.031, 0.025, 0.017, 0.012)
)
## -----------------------------------------------------------------------------
## fit parameters and initial values
## -----------------------------------------------------------------------------
parms <- c(CL = 1.0, CF = 0.0, ke = 0.2,    kFL = 0.1,  kLF = 0.05)
cost <- function(p, data, ...) {
yy <- p[c("CL", "CF")]           # initial values
pp <-  p[c("ke", "kFL", "kLF")]  # start parameters
out  <-  ode(yy, times, twocomp, pp)
modCost(out, data, y="value", ...)
}
## The default Marq optimizer fails here, so we use another, e.g. Port        
fit6  <- modFit(f = cost, p = parms, data=dat2, weight="std",
lower=rep(0, 5), upper=c(2,2,1,1,1), method="Port")
summary(fit6)        
y0 <- coef(fit6)[c("CL", "CF")]
pp <- coef(fit6)[c("ke", "kFL", "kLF")]
out6 <- ode(y0, times, twocomp, pp)
plot(out, out6, obs=dat2)

我认为您的模型规范有问题。优化器正确运行(从技术意义上讲(,并且最佳参数零。

请查看评论,更改内容:

  • 更大的惩罚值
  • 将成本值重新调整到可行范围
  • 对成本函数的一些手动测试调用
  • 一些可能有助于调试的cat((函数
  • 还要注意,"点"语法(L.、R.等(不是必需的

以下内容可能仍然不是您想要的,但有望帮助它运行。祝你好运

library(deSolve)
### ODE FUNCTION
HAVODE <- function(t, states, parameters){
with(as.list(c(states,parameters)),
{
N    <- S + L + Z + I + R
#cat("N=", N, "n")
dS <- -beta * S * (I/N) 
dL <-  beta * S * (I/N) - (1/durL)*L
dI <-  (1/durL)*L +(1/durRel)*R - (1/durI)*I             
dZ <- (1-propRelapse)*(1/durI)*I
dR <- propRelapse*(1/durI)*I - (1/durRel)*R 
return(list(c(dS, dL, dI, dZ, dR)))
})
}
### COST FUNCTION
calib_function <- function(x, parameters,observed.){
## Variable to be optimized
#cat("x=", x, "n")
numcaseswk0 <- x
initpop = parameters[1]
durL = parameters[2]
durI = parameters[3]
fracImmune = parameters[4]
durRel = parameters[5]
propRelapse = parameters[6]
probdetec = parameters[7]
beta  = parameters[8]
## Starting values for states 
S. = (1-fracImmune)*initpop
L. = numcaseswk0              # ***  I want this value to be optimized
I. = 0
Z. = fracImmune*initpop
R. = 0  
states = c(S=S., L= L. , I=I.,  Z=Z.,   R=R.)
#cat(states, "n")
## Parameters to be fed into ODE solver
parameters1 = c(durL = durL, durI = durI,durRel = durRel, propRelapse = propRelapse,  beta = beta  )                 
tspan = seq(0, length(observed.)+10); 
# Run the ODE solver
result <- data.frame(ode(y = states, times = tspan,  func = HAVODE,  parms = parameters1))
# Calculating model response (number of detected incident cases)
IncDetec <- probdetec *((1/durL)*result[, 3] + (1/durRel)*result[, 6])
model_response <- IncDetec[-1][1:length(observed.)]     # exclude initial week

# Calculate negative log likelihood of model responses
NLLK <- -sum(dpois(x = floor(model_response), lambda = observed., log = TRUE ))
## tpe: set it to a really large value
if (!is.finite(NLLK)){
NLLK = 0.1 * .Machine$double.xmax    # if NLLK is infinity, replace by a large number
}
## tpe: re-scale return value to a numerically feasible range
return(NLLK * 1e-10)  
}
## vector of starting values
x0 <- 2
## set lower and upper bounds for these variables
upper <- 10
lower <- 0
## Call the cost function with optim
calib_parameters <- c(135722, 9.2088, 2.6047, 0.47, 3.930, 7.21, 0.094, 0.517)
## tpe: reproducible comparison data
set.seed(42)
observed <- abs(rnorm(50, mean=6, sd=3))
## test manually
calib_function(1, calib_parameters, observed)
calib_function(0, calib_parameters, observed)
calib_function(10, calib_parameters, observed)
## tpe: we see that zero *is* the best among these
## optimize automatically
optimization_results <- optim(par=x0, lower = lower,  upper = upper, 
method = 'L-BFGS-B', fn = calib_function, 
parameters = calib_parameters,  
observed. =  observed,
control=list(trace=TRUE))

optimization_results
## tpe: optimized par is again zero, that confirms the manual test

最新更新