22
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

無償ジオコーディングの比較

Posted at

はじめに

仕事でジオコーディングをすることが多々あるため、プロバイダー毎のジオコーディングを整理したいと思い、本記事を執筆します。
ジオコーディングとは、住所から緯度経度情報に変換する技術のことです。逆に、緯度経度情報から住所に変換することは、リバースジオコーディングや逆ジオコーディングといいます。
私がよくやるのは、ジオコーディングの方で、住所情報をQGIS等のGISソフト上に載せたいときなどに、使います。
順序としては下記の通りです。

  1. 当該情報(住所を含んだ不動産情報等)をインターネット上か取得します(スクレイピング)(データ形式はCSV)
  2. 取得した情報(住所)に対して、ジオコーディングを行い、緯度経度情報に変換します(データ形式はCSV)
  3. QGISの「CSVテキストレイヤの追加」を行い、QGIS上に表示します。

しかし、ジオコーディングは色々なプロバイダーが提供しているので、どのプロバイダーを使えばいいのかよくわかりません。
そこで、本記事ではプロバイダー別に、ジオコーディングを比較していきたいと思います。

#比較するジオコーディングのプロバイダ
ジオコーディングの関数は色々ありますが、今回は本サイトで紹介されているモジュールを使います。Pythonで使用可能です。

本モジュールで使用可能なプロバイダを下記にまとめました。

# プロバイダ名 APIkeyが必要か不要か 備考
1 ArcGIS 不要
2 Baidu 必要 住所情報ではなく、IPアドレスを元にジオコーディングする。リクエスト数は100万回/日
3 Bing 必要
4 CanadaPost 必要
5 FreeGeoIP.net 不要 リクエスト数は1万回/1時間
6 Gaode 必要 リクエスト数は2000回/日
7 GeocodeFarm 不要 リクエスト数は250回/日
8 Geocoder.ca 不要 カナダと米国のジオコーダー
9 GeoNames 必要
10 GeoOttawa 不要
11 Google 必要
12 HERE 必要
13 IP Info.io 不要 住所情報ではなく、IPアドレスを元にジオコーディングする
14 LocationIQ 必要 OpenStreetMapと完全互換性
15 Mapbox 不要
16 MapQuest 必要
17 MaxMind 不要 住所情報ではなく、IPアドレスを元にジオコーディングする
18 Opencage 必要
19 OpenStreetMap 不要
20 Tamu 必要
21 TomTom 必要
22 What3Words 不要 緯度経度情報ではなく、3mX3m四方のグローバルグリッドを指す一意の3ワードを返す
23 Yahoo 不要 YOLPとは違うサービスらしい。Yahoo Place Finderというサービス
24 Yandex 不要 ロシア最大のインターネット企業が提供するサービス
25 TGOS 必要 台湾の公式地図サービス

APIkeyが必要なものはいちいち登録するのも面倒なため、不要のサービスを比較してみます。
また、IPアドレスからのジオコーディングは使わないため、こちらも除外します。
それと、What3Wordsも除外します。

不要のサービスは以下の通りです。
また、YahooとYandexは使えなくなっていたので、除外します。

# プロバイダ名 APIkeyが必要か不要か 備考
1 ArcGIS 不要
2 GeocodeFarm 不要 リクエスト数は250回/日
3 Geocoder.ca 不要 カナダと米国のジオコーダー
4 GeoOttawa 不要
5 Mapbox 不要
6 OpenStreetMap 不要

9のサービスを対象にどの程度の制度でジオコーディングができるのか実施します。

#住所の細かさ
住所を細かくしたとき、どの程度の細かさまで対応できるのか試してみたいと思います。
対象とする住所は、下記の6つにします

  1. 日本
  2. 東京都
  3. 東京都足立区
  4. 東京都足立区北千住
  5. 東京都足立区北千住3
  6. 東京都足立区北千住3-92

#プログラム
TypeErrorとかそのあたりは例外処理でとりあえず飛ばしています。
多分、サービス停止シていたりするものも有るかと思いますが、そのあたりは後で調査するとしてまずは緯度経度を返してくれるかどうかだけをみます。

main.py
import geocoder
import pandas as pd
import numpy as np

value = ["日本","東京都","東京都足立区","東京都足立区北千住","東京都足立区北千住","東京都足立区北千住3","東京都足立区北千住3-92"]
provider = ["ArcGIS","GeocodeFarm","Geocoder.ca","GeoOttawa","Mapbox","OpenStreetMap"]

cols = ['住所情報','プロバイダ','緯度','経度']
df = pd.DataFrame(index=[],columns=cols)

