Excel の WEBSERVICE 関数でジオコーディング

Excel の WEBSERVICE 関数を使って、住所文字列に対応する緯度経度を取得する方法を紹介します。なお、この記事で紹介する方法は [CSISシンプルジオコーディング実験](https://geocode.csis.u-tokyo.ac.jp/home/simple-geocoding/) のサービスを使用したものとなります。この方法を使用する場合には [CSISシンプルジオコーディング実験 参加規約](https://geocode.csis.u-tokyo.ac.jp/home/simple-geocoding/simple-geocoding-tems-of-use/) にしたがって、権利者の権利を侵害しないように注意してください。

WEBSERVICE 関数については前稿 [Excel の WEBSERVICE 関数で外部データ取得](http://qiita.com/frogcat/items/eddf5f8df4bba0419336) を参照してください。

# 1. シナリオ

世田谷区のサイト [公衆浴場～世田谷銭湯スタンプラリー「世田谷湯屋めぐり」を開催中！！～](http://www.city.setagaya.lg.jp/kurashi/101/116/300/d00007066.html) の最下部にある、 [公衆浴場一覧（ＣＳＶ形式 2キロバイト）](http://www.city.setagaya.lg.jp/kurashi/101/116/300/d00007066_d/fil/yokujyocms.csv) を例題とします。

CSV をダウンロードして Excel で開くとこのようなレイアウトになっているはずです。世田谷区の銭湯の一覧が住所・電話番号とともに整備されています。

![image](https://qiita-image-store.s3.amazonaws.com/0/82494/73882be6-6878-dc57-107a-31b5b3378381.png)



**B列** の住所文字列をもとに、以下のように緯度・経度を付与するのが今回の目的です。

![image](https://qiita-image-store.s3.amazonaws.com/0/82494/6c85aeca-295b-6dec-a51a-145155078e4c.png)

# 2. 手順

## ジオコーディング用の URL を設定

セル **E3** に以下の式を入力します

```URLの構築.
= "http://geocode.csis.u-tokyo.ac.jp/cgi-bin/simple_geocode.cgi?charset=UTF8&addr=" & ENCODEURL(B3)
```

![image](https://qiita-image-store.s3.amazonaws.com/0/82494/a7612671-9361-383d-8a83-6c52d4c03998.png)

入力するとセルに以下のような URL が表示されるはずです。

* [http://geocode.csis.u-tokyo.ac.jp/cgi-bin/simple_geocode.cgi?charset=UTF8&addr=池尻4-35-25](http://geocode.csis.u-tokyo.ac.jp/cgi-bin/simple_geocode.cgi?charset=UTF8&addr=%E6%B1%A0%E5%B0%BB4-35-25)

実際にこの URL にアクセスすると、以下のような XML が表示されるはずです。

![image](https://qiita-image-store.s3.amazonaws.com/0/82494/b5c4169c-ff73-f5d5-f860-56cacc76a0a1.png)

※ 結果が二件含まれていることについては後述

## XML を取得

セル **F3** に以下の式を入力します

```XMLの取得.
= WEBSERVICE(E3)
```

![image](https://qiita-image-store.s3.amazonaws.com/0/82494/d52f2cfa-71e1-e57a-2484-ca0df5f08038.png)

入力するとセルに XML 文字列が表示されるはずです。

## 緯度、経度をフィル

セル **G3** および **H3** に以下を入力します

```緯度.
=FILTERXML(F3,"//latitude")
```

```経度.
=FILTERXML(F3,"//longitude")
```

![image](https://qiita-image-store.s3.amazonaws.com/0/82494/436b4c89-dba7-1708-fe8e-b6ef3247ba90.png)

それぞれのセルに緯度経度らしき数値が設定されていたら成功です。

## コピー

**E3** ～ **H3** を選択して **E4** ～ **H4** 以下の行にコピーすることで、各行ごとにURL設定／XML取得／緯度経度フィルを行うことができます。


![image](https://qiita-image-store.s3.amazonaws.com/0/82494/fbfd3170-3fb9-6a1d-18f1-a9e8e6ab40e5.png)

※ 最終行に明らかにあやしい緯度経度が含まれている件は後述

# 3. 解説

上記の手順では3つの関数を使用しています。

**ENCODEURL(str)** 文字列を URL エンコードして返す関数です。URLを組み立てるために使っています。住所文字列は通常日本語なので、そのまま URL に使ってしまうとサーバによっては正しい結果が返ってこないためです。

**WEBSERVICE(url)**  指定の URL のコンテンツを取得する関数です。ここで実際に CSISシンプルジオコーディング実験のサーバにアクセスが発生します。

**FILTERXML(xml,xpath)** xml 文字列に対して xpath で検索を実施して返す関数です。

上記はわかりやすくするために手順を別々に記述していますが、以下のように連結して記述しても問題はありません。

```緯度(一行).
= FILTERXML(WEBSERVICE("http://geocode.csis.u-tokyo.ac.jp/cgi-bin/simple_geocode.cgi?charset=UTF8&addr=" & ENCODEURL(B3)),"//latitude")
```


```経度(一行).
= FILTERXML(WEBSERVICE("http://geocode.csis.u-tokyo.ac.jp/cgi-bin/simple_geocode.cgi?charset=UTF8&addr=" & ENCODEURL(B3)),"//longitude")
```

# 4. 精度を上げるために

ジオコーディングサービスではクエリーに対して一意に座標が確定するとは限りません。たとえば上の **池尻4-35-25** の例では、**東京都世田谷区** と **兵庫県伊丹市** の2つの結果が返ってきていることがわかります。 これは FILTERXML 関数が最初にヒットしたものを返す点、加えて、XML ファイルの最初のエントリが東京都世田谷区のものであった、という偶然によってうまくいったものです。

実際セル **B13** の **桜丘2-18-26** の事例では明らかに北方の緯度経度が付与されていることがわかります。

* [http://geocode.csis.u-tokyo.ac.jp/cgi-bin/simple_geocode.cgi?charset=UTF8&addr=桜丘2-18-26](http://geocode.csis.u-tokyo.ac.jp/cgi-bin/simple_geocode.cgi?charset=UTF8&addr=%E6%A1%9C%E4%B8%982-18-26)

この問題を回避するためには、人間による情報の補完が必要になってきます。上記の銭湯のデータは東京都世田谷区のローカルデータであることは自明なので、住所には都道府県市区町村名が省略されています。これを以下のように補完することが必要になってきます。

* [http://geocode.csis.u-tokyo.ac.jp/cgi-bin/simple_geocode.cgi?charset=UTF8&addr=東京都世田谷桜丘2-18-26](http://geocode.csis.u-tokyo.ac.jp/cgi-bin/simple_geocode.cgi?charset=UTF8&addr=%E6%9D%B1%E4%BA%AC%E9%83%BD%E4%B8%96%E7%94%B0%E8%B0%B7%E5%8C%BA%E6%A1%9C%E4%B8%982-18-26)

セルに入力する場合には、次のように文字列連結することになります。

```URLの構築(コンテクスト補完).
= "http://geocode.csis.u-tokyo.ac.jp/cgi-bin/simple_geocode.cgi?charset=UTF8&addr=" & ENCODEURL("東京都世田谷区" & B3)
```


この方法で式を更新した結果がこちらになります。緯度経度のばらつきが収まっているのがわかるかと思います。

![image](https://qiita-image-store.s3.amazonaws.com/0/82494/81e6d562-5b71-2ee5-2d10-e39942711152.png)



精度の高い変換のためには、データの各行に含まれないコンテクストにひもづく情報を適宜補完していくことが必要になってきます。


# 5. まとめ

* WEBSERVICE 関数と CSISシンプルジオコーディング実験のAPIを使うことで、Excel 上でマクロを使わずにジオコーディングを行う方法を紹介しました。
* クエリーを実行する際には都道府県市区町村名の補完を忘れずに。ローカル地名だけではバッティングが多発します。


# 追記

XML のレスポンスに2つ以上の候補が含まれているかを目視でチェックするのは大変なので、関数で発見する方法も紹介。

```フラグ.
= ISERROR(FILTERXML(F3,"//candidate[2]/latitude"))
```

XML (F3) 文字列にふたつめの candidate がない場合には TRUEが返る、というものです。

![image](https://qiita-image-store.s3.amazonaws.com/0/82494/351f46bf-40ca-9476-b881-a6f9bb4e1c49.png)