位置情報のデータを扱っていると、「緯度経度のペアが大量にあって、これを地域単位で集計したい」という場面に出会います。市区町村で切ると合併で境界が変わるし、区画の大きさもバラバラ。そこで出てくるのがメッシュコードです。
自分はこの変換をRustでやるために jismeshcode というクレートを書いて公開しています。実装にあたってJIS X 0410の仕様をだいぶ読み込んだので、その過程で整理した内容をまとめておきます。
メッシュコードって何
メッシュコード(地域メッシュコード)は、日本全国を緯度・経度に基づいて格子状に分割し、各区画に一意の番号を振ったものです。JIS規格「JIS X 0410 地域メッシュコード」として定められていて、元をたどると昭和48年の行政管理庁告示に行き着きます。
ポイントは、区画が緯度経度だけで決まることです。市町村合併があっても区画は動かないので時系列比較に強く、全国どこでも同じルールなので地域間の比較も公平にできる。だから国勢調査、気象庁のデータ、国交省の土地利用データなど、公的統計の空間単位として広く使われています。
ひとつ注意点として、2002年の測量法改正以降、JIS X 0410は世界測地系ベースです。古い日本測地系の座標データと混ぜると数百mズレるので、昔のデータを扱うときは測地系を確認してください。
地域メッシュの種類
分割の細かさに応じて階層になっています。
| 区画の種類 | 別名 | コード桁数 | 緯度の間隔 | 経度の間隔 | 一辺の長さ |
|---|---|---|---|---|---|
| 1次メッシュ | 第1次地域区画 | 4桁 | 40分 | 1度 | 約80km |
| 2次メッシュ | 第2次地域区画 | 6桁 | 5分 | 7分30秒 | 約10km |
| 3次メッシュ | 基準地域メッシュ | 8桁 | 30秒 | 45秒 | 約1km |
| 2分の1メッシュ | 4次メッシュ | 9桁 | 15秒 | 22.5秒 | 約500m |
| 4分の1メッシュ | 4次メッシュ | 10桁 | 7.5秒 | 11.25秒 | 約250m |
| 8分の1メッシュ | 4次メッシュ | 11桁 | 3.75秒 | 5.625秒 | 約125m |
| 5次メッシュ | 10分の1細分メッシュ | 10桁 | 3秒 | 4.5秒 | 約100m |
実務でいちばん使うのは3次メッシュ(約1km四方、通称・基準地域メッシュ)です。国勢調査をはじめ多くの統計データがこの単位で提供されています。
罠がひとつあって、4分の1メッシュと5次メッシュはどちらも10桁です。桁数が同じなのに付番ルールが違うので、コードだけ渡されると区別できません。データの仕様書でどちらのメッシュか必ず確認してください。ここは実装していて一番紛らわしいポイントでした。
付番ルールと計算方法
メッシュコードは恣意的な連番ではなく、緯度経度から計算で求まります。東京駅(北緯35.681度、東経139.767度)を例にすると:
1次メッシュ(4桁) — 上2桁は南端緯度×1.5の整数部、下2桁は西端経度−100。
- 35.681 × 1.5 = 53.52… →
53 - 139.767 − 100 = 39.767… →
39 - 1次メッシュコードは
5339
2次メッシュ(+2桁) — 1次メッシュを縦横8等分し、南から0〜7の行番号、西から0〜7の列番号を「行+列」の順で付加。南から4番目・西から6番目なら 46 が付いて 533946。
3次メッシュ(+2桁) — 2次メッシュを縦横10等分し、同様に0〜9の行・列番号を付加。53394613 のような8桁になります。
4次メッシュはここからさらに縦横2等分を繰り返し、南西=1、南東=2、北西=3、北東=4の番号を末尾に足していきます。
緯度経度⇔メッシュコードの変換式
緯度経度→メッシュコードは、上の付番ルールをそのまま式にしたものです。
p = floor(緯度 × 1.5)
q = floor(経度) - 100
1次メッシュコード = p × 100 + q
緯度の余り = 緯度 - (p / 1.5)
経度の余り = 経度 - (q + 100)
r = floor(緯度の余り × 1.5 × 8)
s = floor(経度の余り × 8)
2次メッシュコード = 1次コード × 100 + r × 10 + s
t = floor(残りの緯度 × 1.5 × 8 × 10)
u = floor(残りの経度 × 8 × 10)
3次メッシュコード = 2次コード × 100 + t × 10 + u
逆方向(メッシュコード→緯度経度)は、8桁コードを AABBCDEF と分解して南西端を復元します。
南西端の緯度 = AA / 1.5 + C × 5/60 + E × 30/3600
南西端の経度 = BB + 100 + D × 7.5/60 + F × 45/3600
中心座標が欲しければ、南西端にメッシュサイズの半分を足すだけです。
単発で調べるならツールで十分
数件調べたいだけなら実装は不要で、国土地理院の地図ツールや総務省統計局の jSTAT MAP(e-Stat)で地図をクリックすればメッシュコードが表示されます。1次メッシュは全国で約180個しかないので、e-Statの一覧表から絞り込む手もあります。
Rustで変換する: jismeshcode
大量の座標データをバッチ変換したり、位置情報サービスの空間インデックスに使うなら、プログラムでの変換になります。Pythonなら jismesh が定番で情報も豊富です。
Rustの場合は、自分が書いた jismeshcode を使ってください。手前味噌ですが、JIS X 0410の1次〜5次まで全レベル対応で、座標⇔コード変換のほかに隣接メッシュの取得、親子メッシュの階層操作、半径検索まで入れてあります。no_std環境でも動きます(数学関数のため libm フィーチャーが必要)。
use jismeshcode::prelude::*;
fn main() {
// 緯度経度からメッシュコードへ変換(東京駅の例)
let coord = Coordinate::new(35.6812, 139.7671).unwrap();
let mesh = coord_to_mesh(coord, MeshLevel::Third).unwrap();
println!("東京駅の3次メッシュコード: {}", mesh);
// メッシュコードから中心座標を取得
let center = mesh_to_center(mesh);
println!("中心座標: ({}, {})", center.lat(), center.lon());
// 隣接メッシュの取得
for n in neighbors(mesh) {
println!("隣接: {}", n);
}
// 半径1km以内のメッシュコードを検索
for nearby in mesh_codes_in_radius(coord, 1000.0, MeshLevel::Third) {
println!("近傍メッシュ: {}", nearby);
}
}
[dependencies]
jismeshcode = "0.3"
GPS座標をメッシュコードに変換して空間インデックスにすると、「この地点の周辺」の検索がただの数値比較になるので、大量データでも高速に回せます。メッシュの階層構造をそのまま広域→詳細のドリルダウンに使えるのも便利なところです。
というわけで
メッシュコードは「緯度経度から計算で決まる、動かない区画」というのが本質で、統計・防災・気象・エリアマーケティングまで日本の空間データの共通言語になっています。単発なら地図ツール、大量処理ならライブラリで。Rustなら jismeshcode をどうぞ。
