LINK:[GoogleEarthとR][ShapeFileライブラリ][kmlラボ][空間的なデータの分析][Rでジオコーディング][RでGPS]


目次


論文引用・書籍等に引用する場合の著作権についての連絡>>okinawa


目的

GoogleMapやGoogleEarthのおかげで、最近ジオコーディングという言葉がインターネットで頻繁に使われだしている。
ジオコーディングとは簡単に言えば、住所や郵便番号情報から、緯度・経度の位置情報に変換する技術のことであるが、WebAPIを利用したものや完全にフリーで配布されているもの、有償でかなりお高いものなど多々存在する。
最近になって勢力を拡大してきているのが、WebAPIを利用したジオコーダー(ジオコーディング用のプログラム)で、もっとも有名なのがGoogleMapAPIに含まれているジオコーダーである。
また、国から「街区レベル位置参照情報ダウンロードサービス」が開始されたり、郵便番号データがダウンロードできるようになってからは、これらのデータを組み合わせてジオコーディングを行うものが出てきている。

ここでは、ジオコーディングの情報を収集するとともに、Rを用いたジオコーディングについて検証していくこととする。
基本的には、Rのみでジオコーディングを可能にすることが目標である。
GoogleEarthのジオコーディングはすばらしいが、なにしろ変換スピードが遅いのがネックである。(ちなみにGoogleMapAPIの日本版ジオコーディング部分はゼンリンのものが使われていると言われている。)

(注意)
ジオコーディングを業務用に利用するならば、ジオコーディングする前に「住所情報の正規化」という作業が必要になることが多い。
つまり、業務で入力されている住所がきちんとした住所になっていない(たとえば、**市を端折って市内と書いてあったりする)ので、まずきちんとした住所になるように文字列を整える必要がある。
そういう意味では、文書としての住所を解析して正規化する文書解析という分野の知識も必要になる。

利用するパッケージ

RCurl
XML
rjson
SSOAP

ツールとデータ

ジオコーディングツール
無償版:
[GoogleMapAPI] http://www.google.com/apis/maps/documentation/
[CSVアドレスマッチングサービス] http://www.tkl.iis.u-tokyo.ac.jp/~sagara/geocode/overview.html
[gコンテンツ流通推進協議会] http://www.g-contents.jp/
[geocoder.ja] http://www.postlbs.org/
[JNS住所認識システム]http://nlftp.mlit.go.jp/isj/jns_agreement.html

有償版:
[jasminesoft住所正規化コンバータ] http://anorm.jp/
[アルプス社] http://www.alpsmap.jp/mapinfo/data/geocoding/

ジオコーディング用データ
[街区レベル位置参照情報ダウンロードサービス] http://nlftp.mlit.go.jp/isj/
[郵便番号ダウンロード] http://www.post.japanpost.jp/zipcode/download.html

文字列検索アルゴリズム
[1]http://fujimiya.net/?Boyer-Moore%20Fast%20String%20Searching%20Algorithm
[2]http://d.hatena.ne.jp/siokoshou/20060325
[3]http://www.dbsj.org/Japanese/DBSJLetters/vol1/no1/ronbun/Sagara.pdf

日本語形態素解析
[1]YahooJapan:http://developer.yahoo.co.jp/jlp/MAService/V1/parse.html

RCODE

1.街区レベル位置参照情報データを利用した簡易ジオコーディング

事前に街区レベル位置参照情報ダウンロードサービスから対象となるデータをダウンロードして解凍してください。
下記の例は、沖縄県全域データを利用したものです。

x<- read.csv("c:\\47_2006.csv")
y<- paste(x$都道府県名,x$市区町村名,x$大字.町丁目,x$街区符号.地番,sep="")
target<- "沖縄県島尻郡八重瀬町後原566"
xnum<-pmatch(target,y)
z<-x[xnum,8:9]
print(z)
 > print(z)
          緯度     経度
95660 26.14762 127.7343

(注)まったく役に立ちませんが、とりあえず住所完全一致でのジオコーディング。一度変数に入れてしまえば、3行目以降のみで可能。さて、住所の正規化をどうするか・・・。

