2011-02-09 14 views
25

मैं बड़ी संख्या में आइटम पर एक जटिल फ़ंक्शन चलाने के लिए lapply का उपयोग कर रहा हूं, और मैं प्रत्येक आइटम (यदि कोई हो) से उत्पादन को किसी भी चेतावनी/त्रुटियों के साथ सहेजना चाहता हूं ताकि मैं बता सकूं कि मैं कौन सा बता सकता हूं आइटम जो चेतावनी/त्रुटि उत्पन्न किया।मैं फ़ंक्शन से आउटपुट के रूप में चेतावनियां और त्रुटियों को कैसे सहेजूं?

मुझे withCallingHandlers का उपयोग करके चेतावनियों को पकड़ने का एक तरीका मिला (यहां वर्णित: https://stackoverflow.com/questions/4947528)। हालांकि, मुझे त्रुटियों को भी पकड़ने की जरूरत है। मैं इसे tryCatch (नीचे दिए गए कोड में) में लपेटकर कर सकता हूं, लेकिन क्या ऐसा करने का एक बेहतर तरीका है? इस समारोह के

catchToList <- function(expr) { 
    val <- NULL 
    myWarnings <- NULL 
    wHandler <- function(w) { 
    myWarnings <<- c(myWarnings, w$message) 
    invokeRestart("muffleWarning") 
    } 
    myError <- NULL 
    eHandler <- function(e) { 
    myError <<- e$message 
    NULL 
    } 
    val <- tryCatch(withCallingHandlers(expr, warning = wHandler), error = eHandler) 
    list(value = val, warnings = myWarnings, error=myError) 
} 

नमूना उत्पादन होता है:

> catchToList({warning("warning 1");warning("warning 2");1}) 
$value 
[1] 1 

$warnings 
[1] "warning 1" "warning 2" 

$error 
NULL 

> catchToList({warning("my warning");stop("my error")}) 
$value 
NULL 

$warnings 
[1] "my warning" 

$error 
[1] "my error" 

वहाँ कई सवाल यहाँ पर कर रहे हैं ताकि पर चर्चा tryCatch और त्रुटि हैंडलिंग, लेकिन कोई भी है कि मुझे लगता है कि पता इस विशेष मुद्दे पाया। सबसे प्रासंगिक लोगों के लिए How can I check whether a function call results in a warning?, warnings() does not work within a function? How can one work around this?, और How to tell lapply to ignore an error and process the next thing in the list? देखें।

उत्तर

34

हो सकता है कि यह आपके समाधान के रूप में ही है, लेकिन मैं एक factory लिखा कार्यों कि उनके मूल्यों, त्रुटियों और चेतावनियों पर कब्जा में सादे पुराने कार्यों कन्वर्ट करने के लिए, तो मैं कर सकते हैं

test <- function(i) 
    switch(i, "1"=stop("oops"), "2"={ warning("hmm"); i }, i) 
res <- lapply(1:3, factory(test)) 
के प्रत्येक तत्व के साथ

परिणाम में मान, त्रुटि, और/या चेतावनियां होती हैं। यह उपयोगकर्ता कार्यों, सिस्टम फ़ंक्शंस, या अज्ञात फ़ंक्शंस (factory(function(i) ...)) के साथ काम करेगा। यहाँ कारखाने

factory <- function(fun) 
    function(...) { 
     warn <- err <- NULL 
     res <- withCallingHandlers(
      tryCatch(fun(...), error=function(e) { 
       err <<- conditionMessage(e) 
       NULL 
      }), warning=function(w) { 
       warn <<- append(warn, conditionMessage(w)) 
       invokeRestart("muffleWarning") 
      }) 
     list(res, warn=warn, err=err) 
    } 

और परिणाम सूची

.has <- function(x, what) 
    !sapply(lapply(x, "[[", what), is.null) 
hasWarning <- function(x) .has(x, "warn") 
hasError <- function(x) .has(x, "err") 
isClean <- function(x) !(hasError(x) | hasWarning(x)) 
value <- function(x) sapply(x, "[[", 1) 
cleanv <- function(x) sapply(x[isClean(x)], "[[", 1) 
+3

हाँ, वही विचार, लेकिन बहुत अच्छा! क्या आपने इसे पैकेज में लपेटने पर विचार किया है? अन्य प्रश्नों से मैंने यहां कुछ अन्य लोगों को यह भी उपयोगी पाया होगा। – Aaron

+1

मेरे पास एक ऐसा फ़ंक्शन है जो आउटपुट में अपना कॉल संग्रहीत करता है। 'फैक्ट्री' का आह्वान करने के बाद यह कॉल बदल गया है, उदा। 'मजेदार (सूत्र = ..1, डेटा = ..2, विधि =" अनुवांशिक ", अनुपात = ..4, print.level = 0) ', जहां' सूत्र 'मेरा मूल इनपुट सूत्र होना चाहिए, लेकिन ओवरराइट हो जाता है । कोई सुझाव? –

+0

@ रोमन लूस्ट्रिक: मुझे लगता है कि ऐसा इसलिए है क्योंकि यह वास्तव में एक नया फ़ंक्शन 'मजेदार' बना रहा है और उसे सीधे कॉल करने के बजाय '...' के साथ कॉल कर रहा है। मुझे आश्चर्य है कि मेरा 'कैच टॉलीस्ट' फ़ंक्शन काम करता है, या यदि 'फैक्ट्री' को संशोधित किया जा सकता है, तो शायद 'do.call' का उपयोग कर। इसे पुन: उत्पन्न कैसे किया जा सकता है? – Aaron

12

evaluate package प्रयास करें से निपटने के लिए कुछ सहायकों है।

library(evaluate) 
test <- function(i) 
    switch(i, "1"=stop("oops"), "2"={ warning("hmm"); i }, i) 

t1 <- evaluate("test(1)") 
t2 <- evaluate("test(2)") 
t3 <- evaluate("test(3)") 

यह वर्तमान में अभिव्यक्ति का मूल्यांकन हालांकि का एक अच्छा तरीका का अभाव है - यह मुख्य रूप से है क्योंकि यह कंसोल पर वास्तव में क्या आर उत्पादन के दिए गए पाठ इनपुट के पुनरुत्पादन की ओर निशाना बनाया गया है।

replay(t1) 
replay(t2) 
replay(t3) 

यह भी संदेश, कंसोल के लिए उत्पादन कैप्चर करता है, और यह सुनिश्चित करता है कि सब कुछ सही ढंग से जिस क्रम में यह हुआ में interleaved है।

5

मैंने मार्टिन आत्माओं (https://stackoverflow.com/a/4952908/2161065) विलय कर लिया है और आर-सहायता मेलिंग सूची में से एक है जिसे आप demo(error.catching) के साथ प्राप्त करते हैं।

मुख्य विचार दोनों को चेतावनी/त्रुटि संदेश के साथ-साथ इस समस्या को ट्रिगर करने का आदेश रखना है।

myTryCatch <- function(expr) { 
    warn <- err <- NULL 
    value <- withCallingHandlers(
    tryCatch(expr, error=function(e) { 
     err <<- e 
     NULL 
    }), warning=function(w) { 
     warn <<- w 
     invokeRestart("muffleWarning") 
    }) 
    list(value=value, warning=warn, error=err) 
} 

उदाहरण:

myTryCatch(log(1)) 
myTryCatch(log(-1)) 
myTryCatch(log("a")) 

आउटपुट:

> myTryCatch (लॉग (1))

$ मूल्य [1] 0 $ चेतावनी शून्य $ त्रुटि नल

> myTryCatch (लॉग (-1))

$ मूल्य [1] NaN $ चेतावनी $ त्रुटि शून्य

> myTryCatch (लॉग ("एक"))

$ Null मूल्य $ चेतावनी शून्य $ त्रुटि

+0

यह अच्छा है लेकिन संदेश या प्रिंट नहीं पकड़ता है। मैं केवल एक ही समारोह के साथ अच्छा होगा जो सभी 4 मुख्य आउटपुट प्रकारों को पकड़ा। मैं मुख्य कहता हूं, क्योंकि कुछ अन्य जैसे भूखंड, क्लिपबोर्ड पर लिखना और फ़ाइल में लिखना है। कुछ मामलों में, कोई भी इन्हें पकड़ने के लिए देखता है। – Deleet

2

मेरा उत्तर (और मार्टिन उत्कृष्ट कोड में संशोधन) के प्रयोजन के लिए इतना है कि कारखाने में एड समारोह डेटा संरचना की उम्मीद लौटाता है यदि सब कुछ ठीक है। अगर एक चेतावनी का अनुभव होता है, तो यह factory-warning विशेषता के तहत परिणाम से जुड़ा हुआ है। डेटाटेबल के setattr फ़ंक्शन का उपयोग उस पैकेज के साथ संगतता की अनुमति देने के लिए किया जाता है। यदि कोई त्रुटि अनुभव की जाती है, तो परिणाम वर्ण तत्व "फ़ैक्टरी फ़ंक्शन में एक त्रुटि हुई" और factory-error विशेषता में त्रुटि संदेश होगा।

#' Catch errors and warnings and store them for subsequent evaluation 
#' 
#' Factory modified from a version written by Martin Morgan on Stack Overflow (see below). 
#' Factory generates a function which is appropriately wrapped by error handlers. 
#' If there are no errors and no warnings, the result is provided. 
#' If there are warnings but no errors, the result is provided with a warn attribute set. 
#' If there are errors, the result retutrns is a list with the elements of warn and err. 
#' This is a nice way to recover from a problems that may have occurred during loop evaluation or during cluster usage. 
#' Check the references for additional related functions. 
#' I have not included the other factory functions included in the original Stack Overflow answer because they did not play well with the return item as an S4 object. 
#' @export 
#' @param fun The function to be turned into a factory 
#' @return The result of the function given to turn into a factory. If this function was in error "An error as occurred" as a character element. factory-error and factory-warning attributes may also be set as appropriate. 
#' @references 
#' \url{http://stackoverflow.com/questions/4948361/how-do-i-save-warnings-and-errors-as-output-from-a-function} 
#' @author Martin Morgan; Modified by Russell S. Pierce 
#' @examples 
#' f.log <- factory(log) 
#' f.log("a") 
#' f.as.numeric <- factory(as.numeric) 
#' f.as.numeric(c("a","b",1)) 
factory <- function (fun) { 
    errorOccurred <- FALSE 
    library(data.table) 
    function(...) { 
    warn <- err <- NULL 
    res <- withCallingHandlers(tryCatch(fun(...), error = function(e) { 
     err <<- conditionMessage(e) 
     errorOccurred <<- TRUE 
     NULL 
    }), warning = function(w) { 
     warn <<- append(warn, conditionMessage(w)) 
     invokeRestart("muffleWarning") 
    }) 
    if (errorOccurred) { 
     res <- "An error occurred in the factory function" 
    } 

    if (is.character(warn)) { 
     data.table::setattr(res,"factory-warning",warn) 
    } else { 
     data.table::setattr(res,"factory-warning",NULL) 
    } 

    if (is.character(err)) { 
     data.table::setattr(res,"factory-error",err) 
    } else { 
     data.table::setattr(res, "factory-error", NULL) 
    } 
    return(res) 
    } 
} 

क्योंकि हम एक अतिरिक्त सूची में परिणाम रैप नहीं हम मान्यताओं कि उनकी एक्सेसर कार्यों में से कुछ के लिए अनुमति की तरह कर सकते हैं नहीं है, लेकिन हम सरल जांच लिख सकते हैं और कैसे मामलों को संभालने के लिए तय जैसा कि हमारे विशेष परिणामस्वरूप डेटा संरचना के लिए उपयुक्त है।

.has <- function(x, what) { 
    !is.null(attr(x,what)) 
} 
hasWarning <- function(x) .has(x, "factory-warning") 
hasError <- function(x) .has(x, "factory-error") 
isClean <- function(x) !(hasError(x) | hasWarning(x)) 
संबंधित मुद्दे