【问题标题】:capturing convergence message from lme4 package in R从 R 中的 lme4 包中捕获收敛消息
【发布时间】:2021-01-14 18:48:17
【问题描述】:

我想知道是否有办法编写逻辑测试 (TRUE/FALSE) 来显示来自 lme4 包的模型是否已收敛?

下面是一个例子,我想捕捉任何模型是否带有收敛警告(即Model failed to converge)消息?

library(lme4)

dat <- read.csv('https://raw.githubusercontent.com/rnorouzian/e/master/nc.csv')

m <- lmer(math ~ ses*sector + (ses | sch.id), data = dat)

Warning message:
In checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv,  :
  Model failed to converge with max|grad| = 0.00279 (tol = 0.002, component 1)

【问题讨论】:

    标签: r function regression lme4


    【解决方案1】:

    我们可以使用tryCatch,使用withCallingHandlersthis 帖子中获取灵感。

    dat <- read.csv('https://raw.githubusercontent.com/rnorouzian/e/master/nc.csv')
    
    m <- tryCatch({
              withCallingHandlers({
                error <- FALSE
                list(model = lmer(math ~ ses*sector + (ses | sch.id), data = dat),
                     error = error)
              },warning = function(w) {
                  if(grepl('failed to converge', w$message)) error <<- TRUE
              }
              )})
    
    
    m$model
    #Linear mixed model fit by REML ['lmerMod']
    #Formula: math ~ ses * sector + (ses | sch.id)
    #   Data: dat
    #REML criterion at convergence: 37509.07
    #Random effects:
    # Groups   Name        Std.Dev. Corr
    # sch.id   (Intercept) 1.9053       
    #          ses         0.8577   0.46
    # Residual             3.1930       
    #Number of obs: 7185, groups:  sch.id, 160
    #Fixed Effects:
    #(Intercept)          ses       sector   ses:sector  
    #     11.902        2.399        1.677       -1.322  
    #convergence code 0; 0 optimizer warnings; 1 lme4 warnings 
    
    m$error
    #[1] TRUE
    

    输出m 是一个包含modelerror 元素的列表。


    如果我们需要在模型创建后测试警告,我们可以使用:

    is_warning_generated <- function(m) {
      df <- summary(m)
      !is.null(df$optinfo$conv$lme4$messages) && 
               grepl('failed to converge', df$optinfo$conv$lme4$messages)
    }
    
    m <- lmer(math ~ ses*sector + (ses | sch.id), data = dat)
    is_warning_generated(m)
    #[1] TRUE
    

    【讨论】:

    • 谢谢,罗纳克!那么对于我们的逻辑测试,我们是否可以编写一个函数,其中该函数获取一个类似m 的模型,如果模型有警告则输出TRUE,否则输出FALSE
    • 您的解决方案需要在列表中重新键入整个模型!就像我说的那样,我只需要一个函数,在我的问题中接受像 m 这样的模型对象,并检查是否存在该警告(返回 TRUE)或其他 FALSE
    • 查看更新的答案以将模型 m 传递给函数 is_warning_generated
    【解决方案2】:

    我们可以从purrr 使用safely。它还将error 作为list 元素返回并捕获错误。如果没有错误,则为NULL

    library(purrr)
    safelmer <- safely(lmer, otherwise = NA)
    out <- safelmer(math ~ ses*sector + (ses | sch.id), data = dat)
    

    【讨论】:

      【解决方案3】:

      我只想说@RonakShah 的is_warning_generated 可以稍微紧凑一些:

      function(m) { 
          w <- m@optinfo$conv$lme4$messages
          !is.null(w) && grepl('failed to converge', w) 
      }
      

      【讨论】:

        【解决方案4】:

        我将 Ronak 的解决方案应用于我自己的模拟数据,发现了一个问题。 该消息可能是多个条目的向量,也导致grepl() 具有多个条目。但是,&amp;&amp; 运算符仅将字符串与第一个条目进行比较,因此不会观察到进一步出现的“收敛失败”。为了避免这种行为,我将&amp;&amp; 更改为&amp;

        如果根本没有消息,就会出现问题。在这种情况下,!is.null() 部分变为正确的FALSE(即没有生成警告),但grepl() 部分变为logical(0),函数值变为FALSE &amp; logical(0),即logical(0)。事实上,它适用于FALSE &amp;&amp; logical(0),即FALSE(正确)。

        对我有用的解决方案是 if(is.null(mess)) FALSE else grepl('failed to converge', mess)

        在收敛失败的情况下,在放置警告的条目处提供一个带有 TRUE 的向量。例如,可以通过构建大于 0 或 TRUE 的数字(或布尔值)和来评估该向量。

        【讨论】:

        • 感谢 Dylan 的编辑!
        【解决方案5】:
        > sm=summary(model)
        > sm$optinfo$conv$lme4$messages
        [1] "Model failed to converge with max|grad| = 0.0120186 (tol = 0.002, component 1)"
        >
        

        【讨论】:

        • 你能澄清一下这增加了现有答案吗?
        • 我认为前面的答案很复杂,没有明显的原因。为什么要使用 purrr、grep、编写特殊函数以及所有这些爵士乐?只需查看模型对象中的字符串即可。我阅读了现有的答案,但至少在开始时无法弄清楚那里发生了什么。我认为一个简单的答案更好。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-16
        • 1970-01-01
        • 1970-01-01
        • 2016-08-13
        相关资源
        最近更新 更多