我正在尝试处理for循环中的两个可能的错误,该循环要求stplanr::dist_google与API进行交互。我知道这些错误,因此我想在发生错误时采取特定的措施。
如果我尝试仅处理可能的错误之一,则它可以工作:
data(cents, package = "stplanr")
data(flow, package = "stplanr")
od <- stplanr::od2odf(flow=flow, zones=cents)
uma_linha <- data.frame(from_addresses=NA, to_addresses=NA, distances=NA,
duration=NA, currency=NA, fare=NA)
output <- data.frame()
for (linha in 1:nrow(od)) {
o <- od[linha, 3:4]
d <- od[linha, 5:6]
output <- tryCatch(
{
rbind(output, stplanr::dist_google(from = o, to = d,
mode = 'walking'))
},
error = function(na) {
message("Erro: No results for this request (e.g. due to lack of support for this mode between the from and to locations)")
message(na)
output <- rbind(output, uma_linha)
}
)
}
Run Code Online (Sandbox Code Playgroud)
我需要获得2500多个观察结果。然后,自动使用两个API。我试图将其他信息和一些小技巧作为一种动作。当我调用循环时,我反复收到两条错误消息。
n <- 1
apis <- c("api01", "api02", "api03")
for (linha in 1:nrow(od)) {
o <- od[linha, 3:4]
d <- od[linha, 5:6]
output <- tryCatch(
{
rbind(output, stplanr::dist_google(from = o, to = d,
mode = 'walking',
google_api = apis[n]))
},
error = function(na) {
message("Erro: No results for this request (e.g. due to lack of support for this mode between the from and to locations)")
message(na)
output <- rbind(output, uma_linha)
},
error = function(quota) {
message("Erro: You have exceeded your daily request quota for this API.")
message(quota)
n <- n + 1
return(n)
}
)
}
Run Code Online (Sandbox Code Playgroud)
我对tryCatch感到困惑。我究竟做错了什么?
非常感谢您的帮助。
编辑
在Martin明确解释之后,我尝试将所有内容放入函数中。没用
如果错误是:
No results for this request (e.g. due to lack of support for this mode between the from and to locations)
Run Code Online (Sandbox Code Playgroud)
然后该函数将继续执行并返回一个空对象。配额结束时,错误为:
You have exceeded your daily request quota for this API.
Run Code Online (Sandbox Code Playgroud)
它递归地返回错误,而不是执行n <- n + 1并继续循环:
asha_dists <- function(fluxo, zonas, api) {
zonas <- as(st_transform(zonas, 4326), "Spatial")
od <- stplanr::od2odf(flow = fluxo, zones = zonas)
uma_linha <- data.frame(from_addresses=NA, to_addresses=NA, distances=NA,
duration=NA, currency=NA, fare=NA)
n <- 1
output <- data.frame()
for (linha in 1:nrow(od)) {
o <- od[linha, 3:4]
d <- od[linha, 5:6]
output <- tryCatch(
{
rbind(output, stplanr::dist_google(from = o, to = d,
mode = 'walking', google_api = api[n]))
},
custom_error = function(e) {
err <- conditionMessage(e)
message("found custom_error: ", err)
output <- rbind(output, uma_linha)
},
error = function(e) {
err <- conditionMessage(e)
message("found an error: ", err)
n <- n + 1
}
)
}
return(output)
}
Sent this request: https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=-23.5678377804732,-46.5708261676873&destinations=-23.5706647015703,-46.5755950203842&mode=walking&key=AIzaSyBRPrAjSE_pRMWSq_XlO4BFwGD63j_gB4U
found an error: You have exceeded your daily request quota for this API.
Sent this request: https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=-23.5665596480444,-46.5682308348154&destinations=-23.5706647015703,-46.5755950203842&mode=walking&key=AIzaSyBRPrAjSE_pRMWSq_XlO4BFwGD63j_gB4U
found an error: You have exceeded your daily request quota for this API.
Run Code Online (Sandbox Code Playgroud)
我只是被困住了。
有两种方法可以捕获错误类型,这取决于错误是如何生成的。这是一个产生错误的函数
f <- function(type) {
switch(
type,
a = stop("oops a: type 1 error"),
b = stop("oops b: type 2 error"),
c = {
err <- simpleError("oop 2: custom error class")
class(err) <- c("custom_error", class(err))
stop(err)
}
)
}
Run Code Online (Sandbox Code Playgroud)
如果type是“a”或“b”,则该函数生成标准错误条件,但具有不同的条件消息(“oops a:...”和“oops b:...”)。如果type是“c”,则该错误具有特定的类“custom_error”,该类扩展了标准错误的 (S3) 类。
> f("a")
Error in f("a") : oops a: type 1 error
> f("b")
Error in f("b") : oops b: type 2 error
> f("c")
Error: oop 2: custom error class
Run Code Online (Sandbox Code Playgroud)
这是一个捕获错误的函数。
g <- function(type) {
tryCatch({
f(type)
}, custom_error = function(e) {
err <- conditionMessage(e)
message("found custom_error: ", err)
}, error = function(e) {
err <- conditionMessage(e)
if (startsWith(err, "oops a")) {
message("found type 'a' error: ", err)
} else if (startsWith(err, "oops b")) {
message("found type 'b' error: ", err)
} else {
message("generic error: ", err)
}
})
}
Run Code Online (Sandbox Code Playgroud)
tryCatch 的处理程序参数按照它们在参数列表中出现的顺序进行测试,如果它们与错误的类匹配,则对它们进行评估。“a”或“b”类型的错误具有相同的类,因此由相同的处理程序捕获;区分它们的唯一选择是“抓取”错误消息,查看条件(错误)消息以确定正在处理的错误类型(希望该包不要复杂到包含错误消息翻译,例如基础 R 确实如此,因为通常不可能以稳健的方式消除翻译错误......)
> g("a")
found type 'a' error: oops a: type 1 error
> g("b")
found type 'b' error: oops b: type 2 error
Run Code Online (Sandbox Code Playgroud)
另一方面,类型“c”可以被处理程序捕获,因为它有自己的类。所以...
> g("c")
found custom_error: oop 2: custom error class
Run Code Online (Sandbox Code Playgroud)
实际上可以沿着错误处理程序或调用堆栈向上传递错误
h <- function(type) {
tryCatch({
f(type)
}, custom_error = function(e) {
err <- conditionMessage(e)
message("found custom_error: ", err)
stop(e)
}, error = function(e) {
err <- conditionMessage(e)
message("found an error: ", err)
stop(e)
})
}
Run Code Online (Sandbox Code Playgroud)
和
> h("c")
found custom_error: oop 2: custom error class
found an error: oop 2: custom error class
Error: oop 2: custom error class
Run Code Online (Sandbox Code Playgroud)
很少有软件包实际上使用了产生自定义错误的功能,因此您可能会一直试图清除所看到的错误。对于你的情况,看来你必须刮,所以
output <- tryCatch({
rbind(
output,
stplanr::dist_google(
from = o, to = d, mode = 'walking', google_api = api[n]
)
)
}, error = function(e) {
err <- conditionMessage(e)
if (startsWith("No results for this request", err) {
warning(err) # warn instead of error
n <<- n + 1 # '<<-' to update n _outside_ this function
rbind(output, uma_linha) # empty output as result
} else if (startsWith("You have exceeded your daily", err) {
stop(e) # signal the original error
} else {
stop(e) # no error that we know how to handle, signal
}
})
Run Code Online (Sandbox Code Playgroud)