options(digits=10)
target<- "浦添市当山二丁目"
xnum<-grep(target,y)
z<-x[xnum,1:9]
mean(z[8:9])
> mean(z[8:9])
      緯度        経度 
26.2515489 127.7348568 

(注)grepだと結構いい感じであいまい検索してくれる。

2.GoogleEarthとRのコメント欄にXMLパッケージとGoogleEarthを利用したコードが岡田先生により掲載されています。

1)GoogleEarthを利用したジオコーディング:

# hospdは $Addrに住所, $Nameに名前が入っているデータフレーム。
library(XML)
makePlacemark <- function(x) {
  addr=xmlNode("address", xmlTextNode(hospd$Addr[x]));
  name=xmlNode("name", xmlTextNode(hospd$Name[x]));
  return(xmlNode("Placemark",addr,name));
}
addrList <- lapply(1:nrow(hospd), makePlacemark)
d<-xmlNode("Document")
for(i in 1:length(addrList)) { d$children[[i]] <- addrList[[i]] }
p <- xmlNode("kml", d)
sink(file("hospd.kml",encoding="utf-8",open="w")) #なかまさんのものをくっつけました
print(p)
sink()

出力されたhospd.kmlをGoogleEarthに読み込むと、GEが自動的にジオコーディングして表示してくれます。(遅いです)想像ですが、GoogkeMapAPIのジオコーディングを使っていると思いますので、ゼンリンのデータを用いた独自解析のものでしょう。

2)GE上で「情報を取得」などを行ってから再びKMLに書き出すと、coordinatesエレメントがついたKMLになりますが、それを再度Rにとりこむ関数:

placemark2GeoData <- function(rootNode) {
	findDoc <- function(x) {
		if(xmlName(x) == "Document") {
			return(x)
		}
		for(m in xmlChildren(x)) {
			n <- findDoc(m)
			if(!is.null(n)) {
				return(n)
			}
		}
		return(NULL)
	}
	ininode <- findDoc(rootNode)
	namev <- vector()
	addrv <- vector()
	longv <- vector()
	lattv <- vector()
	for(node in xmlChildren(ininode)) {
		if(xmlName(node) == "Placemark") { 
			n <- NULL
			a <- NULL
			gd <- NULL
			for(i in xmlChildren(node)) {
				if(xmlName(i) == "name") {
					n <- xmlValue(i$children[[1]])
				} else if(xmlName(i) == "address") {
					a <- xmlValue(i$children[[1]])
				} else if(xmlName(i) == "Point") {
					gd <-   strsplit(xmlValue(i$children[[1]]$children[[1]]),",")[[1]]
				} 
			}
			if(!(is.null(gd) | is.null(a) | is.null(n)) ) {
				namev <- append(namev, n)
				addrv <- append(addrv, a)
				longv <- append(longv, gd[1])
				lattv <- append(lattv, gd[2])
			}
		}
	}
	return(data.frame(Name=namev, Address=addrv, Longitude=longv,  Lattitude=lattv))
}

こんな風に使います

doc <- xmlTreeParse("ih.kml")
hospg <- placemark2GeoData(xmlRoot(doc)) # これでLong, Latが入ったデータフレームができる
merge(hospg,hospd,by="Name")

3.GoogleMapAPIのGeoCording(HTTP Request)を利用してジオコーディング

##GoogleMapAPIを用いたジオコーディング
address<-"沖縄県那覇市久米2丁目4番14号"
returnform<-"xml"#xmlorjson
key<-"ABQIAAAA7Qa-RE_JYtVliR9OTauOexScAlgT1OMB91Iojh4cvnPDirRWVBRkKoWJQNoMN19LbzuRx7z0aIWHTQ"#ここはGoogleAPIでもらったkeyを登録
text1<-"http://maps.google.com/maps/geo?q="
text2<-"&output="
text3<-"&key="
savefile<-"c:\\geocode.xml"
EncodeAddress<-paste(c("",charToRaw(iconv(address,"CP932","UTF-8"))),collapse="%")#なかまさんのURLエンコード
URLText<-paste(text1,EncodeAddress,text2,returnform,text3,key,sep="")
download.file(URLText,savefile)

