วิธีเขียน trycatch ใน R


342

ฉันต้องการเขียนtrycatchโค้ดเพื่อจัดการกับข้อผิดพลาดในการดาวน์โหลดจากเว็บ

url <- c(
    "http://stat.ethz.ch/R-manual/R-devel/library/base/html/connections.html",
    "http://en.wikipedia.org/wiki/Xz")
y <- mapply(readLines, con=url)

คำสั่งสองคำสั่งเหล่านี้ทำงานได้สำเร็จ ด้านล่างนี้ฉันสร้างที่อยู่เว็บที่ไม่มีอยู่:

url <- c("xxxxx", "http://en.wikipedia.org/wiki/Xz")

url[1]ไม่ได้อยู่. เราจะเขียนtrycatchloop (function) อย่างไร:

  1. เมื่อ URL ไม่ถูกต้องผลลัพธ์จะเป็น: "เว็บ URL ไม่ถูกต้องไม่สามารถรับได้"
  2. เมื่อ URL ผิดรหัสจะไม่หยุด แต่ยังคงดาวน์โหลดต่อไปจนกว่าจะสิ้นสุดรายการ URL หรือไม่

คำตอบ:


626

ถ้าอย่างนั้น: ยินดีต้อนรับสู่โลก R ;-)

ไปเลย

การตั้งค่ารหัส

urls <- c(
    "http://stat.ethz.ch/R-manual/R-devel/library/base/html/connections.html",
    "http://en.wikipedia.org/wiki/Xz",
    "xxxxx"
)
readUrl <- function(url) {
    out <- tryCatch(
        {
            # Just to highlight: if you want to use more than one 
            # R expression in the "try" part then you'll have to 
            # use curly brackets.
            # 'tryCatch()' will return the last evaluated expression 
            # in case the "try" part was completed successfully

            message("This is the 'try' part")

            readLines(con=url, warn=FALSE) 
            # The return value of `readLines()` is the actual value 
            # that will be returned in case there is no condition 
            # (e.g. warning or error). 
            # You don't need to state the return value via `return()` as code 
            # in the "try" part is not wrapped insided a function (unlike that
            # for the condition handlers for warnings and error below)
        },
        error=function(cond) {
            message(paste("URL does not seem to exist:", url))
            message("Here's the original error message:")
            message(cond)
            # Choose a return value in case of error
            return(NA)
        },
        warning=function(cond) {
            message(paste("URL caused a warning:", url))
            message("Here's the original warning message:")
            message(cond)
            # Choose a return value in case of warning
            return(NULL)
        },
        finally={
        # NOTE:
        # Here goes everything that should be executed at the end,
        # regardless of success or error.
        # If you want more than one expression to be executed, then you 
        # need to wrap them in curly brackets ({...}); otherwise you could
        # just have written 'finally=<expression>' 
            message(paste("Processed URL:", url))
            message("Some other message at the end")
        }
    )    
    return(out)
}

การใช้รหัส

> y <- lapply(urls, readUrl)
Processed URL: http://stat.ethz.ch/R-manual/R-devel/library/base/html/connections.html
Some other message at the end
Processed URL: http://en.wikipedia.org/wiki/Xz
Some other message at the end
URL does not seem to exist: xxxxx
Here's the original error message:
cannot open the connection
Processed URL: xxxxx
Some other message at the end
Warning message:
In file(con, "r") : cannot open file 'xxxxx': No such file or directory

กำลังตรวจสอบผลลัพธ์

> head(y[[1]])
[1] "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"      
[2] "<html><head><title>R: Functions to Manipulate Connections</title>"      
[3] "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"
[4] "<link rel=\"stylesheet\" type=\"text/css\" href=\"R.css\">"             
[5] "</head><body>"                                                          
[6] ""    

> length(y)
[1] 3

> y[[3]]
[1] NA

ข้อสังเกตเพิ่มเติม

tryCatch

tryCatchส่งคืนค่าที่เกี่ยวข้องกับการดำเนินการexprเว้นแต่ว่ามีข้อผิดพลาดหรือคำเตือน ในกรณีนี้สามารถระบุค่าส่งคืนเฉพาะ (ดูreturn(NA)ด้านบน) โดยการจัดหาฟังก์ชันตัวจัดการตามลำดับ (ดูอาร์กิวเมนต์errorและwarningใน?tryCatch) สิ่งเหล่านี้อาจเป็นฟังก์ชั่นที่มีอยู่แล้ว แต่คุณสามารถกำหนดได้ภายในtryCatch()(ตามที่ฉันทำด้านบน)

ความหมายของการเลือกค่าส่งคืนเฉพาะของฟังก์ชันตัวจัดการ

ในฐานะที่เราได้ระบุไว้ว่าNAควรจะกลับในกรณีของข้อผิดพลาดองค์ประกอบที่สามในการเป็นy NAถ้าเราต้องการได้รับการแต่งตั้งNULLให้เป็นค่าตอบแทน, ความยาวของyก็จะได้รับการ2แทน3เป็นlapply()ก็จะ "ละเว้น" NULLค่าผลตอบแทนที่มี โปรดทราบว่าหากคุณไม่ได้ระบุค่าส่งคืนอย่างชัดเจนผ่านทางreturn()ฟังก์ชันตัวจัดการจะส่งคืนNULL(เช่นในกรณีที่เกิดข้อผิดพลาดหรือเงื่อนไขคำเตือน)

ข้อความเตือน "ไม่ต้องการ"

ในฐานะที่warn=FALSEดูเหมือนจะไม่ได้มีผลกระทบใด ๆ ทางเลือกในการปราบปรามการเตือน (ซึ่งในกรณีนี้ไม่ได้จริงๆที่น่าสนใจ) คือการใช้งาน

suppressWarnings(readLines(con=url))

แทน

readLines(con=url, warn=FALSE)

หลายนิพจน์

โปรดทราบว่าคุณยังสามารถวางหลายนิพจน์ใน "ส่วนนิพจน์ที่เกิดขึ้นจริง" (อาร์กิวเมนต์exprของtryCatch()) ถ้าคุณใส่ไว้ในวงเล็บปีกกา (เช่นเดียวกับที่ฉันแสดงในfinallyส่วน)


เนื่องจากสตริงแรกในpasteฟังก์ชันของคุณลงท้ายด้วยช่องว่างทำไมไม่เว้นช่องว่างและsep=""?
seancarmody

2
@ seancarmody: true ;-) ฉันแค่คุ้นเคยกับการใส่สายยาว ๆ / ซับซ้อนกว่าเดิมฉันต้องควบคุมช่องว่างด้วยการเขียนมันออกมา
Rappster

3
คุณควรใช้paste0มัน!
seancarmody

6
paste0() อยู่ในฐาน ภายในทั้งสองpaste()และpaste0()โทรdo_pasteในpaste.c ข้อแตกต่างคือpaste0()ไม่ผ่านการsepโต้แย้ง
jthetzel

1
@JulienNavarre: โปรดจำไว้ว่า "ลองส่วน" จะส่งคืนวัตถุสุดท้ายเสมอ(ปัจจุบันreadLines(con=url, warn=FALSE)ซึ่งเป็นสิ่งที่เกิดขึ้นจริงซึ่งอาจผิดพลาดได้) ดังนั้นหากคุณต้องการเพิ่มข้อความคุณจะต้องเก็บค่าการเติมซ้ำจริงในตัวแปร: out <- readLines(con=url, warn=FALSE)ตามด้วยmessage("Everything worked")ตามด้วยoutเพื่อให้เป็นวัตถุสุดท้ายที่ส่งคืนจริง
Rappster

69

R ใช้ฟังก์ชั่นสำหรับการนำบล็อกลองจับไปใช้:

ไวยากรณ์มีลักษณะดังนี้:

result = tryCatch({
    expr
}, warning = function(warning_condition) {
    warning-handler-code
}, error = function(error_condition) {
    error-handler-code
}, finally={
    cleanup-code
})

ใน tryCatch () มีสองเงื่อนไขที่สามารถจัดการได้: 'คำเตือน' และ 'ข้อผิดพลาด' สิ่งสำคัญที่ต้องทำความเข้าใจเมื่อเขียนโค้ดแต่ละบล็อคคือสถานะของการดำเนินการและขอบเขต @source


5
แทนที่error-handler-codeด้วยcat("web url is wrong, can't get")
seancarmody

2
คุณออกจากการจับข้อความ
rawr

52

tryCatchมีโครงสร้างไวยากรณ์ที่ซับซ้อนเล็กน้อย อย่างไรก็ตามเมื่อเราเข้าใจ 4 ส่วนที่ประกอบเป็นการโทรแบบ tryCatch ที่แสดงด้านล่างจะทำให้จดจำได้ง่าย:

expr : [ จำเป็น ] รหัส R ที่จะได้รับการประเมิน

ข้อผิดพลาด : [ ไม่บังคับ ] สิ่งที่ควรเรียกใช้หากเกิดข้อผิดพลาดขณะประเมินรหัสใน expr

คำเตือน : [ ไม่บังคับ ] สิ่งที่ควรดำเนินการหากมีคำเตือนเกิดขึ้นขณะประเมินรหัสเป็น expr

