郵便番号マップ作成記 (1) - 郵便番号データをデータベースに入れる
前回予告した通り、郵便番号マップを作った手順を紹介していこう。
ビジュアライジングのためにはデータ収集が重要だ。今回はデータベースに郵便番号データを入れていくところを説明する。泥臭いけど避けては通れない作業だ。
郵便番号データを入手
まずは郵便番号のデータを手に入れる。といっても日本郵便が郵便番号データを CSV の形で提供してくれてるので、特に凝ったことはしなくてもよい。
以下のサイトから全国一括のファイルをダウンロードするだけ。ありがたや。
Shift-JIS なので utf-8 に変換しておいた。
% wget http://www.post.japanpost.jp/zipcode/dl/oogaki/lzh/ken_all.lzh
--00:23:50-- http://www.post.japanpost.jp/zipcode/dl/oogaki/lzh/ken_all.lzh
=> `ken_all.lzh.1'
www.post.japanpost.jp をDNSに問いあわせています... 122.215.192.22
www.post.japanpost.jp|122.215.192.22|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 1,726,157 (1.6M) [application/octet-stream]
100%[=============================================>] 1,726,157 1.11M/s
00:23:52 (1.11 MB/s) - `ken_all.lzh.1' を保存しました [1726157/1726157]
% lha -x ken_all.lzh
ken_all.csv - Melted : ooooooooooooooooooooooooooooooooooooooooooooooo
% nkf -w ken_all.csv > ken_all_utf8.csv
データベースへの作成
ビジュアライジング・データ ―Processingによる情報視覚化手法 でのアメリカ版では CSV データに経度緯度データも入っていたんだけど、日本郵便のデータには入っていない。ならば、ジオコーディングで取得するしかない。
今回はその準備のためにデータベース環境を整えていく。言語は Ruby を選択した。O/R マッパーとして Ruby on Rails の ActiveRecord を使って省エネを狙う。DB は手軽に使える sqlite3 を使う。
バージョンはこんな感じ。
- Ruby 1.8.5
- ActiveRecord 1.15
- sqlite3-ruby 1.2.4
- sqlite3 3.6.6.2
テーブルの準備
まずは、DB とテーブルの作成。ActiveRecord の Migration 機能を使ってテーブル構造を定義してやる。
# EntrySchema.rb
require 'rubygems'
require 'active_record'
ActiveRecord::Base.establish_connection(
:adapter => 'sqlite3',
:dbfile => "geocode.db"
)
class EntrySchema < ActiveRecord::Migration
def self.up
create_table(:codes){ |t|
t.column :high, :string, :null => false
t.column :low, :string, :null => false
t.column :pref, :string, :null => false
t.column :city, :string, :null => false
t.column :lat, :float
t.column :lng, :float
}
end
def self.down
drop_table :codes
end
end
class Code < ActiveRecord::Base
end
こう書いておくと、次のようなコードを実行させるだけでテーブルを作成してくれる。
% ruby -e 'require "EntrySchema"; EntrySchema.migrate(:up)' == EntrySchema: migrating ==================================================== -- create_table(:codes) -> 0.0397s == EntrySchema: migrated (0.0402s) ============================================
素晴らしい。
Migration については、以下のサイトを参考にした。
CSV を DB に流し込む
お次は DB に CSV のデータを流し込むところ。
Ruby には標準で CSV クラスがついてくる。こいつを使えば1行を配列としてパースしてくれる。
DB 側は ActiveRecord と併用すればいとも簡単。コードがこれ。
require 'EntrySchema'
require 'csv'
i = 1
CSV.open('ken_all_utf8.csv', 'r') do |row|
# 下4桁が 0000 のだけ突っ込む
next unless row[2].to_s.slice(3, 4) == "0000"
# 既に突っ込んだ場合はそのデータを読み取る
code = Code.find_by_id(i)
code = Code.new if code.nil?
# CSV のデータを保存する
code.high = row[2].to_s.slice(0, 3)
code.low = row[2].to_s.slice(3, 4)
code.pref = row[6]
code.city = row[7]
code.save
# 出力
puts "#{code.pref} #{code.city}"
i += 1
end
ActiveRecord のおかげで、Code オブジェクトのプロパティを設定して save するだけで DB に格納してくれる。抽象度が高くて幸せ。
実行してみる。
% ruby script/parse_postal.rb <font color="#999999">北海道 札幌市中央区 北海道 札幌市北区 北海道 札幌市東区 北海道 札幌市白石区 北海道 札幌市豊平区 : (略) 沖縄県 沖縄市 沖縄県 宮古島市 沖縄県 八重山郡竹富町</font>
いい具合に DB に突っ込まれていく。
ActiveRecord については以下のサイトがとても参考になる。
sqlite3 コンソールで確認
ちゃんと入ってることを確認する。
sqlite> select * from codes;
:
784|904|0000|沖縄県|沖縄市||
785|906|0000|沖縄県|宮古島市||
786|907|0000|沖縄県|八重山郡竹富町||
786件のデータが入力されている。やったね。
次回は、経度緯度を埋めていくところから。