我正在尝试在R中使用while循环实现tryCatch,但一直遇到问题。我试图实现一些建议的解决方案(围绕for循环),但没有成功。
基本上我用R查询API并循环遍历许多相关参数(精确地说是经度和纬度)。我之所以需要tryCatch块,是因为有时URL请求会失败,从而阻止脚本运行。我想要做的是忽略错误,将循环计数器增加1并继续提取。
我设置的while循环是(FYI - length指的是数据帧循环的长度):
i <- 1
while(i <= length) {
x_cord <- geocode_area$X[i]
y_cord <- geocode_area$Y[i]
target <- getUrl(x_cord,y_cord)
dat <- fromJSON(target)
geocode_area$Block[i] <- dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK
print(paste(i/length*100,"% completed",sep=""))
print(dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK)
i <- i + 1
}
getUrl()函数定义为:
getUrl <- function(x,y) {
root <- "http://geocoding.geo.census.gov/geocoder/geographies/coordinates?"
u <- paste0(root,"x=", x,"&y=", y,"&benchmark=4&vintage=4&format=json")
return(URLencode(u))
}
while循环的输入data.frame看起来像这样(注意我已经在字符串中抛出以模拟错误来测试tryCatch是否正常工作):
X Y Block
1 -122.425891675136 37.7745985956747 0
2 -122.42436302145 37.8004143219856 0
3 -122.426995326766 37.8008726327692 0
4 -122.438737622757 37.7715411720578 0
5 abc zsads 0
我尝试了很多SO和其他解决方案,但结果似乎没有正常工作。有人可以帮忙吗?
谢谢!
杰克
答案 0 :(得分:2)
总的来说 - 你的代码有点怪异。我会推荐一个for
循环,或者可能更好,一个完成这个功能的函数。但是你可以让你的循环工作。
# A minimal working version
library(RJSONIO)
options(stringsAsFactors = FALSE)
# Create a data frame with the example data
geocode_area <- data.frame(X = c("-122.425891675136","-122.42436302145","-122.426995326766","-122.438737622757","abc"),
Y = c("37.7745985956747","37.8004143219856","37.8008726327692","37.7715411720578","zsads"),
Block = c(0,0,0,0,0))
# Your old function, unchanged
getUrl <- function(x,y) {
root <- "http://geocoding.geo.census.gov/geocoder/geographies/coordinates?"
u <- paste0(root,"x=", x,"&y=", y,"&benchmark=4&vintage=4&format=json")
return(URLencode(u))
}
# Getting the length parameter
length <- nrow(geocode_area)
i <- 1
while(i <= length) {
x_cord <- geocode_area$X[i]
y_cord <- geocode_area$Y[i]
target <- getUrl(x_cord,y_cord)
# Here be new code
# Do a try(), with silent = TRUE, which suppresses outputs to STDERR
# In principle, this is dangerous - a better approach is to strip out the offending data before invoking it
# Errors are, after all, there for a reason
dat <- try(fromJSON(target),silent = TRUE)
# Now, we conditionally complete the next steps
# If the class of dat is not a try-error, perform your normal operations
# Otherwise, bypass and print a note to the console
if(class(dat) != "try-error") {
geocode_area$Block[i] <- dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK
print(paste(i/length*100,"% completed",sep=""))
print(dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK)
} else if (class(dat) == "try-error") {print("Error encountered, bypassing")}
i <- i + 1
}
已编辑添加:显然,这会使用try()
代替tryCatch()
。然而,由于海报最终使用try()
,这可能代表了另一种方式,我想我会把它留下来。
答案 1 :(得分:0)
在评论的那些人的帮助下,我得到了答案。基本上完全避免while循环,而是使用for循环。
我不确定为什么while循环不起作用,我认为这可能与更新finally块中的循环计数器有困难。
事实上,对于我遇到的具体问题,我根本不需要tryCatch。我会使用错误块将我正在更新的值设置为0,但是可以在for循环中将输入变量重置为0。这是必需的,因为否则将保留前一次迭代的值。我还需要在{}中包装try表达式,因为有多个表达式。
以下代码。我希望这有助于某人!
for(i in 1:length) {
try(
{x_cord <- geocode_area$X[i]
y_cord <- geocode_area$Y[i]
target <- getUrl(x_cord,y_cord)
dat <- fromJSON(target)
geocode_area$Block[i] <- dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK
print(paste(i/length*100,"% completed",sep=""))
print(dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK)
dat$result$geographies$`2010 Census Blocks`[[1]]$BLOCK <- 0}
)
}