在循环中重复数值直到错误消失

3
我目前正在使用for循环和Googleway包来对大量地址进行地理编码。最初,我遇到了“500内部服务器错误”的问题,导致循环执行停止。我使用tryCatch()解决了这个问题。然而,由于这通常是一种短暂的错误,我希望该函数重复尝试出错的地址,直到它收到结果或达到某个任意的尝试次数,比如说10次。
不幸的是,我发现tryCatch()及其相关文档令人困惑,所以我不知道如何做除了让它抛出一个错误消息并继续执行之外的其他操作。以下是我的当前代码:
rugeocoder.fun <- function(addr){
              require(googleway)
              output <- vector("list", length=length(addr))
              tryCatch({
                for(i in 1:length(addr)){
                  output[[i]] <- google_geocode(address=addr[i], key="myapikey", language="ru", simplify=T)
                  print(i)

                }},error=function(e) output[[i]] <- "Error: reattempt")
              return(output)
              }
1个回答

7

您可能希望将安全调用google_geocode()的逻辑和循环地址的逻辑分离。

这里有一个函数,可以修改其他函数以重复调用它们,直到它们成功或失败了max_attempts次。修改其他函数的函数有时被称为“副词”。

safely <- function(fn, ..., max_attempts = 5) {
  function(...) {
    this_env <- environment()
    for(i in seq_len(max_attempts)) {
      ok <- tryCatch({
          assign("result", fn(...), envir = this_env)
          TRUE
        },
        error = function(e) {
          FALSE
        }
      )
      if(ok) {
        return(this_env$result)
      }
    }
    msg <- sprintf(
      "%s failed after %d tries; returning NULL.",
      deparse(match.call()),
      max_attempts
    )
    warning(msg)
    NULL
  }
}

试着在这个生成随机数的简单函数上尝试一下,并且如果它太小就抛出一个错误。

random <- function(lo, hi) {
  y <- runif(1, lo, hi)
  if(y < 0.75) {
    stop("y is less than 0.75")
  }
  y
}
safe_random <- safely(random)
safe_random() # will sometimes work, will sometimes return NULL
safe_random(0, 10) # will usually work

在您的情况下,您想修改google_geocode()函数。
safe_google_geocode <- safely(google_geocode)

然后循环调用这个地址。

geocodes <- lapply( # purrr::map() is an alternative
  addresses,
  safe_google_geocode,
  key = "myapikey", 
  language = "ru", 
  simplify = TRUE
)

1
你介意澄清一下为什么使用了 this_env <- environment() 吗?这里的环境有点复杂,我很难理解结果是如何从由 safely() 函数创建的闭包移动到全局环境中以便被分配给一个对象。 - Sean Norton
1
@SeanNorton 是的,这很令人困惑。tryCatch() 似乎使用它自己的环境,所以仅仅执行 result <- fn(...) 是不起作用的。 - Richie Cotton
哎呀,不幸的是,assign() 函数似乎无法正常工作 - 每次迭代都会出现错误信息 In assign("result", fn(...), envir = this_env) : restarting interrupted promise evaluation,返回一个完全为空的列表。有什么想法可以解决这个问题吗? - Sean Norton
不,使用eval.parent()包装也会产生相同的问题。 - Sean Norton
奇怪的是,清除了我的环境并重新加载只需要的软件包(readxl、googleway),代码现在似乎正在运行。我只能假设其中一个软件包存在冲突或某种错误,但是我不知道是什么。 - Sean Norton
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接