J's blog

趣味で統計•データ解析をしています

Rで(逆)ジオコーディング

今回はGoogle Geocoding APIを利用して、住所から緯度経度(及びその逆)を求めたいと思います。

APIについて

Google Geocoding APIGoogleの提供するAPIで、1日2500件までリクエストが可能です。リクエストにはいくつか形式を選択する必要があります。

必須パラメータ
  • address : 変換する住所。
  • latlng : 変換する緯度経度。ここに最も近い住所を取得する。
  • components : 特定の地域に制限した住所を指定する。詳しくは公式ページ
  • sensor : リクエストが場所センサー搭載のデバイスからのものかどうかをtrueかfalseで指定する。

上3つはどれかがあれば良いです。その他のパラメータについては省略です。

出力形式

出力には2つの形式がありますが、今回はjsonを使います。詳しい出力内容は公式ページ


ジオコーディング

以下に示すようにRコードを組みます。東京ドームの緯度経度を簡潔に求めたいと思います。

### ライブラリのロード
require(rjson)
require(RCurl)

### Queryの作成
# 変換したい住所
address <- "東京都文京区後楽1-3-61"
# UTF-8形式のQuery作成
Query <- paste0("http://maps.googleapis.com/maps/api/geocode/json?address=", address, "&sensor=false")
Query_utf8 <- URLencode(iconv(Query, "", "UTF-8"))

### URLからJSONデータを取得し、リスト形式に変換
getJSON <- fromJSON(getURL(Query_utf8))

ここまでくれば、後は欲しい情報を得たデータから探すだけです。
このデータには精度などの情報もありますが、単純に緯度経度が欲しいだけなら以下でokです。

getJSON$results[[1]]$geometry$location
## $lat
## [1] 35.70466
## 
## $lng
## [1] 139.7533
## 


逆ジオコーディング

基本的にはジオコーディングと変わりません。
Queryのパラメータをaddressの代わりにlatlngにしてあげれば、入力を緯度経度としてリクエストできます。

### ライブラリのロード
require(rjson)
require(RCurl)

### Queryの作成
# 変換したい緯度経度
latlng <- c(35.70466, 139.7533)
# UTF-8形式のQuery作成
Query <- paste0("http://maps.googleapis.com/maps/api/geocode/json?latlng=", paste(latlng, collapse = ","), "&sensor=false&language=ja&region=JP")
Query_utf8 <- URLencode(iconv(Query, "", "UTF-8"))

### URLからJSONデータを取得し、リスト形式に変換
getJSON <- fromJSON(getURL(Query_utf8))

これに関しても、詳細は省いて住所のみを取り出す場合は以下を実行すれば良いです。

getJSON$results[[1]]$formatted_address
## [1] "日本, 〒112-8562 東京都文京区後楽1丁目3−61"


関数化

どうせなので、関数にしました。
para引数には、APIに可能なパラメータを入れます。またproxy引数を設定することでproxy環境下でも実行可能にしています。

こちらがジオコーディング。住所から緯度経度に変換します。

require(rjson)
require(RCurl)
### 関数定義
GEO <- function(address, para = list(sensor = "false", language = "ja", region = "JP"), proxy = NULL) {
  curl_set <- getCurlHandle()
  if(!is.null(proxy)) curlSetOpt(.opts = list(proxy = proxy), curl = curl_set)
  parameters <- paste0("&", names(para), "=", unname(unlist(para)), collapse = "")
  GeoRequest <- iconv(paste0("http://maps.googleapis.com/maps/api/geocode/json?address=", address, parameters), "", "UTF-8")
  geodata <- vector("list", length(address))
  for(i in seq_along(address)) {
    getJSON <- fromJSON(getURL(URLencode(GeoRequest[i]), curl = curl_set))
    geodata[[i]] <- as.data.frame(getJSON$results[[1]]$geometry$location)
  }
  cbind(address, do.call("rbind", geodata))
}
### 実行
GEO(address = c("東京都文京区後楽1-3-61", "東京都墨田区押上1-1-13"))
##                  address      lat      lng
## 1 東京都文京区後楽1-3-61 35.70466 139.7533
## 2 東京都墨田区押上1-1-13 35.71004 139.8118

そしてこちらが逆ジオコーディング。緯度経度から住所に変換します。

require(rjson)
require(RCurl)
### 関数定義
rGEO <- function(latlng, para = list(sensor = "false", language = "ja", region = "JP"), proxy = NULL) {
  curl_set <- getCurlHandle()
  if(!is.null(proxy)) curlSetOpt(.opts = list(proxy = proxy), curl = curl_set)
  parameters <- paste0("&", names(para), "=", unname(unlist(para)), collapse = "")
  GeoRequest <- iconv(paste0("http://maps.googleapis.com/maps/api/geocode/json?latlng=", latlng[, 1], ",", latlng[, 2], parameters), "", "UTF-8")
  geodata <- vector("list", nrow(latlng))
  for(i in 1:nrow(latlng)) {
    getJSON <- fromJSON(getURL(URLencode(GeoRequest[i]), curl = curl_set))
    geodata[[i]] <- data.frame(address = getJSON$results[[1]]$formatted_address)
  }
  cbind(latlng, do.call("rbind", geodata))
}
### 実行
rGEO(latlng = data.frame(lat = c(35.70466, 35.71004), lon = c(139.7533, 139.8118)))
##        lat      lon                                        address
## 1 35.70466 139.7533 日本, 〒112-8562 東京都文京区後楽1丁目3−61
## 2 35.71004 139.8118            日本, 東京都墨田区業平2丁目18−1