住所等を緯度経度に変換したい

Google Apps Scriptの中では、実に地味でそれでいてあまり活用されていないけれど、自分としては結構ありがたいと思ったのがこの機能(Maps Class)。自分自身が以前、Google Earth関係でサイトをやっていたからというのもあるのですが、非常に簡単にジオコーディングや逆ジオコーディングが出来てしまうのは、とてもありがたい。他にもこのクラスには、Static Map(完全固定の地図生成)やらありますが、あまり利用価値がありませんので、スルーします。

但し、このジオコーディングやら逆ジオコーディングは、完全にGoogle Mapsの検索機能を利用して答えを貰ってる機能なので、クセがあります。今回は、とりわけもっとも利用頻度の高い「ジオコーディング」に的を絞ってます。

概要と問題点

概要といっても、与えられたキーワードから、緯度経度を取得する。ただそれだけなのですが、このただそれだけが非常に問題だったりします。Googleが悪い点もあり、そうでない点もあり、其の結果としてジオコーディングしたのに、全く目的の場所から違う緯度経度が帰ってきて精度が悪いなんてことも非常に多くあります。以下に、このジオコーディングを利用した時の問題点をGoogleが悪いケースとそうではないケースの2つで説明してみたいと思います。尚、今回は、スプレッドシートを1枚用意して、キーワード列と緯度列、経度列、プレイスマークの列の4つの列を設けたものに、この機能を使って、一括でジオコーディングをするのが目的です。

Googleが悪いケース

  1. 正しい住所にも関わらず、一部のケースで全くジオコーディングされない地域がある
  2. Google Mapsでの検索結果と同じなので、住所ではなくキーワードの場合、2つ以上の答えが帰ってくることがある。
  3. 住所だと正確ではないのに、建物名だとピッタリ正確なポイントが帰ってくることがある。但し、Google Mapsに登録されている固有の建物名であり、尚且つエリアを絞って同一の建物名がないケースで。
  4. 建物名が表記されてるのに、登録されていないので、建物名でヒットしないことがかなりある。
  5. 住所ブロックがおかしなケースがある。指定した住所だとズレるのに、となりの住所を調べて指定すると、ピッタリなんてケースがぼちぼちある。
  6. 建物名だとダメだが、フルネームな建物名だと行けるという謎ケースがある。

そうではないケース

  1. 日本の住所というのは非常に複雑に入り組んでいて、綺麗に整理整頓されているわけではないので、どうしても精度が落ちるエリアというのがあります。
  2. 通常は住所を入れるとマーカーがマップに落ちるのですが、一部の住所でマーカーではなくエリア表示されるケースがあるのはこのためです。しかし、それ以上小さな区分の住所がないので、結果、緯度経度の数値に於いて桁がなんこか落ちたアバウトなポイントが帰ってくるケースがあります。
  3. 地図によって、エリアが曖昧なケースがあり、A地図とB地図とで同じポイントでも所属してるエリアがあったりなかったり、そもそも存在していないと思ったら、旧地名だったり(字だの大字は現代では使いませんが、未だに郵便では使えるので、それを住所表記しているケースがあります)。
  4. 些細なことですが、例えば住所表記で使う上での漢字が原因で上手にジオコーディングできない事があります。
  5. 道路またいでるのに、同じブロックだったりするマヌケなエリアがあったりする。地方の田舎に多い。
  6. 新しい建物の場合や新たに住所が設定されたようなものに関しては、Googleでの登録が遅れているケースがある。この場合建物名でもヒットしないので、一番困る。

ジオコーディングを行う上での対策

  1. 殆どのケースでは、住所で正確なジオコーディングが可能である。
  2. 田舎町だと、県名市名を加えてエリアを絞ったキーワードに建物名のほうが正確にヒットするケースがある。
  3. 帰ってくる答えが2つ以上の場合と0の場合には、エラー処理としてしまい、ジオコーディングをスルーするのも一手。その場合、再度別の形式のワード入力を促すようにしておけば、取りこぼしが少なくて済む。
  4. ジオコーディング結果を同じMapsのStatic Mapsクラスを使ってプレビューしてあげるのは、アリかなと思う。
  5. エリア名で絞って建物名でも出ない時は、Google Maps上で答えが1つになるほど長いフルネームな建物名などを入れるとヒットしやすくなる。
  6. 旧地名は使用しない。大字小字などは代表例。また、市以下にぶら下がる町名も、最新で変更されているケースがある。
  7. 有名なものは、ランドマーク名のみで行ける。住所である必要はない。
  8. 同じ住所内に、有名な建物名があり、同居する形で違う企業(関連会社など)の場合には、ヒットしないことがある。その場合には有名な建物名のほうで対応するような対応が必要。

ソースコード

function allgeocode(){
  //シートデータ取得準備
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("mainsheet");
  var range = sheet.getRange("A2:U").getValues();
  var num = range.length;
  var finalrow = sheet.getLastRow()-1;
  
  //緯度経度情報格納用二次元配列を作成
  //二次元配列を作成する(4列・行数分+1)
  var msgcnt =3;
  var dataArray = new Array(finalrow); 
  for(i = 0; i < finalrow; i++){
    dataArray[i] = new Array(msgcnt); 
  }
  
  //住所データ列よりジオコーディングをし、結果をとなりの3列に書き込む
  for(var i = 0;i<finalrow;i++){
    //住所キーワードを取得
    var address = range[i][0];
    
    //住所が空の場合はスルーする
    if(address == ""){
      dataArray[i][0] = "";
      dataArray[i][1] = "";
      dataArray[i][2] = "";
      continue; 
    }
    
    //ジオコーディングして値を配列に格納する
    var latlng = georeturn(address,0);
    var kekka = latlng.split(",");
    
    dataArray[i][0] = kekka[0];
    dataArray[i][1] = kekka[1];
    dataArray[i][2] = latlng;
  }
  
  //配列データをスプレッドシートに反映させる
  var lastColumn = dataArray[1].length; //カラムの数を取得する
  var lastRow = dataArray.length;   //行の数を取得する
  
  
  sheet.getRange(2,22,finalrow,3).setValues(dataArray);
}
//ジオコーダー用ラッピング関数
function georeturn(address,option){
  //ジオコーダクラスの宣言
  var geocoder = Maps.newGeocoder();
  
  //空のアドレスの場合には、スルーする
  if(address == ""){
    return ""; 
  }
  
  //ジオコーディング実施
  var response = geocoder.geocode(address);
  
  //optionによって値を返す。本来はresultsは配列で複数の答えが帰ってくることがあるが、0固定で今回はコーディングしてます。
  var ret = "";
  var result = response.results[0];
  
  switch(option){
    case 0: //全部を取得
      ret = result.geometry.location.lat + "," + result.geometry.location.lng;
      break;
    case 1: //緯度だけ取得
      ret = result.geometry.location.lat;
      break;
    case 2: //経度だけ取得
      ret = result.geometry.location.lng
      break;
    default:
      ret = "オプションが指定されていません"
      break;
  }
  
  return ret;
  
}

※今回は、これらのクラスはいちいち書くのもアレなので、関数(georeturn)でラッピングしてます。

参考リンク