Google Maps API返回ZERO_RESULTS时如何生成含NA的DataFrame?
解决ggmap mapdist transit模式下ZERO_RESULTS导致的报错问题
问题说明
使用ggmap的mapdist函数计算公共交通(transit模式)的距离与时间时,若部分地址对无可用公共交通连接,Google API会返回ZERO_RESULTS状态,此时mapdist的simple输出会跳过该条目,导致结果DataFrame的行数与输入地址对数不匹配,触发bind_cols()的尺寸不匹配报错:
Error in
bind_cols(): Can't recycle..1(size 16) to match..2(size 14).
需要修改代码,让无结果的地址对在最终DataFrame中填充NA值,而非报错。
原始代码
ggmap::register_google("your_key", write=TRUE) gmap.trans <- data.frame( gmap.address = c("13187 berlin, germany", "14052 berlin, germany", "10315 berlin, germany", "10249 berlin, germany", "18609 binz, germany", "10369 berlin, germany", "15370 petershagen/eggersdorf, germany", "15806 trebbin, germany", "10719 berlin, germany", "17192, germany", "19053 schwerin, germany", "10717 berlin, germany", "10439 berlin, germany", "12489 berlin, germany", "12527 berlin, germany", "12621 berlin, germany"), dest = c("Oetztal Bahnhof , Österreich")) PubTrans <- mapdist(from = gmap.trans$gmap.address, to = gmap.trans$dest, mode = "transit", output = "simple")
解决方案一:用tryCatch逐个处理地址对
通过逐个处理每个地址对,捕获ZERO_RESULTS触发的错误,返回填充NA的行,最后合并成完整DataFrame:
library(ggmap) library(dplyr) library(purrr) ggmap::register_google("your_key", write=TRUE) gmap.trans <- data.frame( gmap.address = c("13187 berlin, germany", "14052 berlin, germany", "10315 berlin, germany", "10249 berlin, germany", "18609 binz, germany", "10369 berlin, germany", "15370 petershagen/eggersdorf, germany", "15806 trebbin, germany", "10719 berlin, germany", "17192, germany", "19053 schwerin, germany", "10717 berlin, germany", "10439 berlin, germany", "12489 berlin, germany", "12527 berlin, germany", "12621 berlin, germany"), dest = rep("Oetztal Bahnhof , Österreich", 16) ) # 定义单个地址对的处理函数 get_transit_info <- function(from_addr, to_addr) { tryCatch( mapdist(from = from_addr, to = to_addr, mode = "transit", output = "simple"), error = function(e) { # 无结果时返回填充NA的行 data.frame( from = from_addr, to = to_addr, m = NA_real_, km = NA_real_, miles = NA_real_, seconds = NA_real_, minutes = NA_real_, hours = NA_real_, mode = "transit", stringsAsFactors = FALSE ) } ) } # 遍历所有地址对并合并结果 PubTrans <- map2_dfr(gmap.trans$gmap.address, gmap.trans$dest, get_transit_info)
解决方案二:直接调用Google Distance Matrix API
绕过mapdist函数,直接调用API接口解析原始返回结果,更灵活地处理ZERO_RESULTS状态:
library(httr) library(jsonlite) library(dplyr) api_key <- "your_key" base_url <- "https://maps.googleapis.com/maps/api/distancematrix/json" gmap.trans <- data.frame( gmap.address = c("13187 berlin, germany", "14052 berlin, germany", "10315 berlin, germany", "10249 berlin, germany", "18609 binz, germany", "10369 berlin, germany", "15370 petershagen/eggersdorf, germany", "15806 trebbin, germany", "10719 berlin, germany", "17192, germany", "19053 schwerin, germany", "10717 berlin, germany", "10439 berlin, germany", "12489 berlin, germany", "12527 berlin, germany", "12621 berlin, germany"), dest = rep("Oetztal Bahnhof , Österreich", 16) ) # 发送API请求 response <- GET(base_url, query = list( origins = paste(gmap.trans$gmap.address, collapse = "|"), destinations = gmap.trans$dest[1], mode = "transit", key = api_key )) content <- fromJSON(content(response, "text")) # 解析结果并构建DataFrame PubTrans <- tibble( from = content$origin_addresses, to = rep(content$destination_addresses[1], length(content$origin_addresses)), status = sapply(content$rows$elements, function(x) x$status), m = sapply(content$rows$elements, function(x) ifelse(x$status == "OK", x$distance$value, NA)), km = sapply(content$rows$elements, function(x) ifelse(x$status == "OK", x$distance$value / 1000, NA)), miles = sapply(content$rows$elements, function(x) ifelse(x$status == "OK", x$distance$value / 1609.34, NA)), seconds = sapply(content$rows$elements, function(x) ifelse(x$status == "OK", x$duration$value, NA)), minutes = sapply(content$rows$elements, function(x) ifelse(x$status == "OK", x$duration$value / 60, NA)), hours = sapply(content$rows$elements, function(x) ifelse(x$status == "OK", x$duration$value / 3600, NA)), mode = "transit" )
说明
- 方案一基于原
mapdist函数改造,代码改动较小,适合习惯使用ggmap的用户 - 方案二直接调用API,能完整获取所有返回状态,更可控,适合需要自定义处理逻辑的场景
内容的提问来源于stack exchange,提问作者Pia Berer
相关产品推荐
相关产品推荐

