R에서 tryCatch (또는 유사)를 루프로 사용하거나 경고 인수에서 expr을 조작하는 방법이 있습니까?
회귀 모델 ( lm
또는 glm
또는 lmer
...)이 있고 루프 (공식 및 데이터) 내 fitmodel <- lm(inputs)
에서 inputs
변경 사항을 수행 합니다. 그런 다음 모델 함수가 경고를 생성하지 않으면 유지 fitmodel
하고 싶지만 경고가 표시 update
되면 모델에 경고 가 인쇄 되지 않기를 원 하므로 fitmodel <- lm(inputs)
내부에서 수행 합니다 tryCatch
. 이 경고를 생성한다면, 내부 warning = function(w){f(fitmodel)}
, f(fitmodel)
같은 것
fitmodel <- update(fitmodel, something suitable to do on the model)
사실,이 할당은 if-else
경고에 따라 내부를 if(w$message satisfies something)
조정 하는 방식으로 구조 내부에 있을 것 입니다.suitable to do on the model
update
문제는 내가 얻는 것 Error in ... object 'fitmodel' not found
입니다. withCallingHandlers
와 함께 사용 invokeRestarts
하면 경고없이 모델 계산이 완료 update
됩니다. fitmodel <- lm(inputs)
안쪽 에 다시 추가 something suitable to do on the model
하면 경고가 인쇄됩니다. 이제 시도해 볼 수 있다고 생각 suppresswarnings(fitmodel <- lm(inputs))
하지만 선 fitmodel <- lm(inputs)
을 2 배 더하여 모든 계산 (내부 expr
및 내부 warning
) 을 2 배로 만들어야 하기 때문에 우아한 해결책이 아니라고 생각합니다 .
요약하면 내가 원하지만 실패한 것은 다음과 같습니다.
tryCatch(expr = {fitmodel <- lm(inputs)},
warning = function(w) {if (w$message satisfies something) {
fitmodel <- update(fitmodel, something suitable to do on the model)
} else if (w$message satisfies something2){
fitmodel <- update(fitmodel, something2 suitable to do on the model)
}
}
)
어떡해?
질문의 루프 부분은 다음과 같이 생각했기 때문입니다 (아마도 다른 질문이지만 잠시 동안 여기에 남겨 둡니다). update
나는 또 다른 경고 를받은 후에 발생할 수 있으므로 다음과 같이 할 수 있습니다 while(get a warning on update){update}
. 어떤 의미에서이 update
내부 warning
는 expr
. 이와 같은 것이 가능합니까?
대단히 감사합니다!
최소한의 예가있는 일반적인 질문 버전 :
하자 내가이 말을 tryCatch(expr = {result <- operations}, warning = function(w){f(...)}
하고 난에 경고받을 경우 expr
(사실상에서 생산 operations
내가 뭔가를하고 싶은) result
내가 할 것, 그래서를 warning = function(w){f(result)}
,하지만 내가 얻을 Error in ... object 'result' not found
.
최소한의 예 :
y <- "a"
tryCatch(expr = {x <- as.numeric(y)},
warning = function(w) {print(x)})
Error in ... object 'x' not found
성공하지 않고 withCallingHandlers
대신 사용해 보았습니다. 사용 tryCatch
하기도 invokeRestart
했지만 경고를 받았을 때하고 싶은 것이 아니라 표현 부분을합니다.
당신이 나를 도울 수?
감사합니다!
답변
근본적으로 문제는 할당이 발생하기 전에 핸들러가 호출된다는 것입니다. 그렇지 않은 경우에도 핸들러는 tryCatch
표현식과 다른 범위에서 실행 되므로 핸들러는 다른 범위의 이름에 액세스 할 수 없습니다.
값 변환과 처리를 분리해야합니다.
오류 (경고 아님)의 경우 base R 은이 효과를 달성하기 위해 try
래핑 하는 함수를 제공합니다 tryCatch
. 그러나 try
반환 유형이 불건전 하기 때문에 사용 하지 않는 것이 좋습니다 . 1 ekoam의 답변에서 언급했듯이 'purrr'은 유사한 효과를 얻기 위해 건전한 형식의 기능적 래퍼 (예 :)를 제공 safely
합니다.
그러나 우리는 우리 자신을 만들 수도 있습니다.
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
호출을 중첩 할 때 발생할 수있는 실제 상황입니다 .
함수 호출의 반환 값과 부작용을 모두 캡처하는 기능적 래퍼를 찾고있는 것 같습니다. 나는 purrr::quietly
이런 종류의 작업에 대한 완벽한 후보 라고 생각 합니다. 이와 같은 것을 고려하십시오
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)
}
}
}
산출
> keep_doing(1)
1 is less than 3, 1 is less than 4
2.5 is less than 3, 2.5 is less than 4
[1] 4
> keep_doing(3)
3 is less than 4
[1] 4
다음과 같은 것을 찾고 있습니까? 로 실행 y <- "123"
하면 "OK"
메시지가 인쇄됩니다.
y <- "a"
#y <- "123"
x <- tryCatch(as.numeric(y),
warning = function(w) w
)
if(inherits(x, "warning")){
message(x$message)
} else{
message(paste("OK:", x))
}
함수로 다시 작성된 위의 코드를 사용하여 여러 인수 값을 테스트하는 것이 더 쉽습니다.
testWarning <- function(x){
out <- tryCatch(as.numeric(x),
warning = function(w) w
)
if(inherits(out, "warning")){
message(out$message)
} else{
message(paste("OK:", out))
}
invisible(out)
}
testWarning("a")
#NAs introduced by coercion
testWarning("123")
#OK: 123
x
취급 조건에서 다시 할당 할 수 있을까요?
tryCatch(
warning = function(cnd) {
x <- suppressWarnings(as.numeric(y))
print(x)},
expr = {x <- as.numeric(y)}
)
#> [1] NA
아마도 가장 우아한 대답은 아니지만 장난감 예제를 해결합니다.
과제를 tryCatch
부르지 말고 밖에 두십시오. 예를 들면
y <- "a"
x <- tryCatch(expr = {as.numeric(y)},
warning = function(w) {y})
이 양수인은 y
할 수 x
있지만 경고 몸에 아무것도 넣을 수 있고, 결과에 할당됩니다 x
.
expr
값에 대한 액세스를 원 하지만 경고가 생성 된 시점에 할당되지 않았기 때문에 "내가 원하는"예제는 더 복잡 합니다. 나는 당신이 그것을 다시 계산해야 할 것이라고 생각합니다.
fitmodel <- tryCatch(expr = {lm(inputs)},
warning = function(w) {if (w$message satisfies something) { update(lm(inputs), something suitable to do on the model) } else if (w$message satisfies something2){
update(lm(inputs), something2 suitable to do on the model)
}
}
)
추가하기 위해 편집 :
경고를 처리하기 전에 평가가 완료되도록하려면을 사용할 수 없습니다 tryCatch
. evaluate
패키지 (또한라는 함수가 evaluate
이 작업을 수행 할 수 있습니다). 예를 들면
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
}
몇 가지 참고 사항 : res
목록에는 메시지, 경고, 오류 등을 포함하여 다양한 항목이 포함됩니다. 내 코드는 경고 만 확인합니다. 예전 conditionMessage
에 경고 메시지를 추출했지만 현지 언어 gettext
로 번역되므로 비교를 위해 영어 버전의 메시지를 번역하는 데 사용해야 합니다.