Геокодирование с помощью R и API Googlemaps
Я регулярно использую R для статистического анализа, но постепенно пытаюсь перейти к ГИС и пространственной визуализации с помощью R.
Я пытаюсь повторить код геокодирования, доступный на
https://github.com/smholloway/data-mashups-in-r/blob/master/mapping-foreclosures.r#L14
После запуска функции геокодирования, я получаю следующее сообщение об ошибке
geocoding: http://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=5833%20Ashland%20Ave.+Philadelphia+PA
parsing or http error: $ operator is invalid for atomic vectors
geocoding: http://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=219-221%20E.%20Tioga%20St.+Philadelphia+PA
parsing or http error: arguments imply differing number of rows: 1, 0
Любые предложения о том, что я должен делать, чтобы этот кусок кода работал?
Вот фрагмент кода, который я запускаю
library("XML")
library("rjson")
library("RCurl")
library("PBSmapping")
if (!file.exists("properties.html")) {
download.file(url="http://web.archive.org/web/20080610132249/www.phillysheriff.com/properties.html", destfile="properties.html")
}
########################
# getAddressesFromHTML
# input:html filename
# returns:dataframe of geocoded addresses that can be plotted by PBSmapping
########################
getAddressesFromHTML<-function(myHTMLDoc){
myStreets<-vector(mode="character",0)
stNum<-"^[0-9]{2,5}(\\-[0-9]+)?"
stName<-"([NSEW]\\. )?([0-9A-Z ]+)"
stSuf<-"(St|Ave|Place|Blvd|Drive|Lane|Ln|Rd)(\\.?)$"
badStrings<-
"(\\r| a\\/?[kd]\\/?a.+$| - Premise.+$| assessed as.+$|, Unit.+
|<font size=\"[0-9]\">|Apt\\..+| #.+$|[,\"]|\\s+$)"
myStPat<-paste(stNum,stName,stSuf,sep=" ")
for(line in readLines(myHTMLDoc)){
line<-gsub(badStrings,'',line,perl=TRUE)
matches<-grep(myStPat,line,perl=TRUE,
value=FALSE,ignore.case=TRUE)
if(length(matches)>0){
myStreets<-append(myStreets,line)
}
}
myStreets
}
####################
# geocodeAddresses
# input:vector of streets
# output:data frame containing lat/longs in PBSmapping-acceptable format
####################
geocodeAddresses<-function(myStreets){
myGeoTable<-data.frame(address=character(),lat=numeric(),long=numeric(),EID=numeric())
for(myStreet in myStreets){
requestUrl<-paste(
"http://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=",
URLencode(myStreet),
"+Philadelphia+PA",
sep="")
cat("geocoding:", requestUrl, "\n")
tryCatch({
json_data <- fromJSON(paste(readLines(requestUrl), collapse=""))
lat <- unlist(lapply(json_data$results, function(x) {x$geometry[1]$location$lat}))
lng <- unlist(lapply(json_data$results, function(x) {x$geometry[1]$location$lng}))
myGeoTable<-rbind(myGeoTable,data.frame(address = myStreet, Y = lat, X = lng, EID=NA))
}, error=function(err) {
cat("parsing or http error:", conditionMessage(err), "\n")
})
Sys.sleep(0.1)
}
#let's use the built-in numbering as the event id that PBSmapping wants
myGeoTable$EID<-as.numeric(rownames(myGeoTable))
myGeoTable
}
streets<-getAddressesFromHTML("properties.html")
geoTable<-geocodeAddresses(streets)
1 ответ
Вы можете использовать ggmaps
функция geocode("location")
но есть ограничение в 2500 запросов.
Вот функция, которая позволит вам использовать API Карт Bing (ограничение в 500000 за всю жизнь). Вы должны зарегистрироваться на рынке Microsoft, но это бесплатно.
#Google Maps API limits querys to 2500 per day and fails to geocode smaller towns. So I wrote a function to geocode using Bing's API. It's also much faster.
geocode <- function( x, verbose=FALSE, service="google", returntype="coordinates", ... ) {
UseMethod("geocode",x)
}
geocode.default <- function(x,verbose=FALSE, service="google", returntype="coordinates", ...) {
if( is.na( x ) | gsub(" *", "", x) == "" ) return(c(NA,NA))
service <- tolower(service)
BingMapsKey <- getOption("BingMapsKey")
if(service=="bing" && is.null(BingMapsKey) ) stop("To use Bing, you must save your Bing Maps API key (obtain at http://msdn.microsoft.com/en-us/library/ff428642.aspx) using options(BingMapsKey='mykey').\n")
construct.geocode.url <- list()
construct.geocode.url[["google"]] <- function(address, return.call = "json", sensor = "false") {
root <- "http://maps.google.com/maps/api/geocode/"
u <- paste(root, return.call, "?address=", address, "&sensor=", sensor, sep = "")
return(URLencode(u))
}
construct.geocode.url[["bing"]] <- function(address, maxResults=1) {
root <- "http://dev.virtualearth.net/REST/v1/Locations"
u <- paste0(root, "?query=", address, "&maxResults=",maxResults,"&key=",BingMapsKey)
return(URLencode(u))
}
if(verbose) message(x,appendLF=FALSE)
u <- construct.geocode.url[[service]](x)
doc <- RCurl::getURL(u)
j <- RJSONIO::fromJSON(doc,simplify = FALSE)
parse.json <- list()
parse.json[["google"]] <- function(j) {
if(j$status=="OK") {
res <- list()
if( "coordinates" %in% returntype ) {
lat <- j$results[[1]]$geometry$location$lat
lng <- j$results[[1]]$geometry$location$lng
res$coordinates <- c(lat, lng)
}
if( "zip" %in% returntype ) {
zp <- j$results[[1]]$address_components[[8]]$short_name
if( j$results[[1]]$address_components[[8]]$types[[1]] != "postal_code" ) warning(paste("Not sure these zips are actually zips. Type:", j$results[[1]]$address_components[[8]]$types[[1]]) )
res$zip <- zp
}
return( res )
} else {
if(j$status=="OVER_QUERY_LIMIT") warning("Google's geocoding quota appears to have been reached for the day.")
return(c(NA,NA))
}
}
parse.json[["bing"]] <- function(j) {
if(j$authenticationResultCode != "ValidCredentials") {
warning("Your BingMapsKey was not accepted.")
return(c(NA,NA))
}
if(j$statusDescription!="OK") {
warning("Something went wrong. Bing Maps API return status code ",j$statusCode," - ", j$statusDescription)
return(c(NA,NA))
}
if(j$resourceSets[[1]]$estimatedTotal==0) {
warning("Didn't find any points")
return(c(NA,NA))
}
if(verbose) message(" - Confidence: ", j$resourceSets[[1]]$resources[[1]]$confidence ,appendLF=FALSE)
res <- list()
if( "coordinates" %in% returntype ) {
crds <- unlist(j$resourceSets[[1]]$resources[[1]]$point$coordinates)
res$coordinates <- crds
}
if( "zip" %in% returntype ) {
res$zip <- sub( "^.*(\\d{5}-?\\d?\\d?\\d?\\d?).*$", "\\1", j$resourceSets[[1]]$resources[[1]]$address$formattedAddress )
}
return( res )
}
res <- parse.json[[service]](j)
if(length(returntype)==1) res <- res[[1]]
if(verbose) message("\n",appendLF=FALSE)
return( res )
}
#Vectorize function
geocodeVect <- Vectorize(geocode, vectorize.args="x")
#Batch geocode with Bing
options(BingMapsKey="YourBingAPIkey")
data<-geocodeVect(data, service="bing",
returntype="coordinates")
data <-as.data.frame(t(as.data.frame(data)))
data $location<-rownames(data)
rownames(data)<-NULL