有没有办法在R中使用tryCatch(或类似)作为循环,或者在warning参数中操纵expr?

有没有办法在R中使用tryCatch(或类似)作为循环,或者在warning参数中操纵expr?,r,exception,try-catch,warnings,R,Exception,Try Catch,Warnings,我有一个回归模型(lm或glm或lmer…),我有fitmodel也许您可以在处理条件下再次分配x tryCatch( warning = function(cnd) { x <- suppressWarnings(as.numeric(y)) print(x)}, expr = {x <- as.numeric(y)} ) #> [1] NA tryCatch( 警告=功能(cnd){ x不要把作业放在tryCatch调用中,把它放在外部。例如 y

我有一个回归模型(
lm
glm
lmer
…),我有
fitmodel也许您可以在处理条件下再次分配
x

tryCatch(
  warning = function(cnd) {
    x <- suppressWarnings(as.numeric(y))
    print(x)},
  expr = {x <- as.numeric(y)}
)
#> [1] NA
tryCatch(
警告=功能(cnd){

x不要把作业放在
tryCatch
调用中,把它放在外部。例如

y <- "a"
x <- tryCatch(expr = {as.numeric(y)},
    warning = function(w) {y})
y <- "a"
res <- evaluate::evaluate(quote(x <- as.numeric(y)))
for (i in seq_along(res)) {
    if (inherits(res[[i]], "warning") && 
        conditionMessage(res[[i]]) == gettext("NAs introduced by coercion",
                                              domain = "R"))
        x <- y
}
编辑以添加:

要允许评估在处理警告之前继续完成,您不能使用
tryCatch
evaluate
包有一个函数(也称为
evaluate
)可以完成此操作。例如

y <- "a"
x <- tryCatch(expr = {as.numeric(y)},
    warning = function(w) {y})
y <- "a"
res <- evaluate::evaluate(quote(x <- as.numeric(y)))
for (i in seq_along(res)) {
    if (inherits(res[[i]], "warning") && 
        conditionMessage(res[[i]]) == gettext("NAs introduced by coercion",
                                              domain = "R"))
        x <- y
}

<代码> y> p>你在寻找类似的东西吗?如果它是用<代码> y运行的,看起来你在寻找一个函数包,它既能捕获函数调用的返回值又能捕捉到副作用。我想Purr::悄悄地< /代码>是这类任务的完美候选。
quietly <- purrr::quietly

foo <- function(x) {
  if (x < 3)
    warning(x, " is less than 3")
  if (x < 4)
    warning(x, " is less than 4")
  x
}

update_foo <- function(x, y) {
  x <- x + y
  foo(x)
}

keep_doing <- function(inputs) {
  out <- quietly(foo)(inputs)
  repeat {
    if (length(out$warnings) < 1L)
      return(out$result)
    
    cat(paste0(out$warnings, collapse = ", "), "\n")
    # This is for you to see the process. You can delete this line.
    
    if (grepl("less than 3", out$warnings[[1L]])) {
      out <- quietly(update_foo)(out$result, 1.5)
    } else if (grepl("less than 4", out$warnings[[1L]])) {
      out <- quietly(update_foo)(out$result, 1)
    }
  }
}

从根本上说,问题在于处理程序是在赋值发生之前调用的。即使不是这样,处理程序运行在与
tryCatch
表达式不同的作用域中,因此处理程序无法访问另一个作用域中的名称

我们需要将处理与值转换分开

对于错误(但不是警告),base R提供函数
try
,该函数包装
tryCatch
,以实现此效果。但是,不鼓励使用
try
,因为它的返回类型是.1,如上所述,'purr'提供正确键入(例如
安全地
)以实现类似效果

但是,我们也可以建立自己的,这可能更适合这种情况:

with_warning = function (expr) {
    self = environment()
    warning = NULL

    result = withCallingHandlers(expr, warning = function (w) {
        self$warning = w
        tryInvokeRestart('muffleWarning')
    })
    list(result = result, warning = warning)
}
这为我们提供了一个包装器,用于区分结果值和警告。我们现在可以使用它来实现您的需求:

fitmodel = with(with_warning(lm(inputs)), {
    if (! is.null(warning)) {
        if (conditionMessage(warning) satisfies something) {
            update(result, something suitable to do on the model)
        } else {
            update(result, something2 suitable to do on the model)
        }
    } else {
        result
    }
})


1这意味着
try
的返回类型不区分类型为
try error
的错误值和非错误值。这是一种可能发生的实际情况,例如,当嵌套多个
try
调用时。

我将赋值放在
tryCatch
中,因为我想稍后在内部使用
warning
参数,我询问是否有可能。我认为除了像我的回答中那样复制计算之外,使用基本R代码是不可能的。R代码可以访问警告消息或表达式值,但不能同时访问两者。但是,
evaluate::evaluate()
函数可以做到这一点;我将添加一个示例。
with_warning = function (expr) {
    self = environment()
    warning = NULL

    result = withCallingHandlers(expr, warning = function (w) {
        self$warning = w
        tryInvokeRestart('muffleWarning')
    })
    list(result = result, warning = warning)
}
fitmodel = with(with_warning(lm(inputs)), {
    if (! is.null(warning)) {
        if (conditionMessage(warning) satisfies something) {
            update(result, something suitable to do on the model)
        } else {
            update(result, something2 suitable to do on the model)
        }
    } else {
        result
    }
})