从 R 中的 lme4 包捕获收敛消息
capturing convergence message from lme4 package in R
我想知道是否有一种方法可以编写逻辑测试 (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)
我们可以使用 tryCatch
,使用 withCallingHandlers
从 this post 获得灵感。
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
是一个包含 model
和 error
元素的列表。
如果我们需要在创建模型后测试警告,我们可以使用:
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
我们可以使用 purrr
中的 safely
。它还将 return error
作为 list
元素并捕获错误。如果没有报错,就是NULL
library(purrr)
safelmer <- safely(lmer, otherwise = NA)
out <- safelmer(math ~ ses*sector + (ses | sch.id), data = dat)
我将Ronak的解决方案应用到我自己的模拟数据中,发现了一个问题。
该消息可能是多个条目的向量,导致 grepl()
也有多个条目。但是,&&
运算符仅将字符串与第一个条目进行比较,这样 'failed to converge' 的进一步出现就不会被观察到。为了避免这种行为,我将 &&
更改为 &
。
现在,如果根本没有消息,就会出现问题。在这种情况下,!is.null()
部分变为正确的 FALSE
(即没有生成警告),但 grepl()
部分变为 logical(0)
,函数值变为 FALSE & logical(0)
,这是 logical(0)
。事实上,它适用于 FALSE && logical(0)
,即 FALSE
(正确)。
一个对我有用的解决方案是
if(is.null(mess)) FALSE else grepl('failed to converge', mess)
在收敛失败的情况下,在放置警告的条目处提供一个值为 TRUE 的向量。例如,可以通过构建大于 0 或 TRUE 的数字(或布尔)总和来评估该向量。
我只想说@RonakShah 的 is_warning_generated
可以稍微紧凑一些:
function(m) {
w <- m@optinfo$conv$lme4$messages
!is.null(w) && grepl('failed to converge', w)
}
> sm=summary(model)
> sm$optinfo$conv$lme4$messages
[1] "Model failed to converge with max|grad| = 0.0120186 (tol = 0.002, component 1)"
>
我想知道是否有一种方法可以编写逻辑测试 (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)
我们可以使用 tryCatch
,使用 withCallingHandlers
从 this post 获得灵感。
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
是一个包含 model
和 error
元素的列表。
如果我们需要在创建模型后测试警告,我们可以使用:
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
我们可以使用 purrr
中的 safely
。它还将 return error
作为 list
元素并捕获错误。如果没有报错,就是NULL
library(purrr)
safelmer <- safely(lmer, otherwise = NA)
out <- safelmer(math ~ ses*sector + (ses | sch.id), data = dat)
我将Ronak的解决方案应用到我自己的模拟数据中,发现了一个问题。
该消息可能是多个条目的向量,导致 grepl()
也有多个条目。但是,&&
运算符仅将字符串与第一个条目进行比较,这样 'failed to converge' 的进一步出现就不会被观察到。为了避免这种行为,我将 &&
更改为 &
。
现在,如果根本没有消息,就会出现问题。在这种情况下,!is.null()
部分变为正确的 FALSE
(即没有生成警告),但 grepl()
部分变为 logical(0)
,函数值变为 FALSE & logical(0)
,这是 logical(0)
。事实上,它适用于 FALSE && logical(0)
,即 FALSE
(正确)。
一个对我有用的解决方案是
if(is.null(mess)) FALSE else grepl('failed to converge', mess)
在收敛失败的情况下,在放置警告的条目处提供一个值为 TRUE 的向量。例如,可以通过构建大于 0 或 TRUE 的数字(或布尔)总和来评估该向量。
我只想说@RonakShah 的 is_warning_generated
可以稍微紧凑一些:
function(m) {
w <- m@optinfo$conv$lme4$messages
!is.null(w) && grepl('failed to converge', w)
}
> sm=summary(model)
> sm$optinfo$conv$lme4$messages
[1] "Model failed to converge with max|grad| = 0.0120186 (tol = 0.002, component 1)"
>