Геокодирование с помощью 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
Другие вопросы по тегам