【问题标题】:Geocoding in R with Google Maps使用谷歌地图在 R 中进行地理编码
【发布时间】:2011-03-16 12:09:17
【问题描述】:

我已尝试通过 Google 地图和此博客文章中的 XML 包运行代码以对 R 中的位置进行地理编码: http://www.r-chart.com/2010/07/maps-geocoding-and-r-user-conference.html

这是他的功能:

getDocNodeVal=function(doc, path){
  sapply(getNodeSet(doc, path), function(el) xmlValue(el))
}

gGeoCode=function(str){
  library(XML)
  u=paste('http://maps.google.com/maps/api/geocode/xml?sensor=false&address=',str)
  doc = xmlTreeParse(u, useInternal=TRUE)
  str=gsub(' ','%20',str)
  lng=getDocNodeVal(doc, "/GeocodeResponse/result/geometry/location/lat")
  lat=getDocNodeVal(doc, "/GeocodeResponse/result/geometry/location/lng")
  c(lat,lng)
}

当我运行gGeoCode() 时,我收到以下错误:

> gGeoCode("Philadelphia, PA")
failed to load external entity "http%3A//maps.google.com/maps/api/geocode/xml%3Fsensor=false&address=%20Philadelphia,%20PA"
Error: 1: failed to load external entity "http%3A//maps.google.com/maps/api/geocode/xml%3Fsensor=false&address=%20Philadelphia,%20PA"

如果我只是将带有 Philadelphia, PA 的 API url 粘贴到浏览器中,就像传递给 xmlParseTree 的字符串一样,当我下载它时,我会得到一个看起来像合法 xml 的结果。

这是代码的问题,还是我未能配置某些东西?

【问题讨论】:

  • 旁白/题外话:他可以用 str=URLencode(str) 代替 str=gsub(' ','%20',str)。我只在这里评论是因为我认为这是一个很酷的功能:)
  • 是的,一个很酷的功能。如果它起作用了! :-/
  • json 调用有效,请参阅下面的答案 :)
  • 我知道这个问题很古老,但值得补充的是,ggmap 包中现在有一个 geocode 函数可以为您完成所有这些工作。

标签: google-maps r geocoding


【解决方案1】:

您是否考虑过使用 json 调用来代替?查看您的代码,您可以实现同样的效果(您需要从 omegahat.com 安装包 RCurl 和 RJSONIO)。

复制并粘贴到 R 中:

library(RCurl)
library(RJSONIO)

construct.geocode.url <- 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))
}

gGeoCode <- function(address,verbose=FALSE) {
  if(verbose) cat(address,"\n")
  u <- construct.geocode.url(address)
  doc <- getURL(u)
  x <- fromJSON(doc,simplify = FALSE)
  if(x$status=="OK") {
    lat <- x$results[[1]]$geometry$location$lat
    lng <- x$results[[1]]$geometry$location$lng
    return(c(lat, lng))
  } else {
    return(c(NA,NA))
  }
}

以下是您如何使用上述功能:

x <- gGeoCode("Philadelphia, PA")

这就是你得到的结果。我认为在原始代码中,lat 和 lng 混淆了?但希望这是你想要的:

> x
[1]  39.95233 -75.16379

希望对小伙伴有所帮助,

托尼·布雷亚尔

【讨论】:

  • @Tony Breyal:我在 R 2.14.0 上试过这个代码。不幸的是,我收到一个错误:Error in x$results[[1]]$geometry$location$lat : $ operator is invalid for atomic vectors。我在这里做错了什么?
  • @radek 返回的 JSON 代码看起来有点变化。我更新了代码以通过将 simple=FALSE 添加到 fromJSON 来反映这一点。只要您拥有最新版本的 RJSONIO,现在应该可以工作,因为该简化参数只是在几个版本之前添加的。
  • @TonyBreyal 本着 SO 的精神,我编辑了您的答案以添加改进。如果您愿意我将其还原并将其添加为单独的答案,我可以,但我可以这样(并且您得到它的积分;-))。如果您希望我将gGeoCode 添加到我的杂项包taRifx 以便更广泛地使用,我可以这样做。您显然会被列为作者。
  • @TonyBreyal 我添加了一个版本,该版本也将地址向量作为输入。目前,我没有替换以前的版本,而是将我的版本放在帖子的末尾。
  • 好的,我的修改版本也将地址向量作为输入是下面的回复......
【解决方案2】:

此代码仅使用 XML 库即可工作

library(XML)
url = 'http://maps.googleapis.com/maps/api/geocode/xml?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=true'
doc = xmlTreeParse(url, useInternal=TRUE)
lat = as.numeric(xmlValue(getNodeSet(doc, '//location/lat')[[1]]))
lng = as.numeric(xmlValue(getNodeSet(doc, '//location/lng')[[1]]))

