如何检查函数调用是否导致警告?

在 R 中,如何确定函数调用是否会导致警告?

也就是说,在调用该函数之后,我想知道该调用的实例是否产生了警告。

37538 次浏览

这里有一个例子:

testit <- function() warning("testit") # function that generates warning.


assign("last.warning", NULL, envir = baseenv()) # clear the previous warning


testit() # run it


if(length(warnings())>0){ # or !is.null(warnings())
print("something happened")
}

也许这是间接的,但我不知道更直接的方式。

如果要使用 try构造,可以设置警告选项。参见 ?options。更好的方法是使用 tryCatch():

x <- function(i){
if (i < 10) warning("A warning")
i
}


tt <- tryCatch(x(5),error=function(e) e, warning=function(w) w)


tt2 <- tryCatch(x(15),error=function(e) e, warning=function(w) w)


tt
## <simpleWarning in x(5): A warning>


tt2
## [1] 15


if(is(tt,"warning")) print("KOOKOO")
## [1] "KOOKOO"


if(is(tt2,"warning")) print("KOOKOO")

为了得到结果和警告:

tryCatch(x(5),warning=function(w) return(list(x(5),w)))


## [[1]]
## [1] 5
##
## [[2]]
## <simpleWarning in x(5): A warning>

使用 try

op <- options(warn=2)


tt <- try(x())
ifelse(is(tt,"try-error"),"There was a warning or an error","OK")
options(op)

在 R-help 邮件列表(见 http://tolstoy.newcastle.edu.au/R/help/04/06/0217.html)上,Luke Tierney 写道:

”如果要编写一个函数来计算一个值并收集所有 警告你可以这样做:

withWarnings <- function(expr) {
myWarnings <- NULL
wHandler <- function(w) {
myWarnings <<- c(myWarnings, list(w))
invokeRestart("muffleWarning")
}
val <- withCallingHandlers(expr, warning = wHandler)
list(value = val, warnings = myWarnings)
}

二零一九年最新情况

您可以从 purrr 包中“悄悄地”使用它,它返回输出、结果、警告和错误的列表。然后可以按名称提取每个元素。例如,如果您有一个列表,您想要映射一个函数,并找到返回警告的元素

library(purrr)
library(lubridate)


datelist <- list(a = "12/12/2002", b = "12-12-2003", c = "24-03-2005")


# get all the everything
quiet_list <- map(datelist, quietly(mdy))


# find the elements which produced warnings
quiet_list %>% map("warnings") %>% keep(~ !is.null(.))


# or
quiet_list %>% keep(~ length(.$warnings) != 0)

对于这个示例来说,它非常简单,但是对于很长的数据框架列表,其中的 NA 可能很难被发现,这是非常有用的。

对于给定操作是否导致警告(或错误)的简单 TRUE/FALSE返回,您可以在首次设置 options(warn = 2)以便将警告转换为错误之后,使用来自 berryFunctions 包裹is.error函数。

例如:

options(warn = 2)
berryFunctions::is.error(as.numeric("x")) # TRUE
berryFunctions::is.error(as.numeric("3")) # FALSE

如果希望将选项更改限制为使用此函数,只需按照以下方式创建一个新函数即可。

is.warningorerror <- function(x) {
op <- options()
on.exit(options(op))
options(warn = 2)
berryFunctions::is.error(x)
}


is.warningorerror(as.numeric("x")) # TRUE
options("warn") # still 0 (default)

我个人使用旧的好 sink重定向到一个文本连接:

# create a new text connection directed into a variable called 'messages'
con <- textConnection("messages","w")
# sink all messages (i.e. warnings and errors) into that connection
sink(con,type = "message")
# a sample warning-generating function
test.fun <- function() {
warning("Your warning.")
return("Regular output.")
}
output <- test.fun()
# close the sink
sink(type="message")
# close the connection
close(con)
# if the word 'Warning' appears in messages than there has been a warning
warns <- paste(messages,collapse=" ")
if(grepl("Warning",warns)) {
print(warns)
}
# [1] "Warning message: In test.fun() : Your warning."
print(output)
# [1] "Regular output."

可能比其他建议的解决方案更直接、更干净。