Kesin's diary

プログラミングの記事がメインです

Wikipediaから位置情報のデータベースを作る

Wikipediaの記事から位置情報をマイニングするスクリプトをPythonで作りました!
Wikipediaの建物や場所の記事のタイトル右端にある位置情報と情報ボックス内の位置情報から抽出しています。Wikipediaは日々更新されているので、2012年にオープンしたばかりのスカイツリーダイバーシティのような情報も抽出することができます。
抽出した結果はこんな感じのデータになります

タイトル|カテゴリ|緯度|経度

両国国技館|landmark|35.6969166667|139.793527778
シカゴ||41.9|-87.65
スーパーカミオカンデ||36.4166666667|137.3
アメリカ航空宇宙局|landmark|38.8830555556|-77.0163888889
関西国際空港||34.4272222222|135.243888889
任天堂|landmark|34.9697222222|135.756194444
佐鳴湖||34.7105555556|137.690277778
IBM|landmark|41.1080555556|-73.72

抽出結果のcsvとスクリプトをgithubにアップしました
https://github.com/Kesin11/wikipedia_geomining
csvをそのまま眺めても多くの人は面白くないと思うので、それを地図にマッピングしたウェブアプリも公開しました。一応スマホ向けに作ってあります。(Androidは動作確認していません)
http://location-tweet.herokuapp.com
(こちらのアプリの紹介もいずれ書く予定です)
ただマッピングするだけだと面白くないので、ピンをタップするとその場所に関するツイートを見られるようにしてあります。自分が良く知ってる場所のツイートを見てみると結構面白かったりします。

きっかけ

自分の大学院での研究は自然言語処理と文書検索なのですが、少し横道にそれてWikipedia系の論文を読んでる時にこんな論文を見つけました

Wikipediaから場所と時間の関係をマイニングしようという論文で、面白そうなので抽出した結果を見てみたかったのですが残念ながらデータは公開されてないようです。Wikipedia系の研究で作成したデータを公開してるところってほとんどないような気がします。
誰も公開してくれないなら自分でやるしかない!ということで同じようにWikipediaから位置情報のマイニングして公開してみようと思いました。

正規表現で楽勝だと思ってた時期がありました

Wikipediaは月毎にその巨大なデータベースのダンプデータを公開してるので、Wikipediaデータを活用するときにはこれを利用します。
この巨大なXMLから正規表現で位置情報っぽいものを抽出すればできるよね、簡単簡単!と最初は思っていましたが、
Wikipediaの中身ってめちゃくちゃ汚い
という事がわかりました・・・。Wikipediaは専用の記法を用いて編集するようなのですが、これが多少適当に書いてもちゃんと表示されるようになってるみたいです。そのおかげで位置情報の書き方も人によって統一されておらずバラバラになってしまってます。自分が調べただけでこれぐらい色々な書き方が存在してました

Coord|35.675366|139.7511182
Coord|48.8530|N|2.3498|E|
Coord|44|N|35|E|
Coord|38|49|43.10|N|121|11|36.30|E|
Coord|09|08|00|S|159|49|00|E|
Coord|37|37|08|N|122|22|30|W|

|緯度度 = 51.922832 |緯度分 = |緯度秒 = |N(北緯)及びS(南緯) = N
|経度度 = 4.479606 |経度分 = |経度秒 = |E(東経)及びW(西経) = E

| 緯度度 = 35 | 緯度分 = 37 | 緯度秒 = 48.57 | N(北緯)及びS(南緯) = N
| 経度度 = 139 |経度分 = 47 | 経度秒 = 37.47 | E(東経)及びW(西経) = E

ここに出したのは一例です。実際のパターンはもう少し多く、さらにスペースがところどころに挿入されてたりしていました。おそらく把握しきれていないパターンもまだまだあると思います。勘弁して(;´д`)

地図って難しい

さて、実は上で示した座標の表記のうちいくつかは正規表現で抜き出すだけではGoogleMapなどで使うことはできません。正しく変換してやらないと全く異なる場所を示してしまいます。
まず、地球上での座標を表す緯度経度には10進数表記と60進数表記という2種類が存在するのですがGoogleMapなどで使われるのは10進表記になります。上で示した例だと

Coord|35.675366|139.7511182
|緯度度 = 51.922832 |緯度分 = |緯度秒 = |N(北緯)及びS(南緯) = N
|経度度 = 4.479606 |経度分 = |経度秒 = |E(東経)及びW(西経) = E

は10進なのでこのまま使用してOKです。逆に60進の

Coord|38|49|43.10|N|121|11|36.30|E|
| 緯度度 = 35 | 緯度分 = 37 | 緯度秒 = 48.57 | N(北緯)及びS(南緯) = N
| 経度度 = 139 |経度分 = 47 | 経度秒 = 37.47 | E(東経)及びW(西経) = E

などは正規表現で抽出した後に10進に変換する必要があります。60進→10進の変換はググればたくさんでてきますが、私はこのサイトを参考にしました
次に緯度と経度における北緯・南緯、東経・西経の変換です。60進表記ならばNSEWを付けるだけですが、10進表記だと南緯と西経はマイナスの値に変換する必要があります。
以上の2つの変換が必要な例として60進, 南緯・西経の座標を10進に変換するとこのようになります

Coord|09|08|00|S|159|49|00|E| → (-9.133333, 159.816667)

やることはそれほど難しくないのですが、条件分岐なんかを考えるのが結構めんどくさかったです。このあたりの処理もgithubにアップしたコードに含まれているので気になる方は参考にしてみてください。

ちなみに緯度経度で座標を表すときに測地系というものが問題になることがありますが、Wikipedia世界測地系WGS84で書くことが推奨されているので問題は無いと思われます。測地系について詳しく知りたい方はWikipedia:測地系にも記事があります。

テストコードって素晴らしい

このように色々な座標表記がちゃんと正しく抽出、変換されてるかを確かめるために初めてテストコードというものを書いてみました。テストコードを書くと内部処理を安心してガンガン書き換えられるから素晴らしいですね。
今回のスクリプトで対応している座標表記は全てテストコードが用意してあります。気になる方は確認してみてください。

応用アイディア

作成したデータからデータベースを作ると簡易的ですが自前でジオコーディング、逆ジオコーディングができます。もちろん精度とデータ量ではYahooやGoogleとは勝負になりませんが、自前のデータベースならAPIの制限もありませんので大規模なデータ解析に使えるのではないかと考えています。
個人的にテキスト→座標の変換は使えそうだと考えていて、最近ネットで見つけた以下の論文が面白そうです

両方ともツイートに含まれる位置情報から現実社会で起こった"イベント"を発見しようという研究ですが、位置情報付きのツイートは絶対数が少ないことから今後の課題としてツイートに付加されてる位置情報に頼らずテキストから位置情報を得ることを挙げています。
新しい情報が追加され続け、正式な名称(リダイレクトで俗称も)が登録されているWikipediaのデータはこの分野の解析と相性が良いと考えています。

これから

  • 対応できる座標表記の増加
    • まだまだ対応しきれてない記事、誤ってる記事がたくさんあるはずなので気がついたものから修正していく予定です
  • リダイレクト情報の活用
    • 現時点でこのデータの最大の欠点は地名や場所の俗称に対応できていないことです。分かりやすい例を挙げると、"ビッグサイト"という名称は登録されていないので代わりに"東京国際展示場"を使う必要があります。リダイレクト情報を活用することでビッグサイト=東京国際展示場の対応が取れるはずです。