for i in range(0,len(value)):
    print("" + value[i] + "の場合")
    
    for j , name in enumerate(provider):
        print("-" + name + "の場合")
        
        #ArcGISの場合
        if(j == 0):
            try:
                latlon = geocoder.arcgis(value[i])
                latlon_lat = latlon.json["lat"]
                latlon_lng = latlon.json["lng"]

                print(latlon)
                print(latlon.json["lng"])
                print(latlon.json["lat"])
            
        
            except ValueError:
                print("ValueErrorが発生")
                latlon_lat = "ValueError"
                latlon_lng = "ValueError"
 
            except TypeError:
                print("TypeErrorが発生")
                latlon_lat = "TypeError"
                latlon_lng = "TypeError"
                
            except KeyError:
                print("KeyError")
                latlon_lat = "KeyError"
                latlon_lng = "KeyError"
                
            
            record = pd.Series([value[i],
                                   name,
                                   latlon_lat,
                                   latlon_lng],
                                   index=df.columns)
            df = df.append(record,ignore_index=True)
          

        #GeocodeFram場合
        if(j == 1):
            try:
                latlon = geocoder.geocodefarm(value[i])
                latlon_lat = latlon.json["lat"]
                latlon_lng = latlon.json["lng"]

                print(latlon)
                print(latlon.json["lng"])
                print(latlon.json["lat"])
            
            except ValueError:
                print("ValueErrorが発生")
                latlon_lat = "ValueError"
                latlon_lng = "ValueError"
 
            except TypeError:
                print("TypeErrorが発生")
                latlon_lat = "TypeError"
                latlon_lng = "TypeError"
                
            except KeyError:
                print("KeyError")
                latlon_lat = "KeyError"
                latlon_lng = "KeyError"
            
            record = pd.Series([value[i],
                                   name,
                                   latlon_lat,
                                   latlon_lng],
                                   index=df.columns)
            df = df.append(record,ignore_index=True)
      
        #Geocoder.ca場合
        if(j == 2):
            try:
                latlon = geocoder.geolytica(value[i])
                #print(latlon.json)
                latlon_lat = latlon.json["lat"]
                latlon_lng = latlon.json["lng"]

                print(latlon)
                print(latlon.json["lng"])
                print(latlon.json["lat"])
            
            except ValueError:
                print("ValueErrorが発生")
                latlon_lat = "ValueError"
                latlon_lng = "ValueError"
 
            except TypeError:
                print("TypeErrorが発生")
                latlon_lat = "TypeError"
                latlon_lng = "TypeError"
                
            except KeyError:
                print("KeyError")
                latlon_lat = "KeyError"
                latlon_lng = "KeyError"
            
            record = pd.Series([value[i],
                                   name,
                                   latlon_lat,
                                   latlon_lng],
                                   index=df.columns)
            df = df.append(record,ignore_index=True)


            
            
        #GeoOttawa場合
        if(j == 3):
            try:
                latlon = geocoder.ottawa(value[i])
                #print(latlon.json)
                latlon_lat = latlon.json["lat"]
                latlon_lng = latlon.json["lng"]

                print(latlon)
                print(latlon.json["lng"])
                print(latlon.json["lat"])
            
            except ValueError:
                print("ValueErrorが発生")
                latlon_lat = "ValueError"
                latlon_lng = "ValueError"
 
            except TypeError:
                print("TypeErrorが発生")
                latlon_lat = "TypeError"
                latlon_lng = "TypeError"
                
            except KeyError:
                print("KeyError")
                latlon_lat = "KeyError"
                latlon_lng = "KeyError"
            
            record = pd.Series([value[i],
                                   name,
                                   latlon_lat,
                                   latlon_lng],
                                   index=df.columns)
            df = df.append(record,ignore_index=True)

            
            
        
        #GMapbox場合
        if(j == 4):
            try:
                latlon = geocoder.mapbox(value[i])
                #print(latlon.json)
                latlon_lat = latlon.json["lat"]
                latlon_lng = latlon.json["lng"]

                print(latlon)
                print(latlon.json["lng"])
                print(latlon.json["lat"])
            
            except ValueError:
                print("ValueErrorが発生")
                latlon_lat = "ValueError"
                latlon_lng = "ValueError"
 
            except TypeError:
                print("TypeErrorが発生")
                latlon_lat = "TypeError"
                latlon_lng = "TypeError"
                
            except KeyError:
                print("KeyError")
                latlon_lat = "KeyError"
                latlon_lng = "KeyError"
            
            record = pd.Series([value[i],
                                   name,
                                   latlon_lat,
                                   latlon_lng],
                                   index=df.columns)
            df = df.append(record,ignore_index=True)

            
            
            
        #OpenStreetMaps場合
        if(j == 5):
            try:
                latlon = geocoder.osm(value[i])
                #print(latlon.json)
                latlon_lat = latlon.json["lat"]
                latlon_lng = latlon.json["lng"]

                print(latlon)
                print(latlon.json["lng"])
                print(latlon.json["lat"])
            
            except ValueError:
                print("ValueErrorが発生")
                latlon_lat = "ValueError"
                latlon_lng = "ValueError"
 
            except TypeError:
                print("TypeErrorが発生")
                latlon_lat = "TypeError"
                latlon_lng = "TypeError"
                
            except KeyError:
                print("KeyError")
                latlon_lat = "KeyError"
                latlon_lng = "KeyError"
            
            record = pd.Series([value[i],
                                   name,
                                   latlon_lat,
                                   latlon_lng],
                                   index=df.columns)
            df = df.append(record,ignore_index=True)
print("finish!")

#出力結果
出力結果は以下の通りです。

住所情報 プロバイダ 緯度 経度
0 日本 ArcGIS 36.655226998000046 139.27149500000007
1 日本 GeocodeFarm TypeError TypeError
2 日本 Geocoder.ca KeyError KeyError
3 日本 GeoOttawa TypeError TypeError
4 日本 Mapbox ValueError ValueError
5 日本 OpenStreetMap 36.5748441 139.2394179
6 東京都 ArcGIS 35.68945633200008 139.69171608500005
7 東京都 GeocodeFarm TypeError TypeError
8 東京都 Geocoder.ca KeyError KeyError
9 東京都 GeoOttawa TypeError TypeError
10 東京都 Mapbox ValueError ValueError
11 東京都 OpenStreetMap 35.6828387 139.7594549
12 東京都足立区 ArcGIS 35.77481105600003 139.80453694100004
13 東京都足立区 GeocodeFarm TypeError TypeError
14 東京都足立区 Geocoder.ca KeyError KeyError
15 東京都足立区 GeoOttawa TypeError TypeError
16 東京都足立区 Mapbox ValueError ValueError
17 東京都足立区 OpenStreetMap 35.783703 139.795319
18 東京都足立区北千住 ArcGIS 35.77481105600003 139.80453694100004
19 東京都足立区北千住 GeocodeFarm TypeError TypeError
20 東京都足立区北千住 Geocoder.ca KeyError KeyError
21 東京都足立区北千住 GeoOttawa TypeError TypeError
22 東京都足立区北千住 Mapbox ValueError ValueError
23 東京都足立区北千住 OpenStreetMap 35.7496486 139.8046045
24 東京都足立区北千住 ArcGIS 35.77481105600003 139.80453694100004
25 東京都足立区北千住 GeocodeFarm TypeError TypeError
26 東京都足立区北千住 Geocoder.ca KeyError KeyError
27 東京都足立区北千住 GeoOttawa TypeError TypeError
28 東京都足立区北千住 Mapbox ValueError ValueError
29 東京都足立区北千住 OpenStreetMap 35.7496486 139.8046045
30 東京都足立区北千住3 ArcGIS 35.77481105600003 139.80453694100004
31 東京都足立区北千住3 GeocodeFarm TypeError TypeError
32 東京都足立区北千住3 Geocoder.ca KeyError KeyError
33 東京都足立区北千住3 GeoOttawa TypeError TypeError
34 東京都足立区北千住3 Mapbox ValueError ValueError
35 東京都足立区北千住3 OpenStreetMap TypeError TypeError
36 東京都足立区北千住3-92 ArcGIS 35.77481105600003 139.80453694100004
37 東京都足立区北千住3-92 GeocodeFarm 48.9505233764802 2.29213690757375
38 東京都足立区北千住3-92 Geocoder.ca KeyError KeyError
39 東京都足立区北千住3-92 GeoOttawa TypeError TypeError
40 東京都足立区北千住3-92 Mapbox ValueError ValueError
41 東京都足立区北千住3-92 OpenStreetMap TypeError TypeError

ほぼほぼエラーですね。。。
整理したのは下記です。

住所情報 プロバイダ 緯度 経度
0 日本 ArcGIS 36.655227 139.271495
5 日本 OpenStreetMap 36.5748441 139.2394179
6 東京都 ArcGIS 35.68945633 139.6917161
11 東京都 OpenStreetMap 35.6828387 139.7594549
12 東京都足立区 ArcGIS 35.77481106 139.8045369
17 東京都足立区 OpenStreetMap 35.783703 139.795319
18 東京都足立区北千住 ArcGIS 35.77481106 139.8045369
23 東京都足立区北千住 OpenStreetMap 35.7496486 139.8046045
24 東京都足立区北千住 ArcGIS 35.77481106 139.8045369
29 東京都足立区北千住 OpenStreetMap 35.7496486 139.8046045
30 東京都足立区北千住3 ArcGIS 35.77481106 139.8045369
36 東京都足立区北千住3-92 ArcGIS 35.77481106 139.8045369

ArcGISとOpenStreetMapのみ、変換に使うことができました。
これらをQGISで表示させてみます。

#QGISでの表示

※赤丸はOpenStreetMap、青丸はArcGISです

住所情報が日本の箇所に関しては、下記のようになりました。(赤枠)
image.png
群馬県になりました。だいたい日本の中心でしょうか。

日本以外に関しては、下記のようになりました。
image.png

東京都に関しては、OpenStreetMapは東京駅を指しています。ArcGISは都庁あたりを指しています。
東京の県庁所在地は新宿区なので、ArcGISもある意味正しいのではないでしょうか。

東京都足立区は下記のようになりました。
image.png

OpenStreetMapは、特に何もランドマークはなかったのですが、ArcGISは足立区役所を指していました。

おわりに

色々なジオコーディングサービスがありますが、とりあえずArcGISか、OpenStreetMapを使えば問題なさそうです。ただし、ポインティングする場所が微妙に異なるため、目視確認等もして判断していけばいいかなと思いました。

22
25
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?