【讨论】:

    【解决方案3】:

    这是地理编码的另一种选择 - 它可能更容易解析:

    https://webgis.usc.edu/Services/Geocode/Default.aspx

    【讨论】:

      【解决方案4】:

      我已经修改了 Tony Breyal 解决方案,以便 gGeoCode 函数也将地址向量作为输入。有了这个版本,你不仅可以做gGeoCode("Philadelphia, PA"),还可以用这个返回值做gGeoCode(c("Philadelphia, PA","New York, NY"))

        address            lat          lng          
      1 "Philadelphia, PA" "39.952335"  "-75.163789" 
      2 "New York, NY"     "40.7143528" "-74.0059731"
      

      请注意,google maps api 的每日限制为 2,500,因此您的矢量不应太长。这是更新后的功能:

      library(RCurl)
      library(RJSONIO)
      
      construct.geocode.url <- 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))
      }
      
      gGeoCode <- function(address,verbose=FALSE) {
        require("plyr")
        if(verbose) cat(address,"\n")
        u <- aaply(address,1,construct.geocode.url)
        doc <- aaply(u,1,getURL)
        json <- alply(doc,1,fromJSON,simplify = FALSE)
        coord = laply(json,function(x) {
          if(x$status=="OK") {
            lat <- x$results[[1]]$geometry$location$lat
            lng <- x$results[[1]]$geometry$location$lng
            return(c(lat, lng))
          } else {
            return(c(NA,NA))
          }
        })
        if(length(address)>1) colnames(coord)=c("lat","lng")
        else names(coord)=c("lat","lng")
        return(data.frame(address,coord))
      }
      

      编辑:代码中的小修正,以便将 lat 和 lng 作为数值返回。

      【讨论】:

        【解决方案5】:

        我需要从geocode 获取所有返回的地址,而不仅仅是第一个地址,所以我编写了一个小函数来做到这一点。它可用于地理编码反向地理编码

        geocode <- function(address,reverse=FALSE)  {
          require("RJSONIO")
          baseURL <- "http://maps.google.com/maps/api/geocode/json?sensor=false&"
        
          # This is not necessary, 
          # because the parameter "address" accepts both formatted address and latlng
        
          conURL <- ifelse(reverse,paste0(baseURL,'latlng=',URLencode(address)),
                                          paste0(baseURL,'address=',URLencode(address)))  
          con <- url(conURL)  
          data.json <- fromJSON(paste(readLines(con), collapse=""))
          close(con) 
          status <- data.json["status"]
         if(toupper(status) == "OK"){
          t(sapply(data.json$results,function(x) {
              list(address=x$formatted_address,lat=x$geometry$location[1],
                                                         lng=x$geometry$location[2])}))
         } else { 
           warning(status)
           NULL 
         }
        }
        

        地理编码示例:

        geocode("Dupont Cir NW, Washington, DC 20036, USA")

             address                                                               lat      lng      
        [1,] "Dupont Circle Northwest, Washington, DC 20036, USA"                  38.90914 -77.04366
        [2,] "Dupont Circle, 1 Dupont Circle Northwest, Washington, DC 20036, USA" 38.90921 -77.04438
        [3,] "Washington, DC 20036, USA"                                           38.90808 -77.04061
        [4,] "Dupont Circle, Washington, DC 20036, USA"                            38.90958 -77.04344
        

        反向地理编码示例:

        请注意,地址可以是格式化地址或 latlng,reverse 参数未使用,但它包括用于将来与其他地理编码服务一起使用

        地理编码("38.910262, -77.043565")

             address                                                    lat      lng      
        [1,] "40-58 Dupont Circle Northwest, Washington, DC 20036, USA" 38.91027 -77.04357
        [2,] "Washington, DC 20036, USA"                                38.90808 -77.04061
        [3,] "Dupont Circle, Washington, DC, USA"                       38.90969 -77.04334
        [4,] "Northwest Washington, Washington, DC, USA"                38.94068 -77.06796
        [5,] "District of Columbia, USA"                                38.90598 -77.03342
        [6,] "Washington, DC, USA"                                      38.90723 -77.03646
        [7,] "United States"                                            37.09024 -95.71289
        

        【讨论】:

          【解决方案6】:

          这也可以通过我的包 googleway 和有效的 Google Maps API 密钥来完成

          library(googleway)
          
          key <- "your_api_key"
          
          df <- google_geocode("Philadelphia, PA",
                                key = key)
          
          df$results$geometry$location
          #        lat       lng
          # 1 39.95258 -75.16522
          

          以及反向地理编码

          df <- google_reverse_geocode(location = c(39.95258, -75.16522),
                                       key = key)
          
          df$results$formatted_address
          # [1] "1414 PA-611, Philadelphia, PA 19102, USA"           "15th St Station - MFL, Philadelphia, PA 19102, USA"
          # [3] "Center City West, Philadelphia, PA, USA"            "Center City, Philadelphia, PA, USA"                
          # [5] "Philadelphia, PA, USA"                              "Philadelphia, PA 19107, USA"                       
          # [7] "Philadelphia County, PA, USA"                       "Philadelphia-Camden-Wilmington, PA-NJ-DE-MD, USA"  
          # [9] "Philadelphia Metropolitan Area, USA"                "Pennsylvania, USA"                                 
          # [11] "United States" 
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-05-07
            • 1970-01-01
            • 1970-01-01
            • 2014-02-20
            相关资源
            最近更新 更多