R語言-處理異常值或報錯的三個示例



Tuesday, March 31, 2015

之前用rvest幫人寫了一個定期抓取amazon價格庫存,並與之前價格比較的小程序,算是近期寫過的第一個完整的程序了。里面涉及了一些報錯的處理。

這里主要參考了stackoverflow上的以下問答:

  1. How to skip an error in a loop
  2. skip to next value of loop upon error in R

tryCatch部分,后續查找資料,發現以下博文: 1. R語言使用tryCatch進行簡單的錯誤處理

以下是代碼示例:

1)使用tryCatch函數跳過錯誤信息。(示例以download.file為樣式)

看以下代碼。這里需要批量下載一堆amazon產品信息。如果產品ID號不對,或者IP被限制,網頁會打不開,而download.file會報錯。我這里用tryCatch來獲取網頁打不開時的錯誤信息。並且要求執行下一步循環“”。

for (n in 1:length(productlink)){
        tryCatch({
        download.file(productlink[n],paste0(getwd(),"/html/",productid[n,],".html"),cacheOK = TRUE)
        },error=function(e){cat("ERROR :",conditionMessage(e),"\n")})
        Sys.sleep(0.5) #增加了Sys.sleep(seconds)函數,讓每一步循環都暫停一段時間。這個雖然會降低程序速度,但對於有訪問限制的網站,不失為一個好的辦法。
}

上述示例由兩個重要函數構成,即tryCatch和cat

查閱函數,tryCatch屬於base包,condition system。在R語言使用tryCatch進行簡單的錯誤處理這篇博文里有tryCatch的簡單示范如下:

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

 

即如果warning時,對warning怎么處理,如果error時對error怎么處理。如果沒有任何條件吻合,則最后會輸出expr里的內容。如果有final項的話,則會同時輸出finally項以及expr項

tryCatch({a<-"c"
        b<-"c"
        b==a},
        error=function(e){cat("hahaha",conditionMessage(e),"\n\n")},
        finally={print("ccc")})

[1] "ccc"
[1] TRUE

tryCatch({a<-"c"

        cc==a}, #cc不存在 error=function(e){cat("hahaha",conditionMessage(e),"\n\n")}, finally={print("ccc")})
hahaha object 'cc' not found 

對於代碼示例,即為,download成功則返回download內容,不成功則返回error=function(e){cat("ERROR :",conditionMessage(e),"\n")}

然后是cat函數。這個cat是一個輸入輸出值。這里等於,要求系統輸出“ERROR :”+conditionMessage(e)的內容。然后用“”分行。

另外,在stackoverflow上的這篇問答,由mmann1123回答的問題里,我們看到了更為有趣的一個應用。

這里收縮起來,展開亦可閱讀。

#!/usr/bin/env Rscript
# tryCatch.r -- experiments with tryCatch

# Get any arguments
arguments <- commandArgs(trailingOnly=TRUE)
a <- arguments[1]

# Define a division function that can issue warnings and errors
myDivide <- function(d, a) {
  if (a == 'warning') {
    return_value <- 'myDivide warning result'
    warning("myDivide warning message")
  } else if (a == 'error') {
    return_value <- 'myDivide error result'
    stop("myDivide error message")
  } else {
    return_value = d / as.numeric(a)
  }
  return(return_value)
}

# Evalute the desired series of expressions inside of tryCatch
result <- tryCatch({

  b <- 2
  c <- b^2
  d <- c+2
  if (a == 'suppress-warnings') {
    e <- suppressWarnings(myDivide(d,a))
  } else {
    e <- myDivide(d,a) # 6/a
  }
  f <- e + 100

}, warning = function(war) {

  # warning handler picks up where error was generated
  print(paste("MY_WARNING:  ",war))
  b <- "changing 'b' inside the warning handler has no effect"
  e <- myDivide(d,0.1) # =60
  f <- e + 100
  return(f)

}, error = function(err) {

  # warning handler picks up where error was generated
  print(paste("MY_ERROR:  ",err))
  b <- "changing 'b' inside the error handler has no effect"
  e <- myDivide(d,0.01) # =600
  f <- e + 100
  return(f)

}, finally = {

  print(paste("a =",a))
  print(paste("b =",b))
  print(paste("c =",c))
  print(paste("d =",d))
  # NOTE:  Finally is evaluated in the context of of the inital
  # NOTE:  tryCatch block and 'e' will not exist if a warning
  # NOTE:  or error occurred.
  #print(paste("e =",e))

}) # END tryCatch

print(paste("result =",result))
tryCatch示范

 

2)利用if語句以及stop語句。

即,如果某條件不成立,則停止程序,並輸出stop里的內容。我這里主要用於檢查原始product id是否輸入正確。

if (!sum(check)==length(productlink)) {
        productlink<-NULL
        productid<-NULL
    stop("invalid productid please double check if any space or else in, and resave the file or the script will not run")
    }

 

3)處理使用data.frame批量讀取數據時,元素因為不存在導致的data.frame報錯。

譬如說以下示例,因為a不存在,而導致data.frame報錯。

a<-NULL
b<-c("cc","dd")
data.frame(a,d)
> Error in data.frame(a, d) : 參數值意味着不同的行數: 0, 2

 因此,對於在循環里,需要先單獨合成data.frame,再使用rbind把各個data.frame合成在一起時,可以考慮增加異常值的賦值。如下面兩段,如果我拉的網頁里不存在product name,則length(productname)==1為FALSE,直接輸出“product not download or not existing”,那么這個字段就不是空值或者2-3個行,而是1行,之后合並為data.frame時就不會報錯了。

data<-function(n){
        ####隱掉獲得productname/price/category的代碼
        if(!length(productname)==1) {productname="Product not download or not existing"}
        if (!length(price)==1) {
                        price=NA 
                        category<-"Product not download or not existing"
        }
        data.frame(productname,price,category)
        #這里合成data.frame,如果這三個行數不等(多為空值NULL,或者某個字段有2-3行所導致。
        #使用上面的IF判斷賦值的好處是,最后出來的productname,price,category保證是1行,可以用data.frame合並。並且對異常值也有輸出。

 由於處理第2/3類錯誤時我還不了解tryCatch函數。目前看下來,貌似tryCatch函數能做的事情更多?

寫下來供以后寫代碼時參考。

另外,tryCatch在java,C里均有類似功效。看來R歸根到底,還是脫離不了底層語言啊。

 

接下來4月的學習計划,學完一個就寫一篇博文~~整理思路記錄筆記。

1)rCurl包,以及它那個厚厚的英文說明書。希望最后能學會用它爬一些rvest無法爬的腳本網頁,以及搜索框網頁等

2)用R做金融時間序列分析(煉數成金的班

3)跟着肖星老師重新復習財務分析知識(mooc課),在復習過去的財務知識后,再重新來看預測者網下的股票數據,嘗試做一下挖掘與分析,至少從宏觀上了解當前中國上市公司的布局與特點,為以后用R研究股票打打基礎。

 ----------

我的博客: http://www.cnblogs.com/weibaar 記錄學習R與數據分析的一切。

 

博客總目錄:http://www.cnblogs.com/weibaar/p/4507801.html

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM