क्या R में लूप के रूप में tryCatch (या समान) का उपयोग करने का तरीका है, या चेतावनी के तर्क में एक्सपेरर का हेरफेर करने का कोई तरीका है?

Nov 27 2020

मैं एक प्रतिगमन मॉडल है ( 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)), लेकिन फिर भी मुझे लगता है कि यह एक सुरुचिपूर्ण समाधान नहीं है, क्योंकि मुझे 2 बार लाइन को जोड़ना है fitmodel <- lm(inputs), जिससे 2 बार सभी गणना (अंदर exprऔर अंदर warning) हो जाती है।

संक्षेप में, जो मैं चाहूंगा लेकिन वह विफल है:

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लेकिन यह अभिव्यक्ति का हिस्सा है, न कि मैं क्या करना चाहता हूं जब मुझे चेतावनी मिलती है।

क्या तुम मेरी मदद कर सकते हो?

धन्यवाद!

जवाब

2 KonradRudolph Nov 28 2020 at 14:24

समस्या, मौलिक रूप से यह है कि असाइनमेंट होने से पहले हैंडलर को बुलाया जाता है। और यहां तक ​​कि अगर ऐसा नहीं था, तो हैंडलर tryCatchअभिव्यक्ति की तुलना में एक अलग दायरे में चलता है , इसलिए हैंडलर अन्य दायरे में नामों तक नहीं पहुंच सकता है।

हमें मूल्य परिवर्तन से हैंडलिंग को अलग करने की आवश्यकता है।

त्रुटियों के लिए (लेकिन चेतावनी नहीं), बेस आर फ़ंक्शन प्रदान करता है try, जो tryCatchइस प्रभाव को प्राप्त करने के लिए लपेटता है। हालांकि, उपयोग tryकरना हतोत्साहित किया जाता है, क्योंकि इसकी वापसी का प्रकार निराधार है । 1 जैसा कि एकोम द्वारा उत्तर में बताया गया है , 'पुअर्र' एक समान प्रभाव प्राप्त करने के लिए ध्वनि टाइप किए गए कार्यात्मक आवरण (जैसे 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कॉल घोंसले का शिकार हो ।

2 ekoam Nov 27 2020 at 11:37

ऐसा लगता है कि आप एक कार्यात्मक आवरण की तलाश कर रहे हैं जो किसी फ़ंक्शन कॉल के दिए गए मान और साइड इफेक्ट दोनों को कैप्चर करता है। मुझे लगता 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
1 RuiBarradas Nov 27 2020 at 10:38

आप निम्नलिखित की तरह कुछ के लिए देख रहे हैं? यदि इसके साथ चलाया जाता है 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
JoaoPedroMacalos Nov 27 2020 at 10:04

शायद आप xफिर से निपटने की स्थिति में असाइन कर सकते हैं ?

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

शायद सबसे सुरुचिपूर्ण जवाब नहीं है, लेकिन अपने खिलौने के उदाहरण को हल करता है।

user2554330 Nov 27 2020 at 10:05

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)

                                }
         }
)

जोड़ने के लिए संपादित:

चेतावनी को संसाधित करने से पहले मूल्यांकन को पूरा करने के लिए अनुमति देने के लिए, आप उपयोग नहीं कर सकते tryCatchevaluateपैकेज एक समारोह (भी बुलाया है 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तुलना के लिए संदेश के अंग्रेजी संस्करण का अनुवाद करना चाहिए ।