R函数loglik()返回-inf?

R function loglik() returning -inf?

在 R 中模拟 SIR 模型。我有一个数据集,我正试图用该模型准确绘制。我现在正在使用粒子过滤功能,然后想在结果上使用相应的 logLik 方法。当我这样做时,结果是“[1] -Inf”。我在文档中找不到这是为什么以及如何避免它。我的模型参数是否不够准确?还有什么问题吗?

我的函数如下所示: SIRsim %>% pfilter(Np=5000) -> pf logLik(pf)

来自题为 POMPS 的可能性 https://kingaa.github.io/sbied/pfilter/ 的在线课程,这是该课程的 R 脚本。然而,代码在这里工作......我不确定如何用它重现我的特定问题,不幸的是无法共享我正在使用的数据集或代码,因为它用于学术研究。

library(tidyverse)
library(pomp)
options(stringsAsFactors=FALSE)
stopifnot(packageVersion("pomp")>="3.0")
set.seed(1350254336)

library(tidyverse)
library(pomp)

sir_step <- Csnippet("
double dN_SI = rbinom(S,1-exp(-Beta*I/N*dt));
double dN_IR = rbinom(I,1-exp(-mu_IR*dt));
S -= dN_SI;
I += dN_SI - dN_IR;
R += dN_IR;
H += dN_IR;
")

sir_init <- Csnippet("
S = nearbyint(eta*N);
I = 1;
R = nearbyint((1-eta)*N);
H = 0;
")

dmeas <- Csnippet("
lik = dbinom(reports,H,rho,give_log);
")

rmeas <- Csnippet("
reports = rbinom(H,rho);
")

read_csv("https://kingaa.github.io/sbied/pfilter/Measles_Consett_1948.csv") 
%>%
  select(week,reports=cases) %>%
  filter(week<=42) %>%
  pomp(
    times="week",t0=0,
    rprocess=euler(sir_step,delta.t=1/7),
    rinit=sir_init,
    rmeasure=rmeas,
    dmeasure=dmeas,
    accumvars="H",
    statenames=c("S","I","R","H"),
    paramnames=c("Beta","mu_IR","eta","rho","N"),
    params=c(Beta=15,mu_IR=0.5,rho=0.5,eta=0.06,N=38000)
  ) -> measSIR

measSIR %>%
  pfilter(Np=5000) -> pf
logLik(pf)

library(doParallel)
library(doRNG)
registerDoParallel()
registerDoRNG(652643293)
foreach (i=1:10, .combine=c) %dopar% {
  measSIR %>% pfilter(Np=5000)
} -> pf
logLik(pf) -> ll
logmeanexp(ll,se=TRUE)

如果我在上面的代码中设置 Beta=100,我可以获得负无限对数似然。

将测量错误片段替换为:

dmeas <- Csnippet("
      double ll = dbinom(reports,H,rho,give_log);
      lik =  (!isfinite(ll) ? -1000 : ll );
")

似乎是 'solve' 问题,尽管您应该稍微小心一点;像这样掩盖数字裂缝有时是可以的,但可以想象稍后会以某种方式回来咬你。如果您只需要避免非有限值足够长的时间以进入合理的参数范围,这可能没问题...

关于为什么会发生这种情况的一些猜测:

  • 您不知何故遇到了“不可能”的情况,例如当潜在的真实感染数为零时报告的病例数为正数。
  • 有时,当非常小的正概率下溢为零时,会出现非有限对数似然。这里相当于很可能感染概率 1-exp(-Beta*I/N*dt) 变为 1.0;那么任何观察到的结果都是不可能有不到 100% 的人口被感染的。

您可以尝试通过查看过滤后的轨迹实际情况并将其与数据进行比较,或者通过在代码中添加调试语句来诊断情况。如果有一种方法可以 运行 仅使用您的参数值进行确定性模拟,这可能会很快告诉您出了什么问题。

easier/more 一种直接的调试方法是用 R 函数替换您用于 dmeas 的 Csnippet:这会更慢但更容易使用(尤其是如果您如果您不熟悉 C 编码)。如果您取消注释下面的 browser() 语句,当您遇到不好的情况时,代码将进入调试模式 ...

dmeas  <- function(reports,H,rho,log, ...) {
    lik <- dbinom(reports,size=H,prob=rho,log=log)
    if (!is.finite(lik)) {
        lik <- -1000
        ## browser()
    }
    return(lik)
}

例如:

(t = 3, reports = 2, S = 2280, I = 0, R = 35721, H = 0, Beta = 100, 
    mu_IR = 0.5, rho = 0.5, eta = 0.06, N = 38000, log = TRUE)
Browse[1]> debug at /tmp/SO65554258.R!ZlSILG#7: return(lik)
Browse[2]> reports
[1] 2
Browse[2]> H
[1] 0
Browse[2]> rho
[1] 0.5

这表明问题确实是当感染为零时报告的病例数为正数...R 正在尝试计算观察到 reports 病例的二项式概率H 种可能需要报告的感染,每种感染的报告概率为 rho。当二项式概率 Binom(N,p) 中的试验次数 N 为零时,唯一可能的结果为零 'successes'(报告的病例),概率为 1。所有其他结果的概率为 0(并且对数概率 -Inf).