で、c:直下にgeocode.xmlで落ちてきます。returnform<-"xml"#xmlorjsonのところで、返り値のフォームを指定してます。(XML形式かJSON形式か)xmlのデコードは次の機会に・・・。

4.YahooMapAPIを利用してジオコーディング

##YahooMapAPIを用いたジオコーディング
address<-"沖縄県那覇市久米2丁目4番14号"
#returnform<-"xml"#xmlorjson
appid<-"YahooDemo"
text1<-"http://api.map.yahoo.co.jp/LocalSearchService/V1/LocalSearch?"
text2<-"&p="
text3<-"appid="
savefile<-"c:\\geocode.xml"
EncodeAddress<-paste(c("",charToRaw(iconv(address,"CP932","UTF-8"))),collapse="%")#なかまさんのURLエンコード
URLText<-paste(text1,text3,appid,text2,EncodeAddress,sep="")
download.file(URLText,savefile)

で、c:直下にgeocode.xmlで落ちてきます。xml構造はYahooの方がきれいかも。

5.RCurlを使う方法( 質問、それって)

library(RCurl) # <=  バイナリは腐ってる事もあります
addr<-"石川県金沢市広坂1丁目1ー1"
encaddr<-paste(c("",charToRaw(iconv(addr,"","UTF8"))),collapse="%")
url<-paste("http://maps.google.com/maps?q=",encaddr,"&output=kml",sep="")
kml<-iconv(getURL(url),"UTF8","")  # iconvの""はカレントのエンコーディングになります

といっしょ?

addr<-"石川県金沢市広坂1丁目1ー1"
encaddr<-paste(c("",charToRaw(iconv(addr,"","UTF8"))),collapse="%")
url<-paste("http://maps.google.com/maps?q=",encaddr,"&output=kml",sep="")
con<-url(url,encoding="UTF8")
kml<-readLines(con,warn=F)

でもいいか. 保存するなら

con<-file("hoge.kml",open="w",encoding="UTF8")
writeLines(kml,con)
close(con)

(注:okinawa)RCurlはBioConductorからインストールできます。

6.RCurlでまとめてジオコーディング(なかまさん)

# ライセンスはGPL!!
ken<-c("富山市新総曲輪1番7号","金沢市鞍月1丁目1番地","福井市大手3丁目17の1")
library(XML)
library(RCurl)
encaddr<-function(x){sapply(x,function(x)paste(c("",charToRaw(iconv(x,"","UTF8"))),collapse="%"))}
makeurl<-function(x)sapply(x,function(x)paste("http://maps.google.com/maps?q=",x,"&output=kml",sep=""))
kmls<-getURIAsynchronous(makeurl(encaddr(ken)))

# encode強制(utf-8の人は何も考えなくて良い)
kmls<-sapply(kmls,function(x)iconv(x,"UTF-8"))
kmls<-sapply(kmls,function(x)gsub("encoding=\\\"UTF-8\\\"",
                                  paste("encoding=\\\"",
                                        localeToCharset(),
                                        "\\\"",
                                        sep=""),x))

#nsが見当たらないのでさくっと消す
kmls<-sapply(kmls,function(x)gsub("<kml xmlns=\\\"http:\\/\\/earth.google.com\\/kml\\/2.0\\\">",
                                  "<kml>",
                                  x))

docs<-sapply(kmls,function(x)xmlTreeParse(x,useInternalNodes=T)) # 内部形式はUTF-8

sapply(docs,function(x)xpathApply(x,"//longitude",xmlValue))
sapply(docs,function(x)xpathApply(x,"//latitude",xmlValue))
sapply(docs,function(x)xpathApply(x,"//coordinates",xmlValue))
sapply(docs,function(x)iconv(xpathApply(x,"//name",xmlValue),"UTF8")) # 日本語はこうして
sapply(docs,free) # 開放

7.Yahoo日本語形態素解析APIを利用した住所の形態素解析