ในที่สุด : [ ไม่บังคับ ] สิ่งที่ควรเรียกใช้ก่อนเลิกการเรียกใช้ tryCatch โดยไม่คำนึงว่า expr ทำงานได้สำเร็จมีข้อผิดพลาดหรือมีคำเตือน

tryCatch(
    expr = {
        # Your code...
        # goes here...
        # ...
    },
    error = function(e){ 
        # (Optional)
        # Do this if an error is caught...
    },
    warning = function(w){
        # (Optional)
        # Do this if an warning is caught...
    },
    finally = {
        # (Optional)
        # Do this at the end before quitting the tryCatch structure...
    }
)

ดังนั้นตัวอย่างของเล่นในการคำนวณบันทึกของค่าอาจมีลักษณะดังนี้:

log_calculator <- function(x){
    tryCatch(
        expr = {
            message(log(x))
            message("Successfully executed the log(x) call.")
        },
        error = function(e){
            message('Caught an error!')
            print(e)
        },
        warning = function(w){
            message('Caught an warning!')
            print(w)
        },
        finally = {
            message('All done, quitting.')
        }
    )    
}

ตอนนี้รันสามกรณี:

กรณีที่ถูกต้อง

log_calculator(10)
# 2.30258509299405
# Successfully executed the log(x) call.
# All done, quitting.

กรณี "คำเตือน"

log_calculator(-10)
# Caught an warning!
# <simpleWarning in log(x): NaNs produced>
# All done, quitting.

กรณี "ผิดพลาด"

log_calculator("log_me")
# Caught an error!
# <simpleError in log(x): non-numeric argument to mathematical function>
# All done, quitting.

ฉันได้เขียนเกี่ยวกับกรณีการใช้งานที่มีประโยชน์ซึ่งฉันใช้เป็นประจำ ค้นหารายละเอียดเพิ่มเติมได้ที่นี่: https://rsangole.netlify.com/post/try-catch/

หวังว่านี่จะเป็นประโยชน์


34

นี่เป็นตัวอย่างที่ง่าย :

# Do something, or tell me why it failed
my_update_function <- function(x){
    tryCatch(
        # This is what I want to do...
        {
        y = x * 2
        return(y)
        },
        # ... but if an error occurs, tell me what happened: 
        error=function(error_message) {
            message("This is my custom message.")
            message("And below is the error message from R:")
            message(error_message)
            return(NA)
        }
    )
}

หากคุณต้องการที่จะจับ "คำเตือน" เพียงเพิ่มwarning=คล้ายกับerror=ส่วน


1
ควรมีวงเล็บปีกการอบexprส่วนเนื่องจากมีสองบรรทัดแทนหนึ่ง?
พอล

ขอบคุณ! หลังจากตรวจสอบสองครั้งฉันไม่เห็นความต้องการวงเล็บปีกกาใด ๆ เลย
พอล

ขอบคุณสำหรับการตรวจสอบซ้ำ เมื่อฉันเรียกรหัสของคุณผมได้และError: unexpected ')' in " )" Error: unexpected ')' in " )"การเพิ่มวงเล็บปีกกาคู่หนึ่งช่วยแก้ไขปัญหา
พอล

สำหรับกรณีการใช้งานส่วนใหญ่คุณพูดถูกขอบคุณ! มันได้รับการแก้ไขแล้ว
พอล

23

เนื่องจากฉันเพิ่งเสียชีวิตไปสองวันเพื่อพยายามแก้ปัญหาสำหรับ tryCatch สำหรับฟังก์ชั่นที่ไม่เหมาะสมฉันคิดว่าฉันควรแบ่งปันภูมิปัญญาของฉัน (และสิ่งที่ขาดหายไป) FYI - irr เป็นฟังก์ชันจริงจาก FinCal ในกรณีนี้ซึ่งมีข้อผิดพลาดในบางกรณีในชุดข้อมูลขนาดใหญ่

  1. ตั้งค่า tryCatch เป็นส่วนหนึ่งของฟังก์ชั่น ตัวอย่างเช่น:

    irr2 <- function (x) {
      out <- tryCatch(irr(x), error = function(e) NULL)
      return(out)
    }
  2. เพื่อให้ข้อผิดพลาด (หรือคำเตือน) ทำงานคุณต้องสร้างฟังก์ชัน ฉันเดิมสำหรับส่วนข้อผิดพลาดเพิ่งเขียนerror = return(NULL)และค่าทั้งหมดกลับมาเป็นโมฆะ

  3. อย่าลืมสร้างย่อยเอาต์พุต (เช่น "ออก" ของฉัน) return(out)และ


3
เหตุใดหมายเลข 3 จึงจำเป็น
jan-glx
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.