library(RCurl) 
addr<-"沖縄県那覇市久米2丁目4番14号JB-NAHAビル8階"
encaddr<-paste(c("",charToRaw(iconv(addr,"","UTF-8"))),collapse="%")
url<-paste("http://api.jlp.yahoo.co.jp/MAService/V1/parse?appid=YahooDemo&results=ma,uniq&uniq_filter=9|10&sentence=",encaddr,sep="")
kml<-iconv(getURL(url),"UTF-8","")  # iconvの""はカレントのエンコーディングになります
print(kml)

実行結果(見やすいように整形してあります)

<?xml version=\"1.0\" encoding=\"UTF-8\" ?>
<ResultSet xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"urn:yahoo:jp:jlp\" xsi:schemaLocation=\"urn:yahoo:jp:jlp http://api.jlp.yahoo.co.jp/MAService/V1/parseResponse.xsd\">
<ma_result><total_count>13</total_count>
<filtered_count>13</filtered_count>
<word_list>
<word><surface>沖縄県</surface><reading>おきなわけん</reading><pos>名詞</pos></word>
<word><surface>那覇市</surface><reading>なはし</reading><pos>名詞</pos></word>
<word><surface>久米</surface><reading>くめ</reading><pos>名詞</pos></word>
<word><surface>2</surface><reading>2</reading><pos>名詞</pos></word>
<word><surface>丁目</surface><reading>ちょうめ</reading><pos>接尾辞</pos></word>
<word><surface>4</surface><reading>4</reading><pos>名詞</pos></word>
<word><surface>番</surface><reading>ばん</reading><pos>接尾辞</pos></word>
<word><surface>14</surface><reading>14</reading><pos>名詞</pos></word>
<word><surface>号</surface><reading>ごう</reading><pos>接尾辞</pos></word>
<word><surface>JB-NAHA</surface><reading>JB-NAHA</reading><pos>名詞</pos></word>
<word><surface>ビル</surface><reading>びる</reading><pos>名詞</pos></word>
<word><surface>8</surface><reading>8</reading><pos>名詞</pos></word>
<word><surface>階</surface><reading>かい</reading><pos>接尾辞</pos></word>
</word_list>
</ma_result><uniq_result><total_count>13</total_count>

住所もきちんと分解してくれてるようですね。更に、指定した名詞・動詞をフィルタリングして抽出してきてます。

<filtered_count>9</filtered_count>
<word_list>
<word><count>1</count><surface>JB-NAHA</surface><reading/><pos>名詞</pos></word>
<word><count>1</count><surface>ビル</surface><reading/><pos>名詞</pos></word>
<word><count>1</count><surface>久米</surface><reading/><pos>名詞</pos></word>
<word><count>1</count><surface>沖縄県</surface><reading/><pos>名詞</pos></word>
<word><count>1</count><surface>那覇市</surface><reading/><pos>名詞</pos></word>
<word><count>1</count><surface>14</surface><reading/><pos>名詞</pos></word>
<word><count>1</count><surface>2</surface><reading/><pos>名詞</pos></word>
<word><count>1</count><surface>4</surface><reading/><pos>名詞</pos></word>
<word><count>1</count><surface>8</surface><reading/><pos>名詞</pos></word>
</word_list></uniq_result></ResultSet>

並びはどうやって決めてるんだろう?

8.GoogleMapAPIを用いた逆ジオコーディング

##GoogleMapAPIを用いた逆ジオコーディング
URLText<-"http://maps.google.com/maps/geo?oe=utf-8&ll=35.620519%2C139.438892&key=ABQIAAAA7Qa-RE_JYtVliR9OTauOexScAlgT1OMB91Iojh4cvnPDirRWVBRkKoWJQNoMN19LbzuRx7z0aIWHTQ&output=json&callback=gmap"
savefile<-"c:\\geocode.xml"
download.file(URLText,savefile)

コメント欄


[1] 0.597 0.103 4.385 0.000 0.000 #光100M 100件
[1] 0.949 0.222 3.303 0.000 0.000 #光100M 200件
[1] 1.400 0.193 3.712 0.000 0.000 #光100M 300件
[1] 1.833 0.229 3.030 0.000 0.000 #光100M 400件
[1] 2.211 0.182 2.791 0.000 0.000 #光100M 500件

アクセス数:

34436 人


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2023-03-25 (土) 11:19:16