GIS奮闘記

現役GISエンジニアの技術紹介ブログ。主にPythonを使用。

【PythonとSQL】Zmap-TOWNⅡをファイルジオデータベースに変換して住所データ(地番戸番)を抜き出す方法 ~やっぱり便利なPandas~

さて、本日はZmap-TOWNⅡから住所データ(地番戸番)を抜き出してみようと思います。大変便利なZmap-TOWNⅡですが、これの住所一覧が欲しいなぁと思ってもゼンリンさんはそんなデータは用意してくれていませんね。なら自分で作ってしまいましょう!

Zmap-TOWNⅡをファイルジオデータベースに変換

まず、Zmap-TOWNⅡは独自の形式なのでファイルジオデータベースに変換します。

変換ツールの使用

以下のようにESRIから変換ツールをダウンロードします。
Zmap-TOWNII、Zmap-AREAII 変換ツールが更新!洗練された地図表現に : ESRIジャパン ArcGISブログ

ArcMapにこのようなツールを追加することができました。
f:id:sanvarie:20160205200056p:plain

これで変換ですね。
f:id:sanvarie:20160205204355p:plain

無事変換を終えたのですが、なんとレイヤ構成がZmap-TOWNⅡと違ってるじゃん!どうなってるのさ?!こんな感じなのですが、明らかにレイヤ構成がおかしい。
f:id:sanvarie:20160205200300p:plain

ということでESRIに問い合わせた結果、変換したファイルジオデータベースは通常のレイヤ追加ではなく、変換ツールからレイヤを追加しなくてはいけないとのこと。
f:id:sanvarie:20160205200501p:plain

実行した結果、そうそうこれ。これですよ!ESRIさんありがとうございますm(_ _)m
f:id:sanvarie:20160205200551p:plain

データの内容

今回一番欲しい建物のデータ定義はこんな感じになっています。
f:id:sanvarie:20160205200904p:plain

中身はこんな感じですね。大字や字丁目などがコードで入っているので、別テーブルと結合して名称を取得する必要がありますね。
f:id:sanvarie:20160205201012p:plain

サンプルコード

各テーブルやフィーチャクラスをPandasのデータフレームに格納してCSVに吐き出します。そのCSVをDB(SQLSERVER)に突っ込み、住所データ(地番戸番)を取得したいと思います。本当はCSVに出力ではなく、そのままDBに格納したかったのですが、どうしてもうまくいかなかったです・・・なので、それは今後の課題として、今回はCSV出力を行いたいと思います。

# -*- coding: utf-8 -*-
import arcpy
import pandas as pd
import numpy as np

#カラム名と属性を返す関数
def GetAttribute(fc):
    field_list = []
    for field in arcpy.ListFields(fc):
        field_list.append(field.name)

    cur = arcpy.SearchCursor(fc)
    vallist2 = []
    for row in cur:
        vallist = []
        for field in field_list:
            vallist.append(row.getValue(field))
        vallist2.append(vallist)
    arr = np.array(vallist2)

    del row,cur
    return arr,field_list

#GDBに変換したZmapを指定
arcpy.env.workspace = ur"D:\python\zenrin\ZmapTown.gdb"

table = arcpy.ListTables()
table.sort()
jCode = ""

#テーブルから属性を取得
for tb in table:
    if tb ==  "ZmapTOWN_ZMAP_PST":
        data,olist = GetAttribute(tb)
        pst = pd.DataFrame(data)
        pst.columns = olist
        #一行だけでいいのでフィルターかける(もじかしたらここは市町村によっては変える必要ありかも)
        pstOneRow = pd.DataFrame(pst[pst.OID == "1"])
        jCode = pstOneRow["JCODE"].values[0]

    if tb ==  "ZmapTOWN_ZMAP_TATEMONO_NAME":
        data,olist = GetAttribute(tb)
        tatemono = pd.DataFrame(data)
        tatemono.columns = olist

        #重複データとCHIBAN、NAMEが空のデータは削除
        tatemonoValue = pd.DataFrame(tatemono[tatemono.CHIBAN <> ""])
        tatemonoValue = pd.DataFrame(tatemonoValue[tatemonoValue.NAME <> ""])

        #ここはキャストしない
        tatemonoValue = pd.DataFrame(tatemonoValue[tatemonoValue.JCODE == jCode])
        tatemonoValue = pd.DataFrame(tatemonoValue.drop_duplicates(['ACODE','CCODE','GCODE','CHIBAN','TPOLYCD']))

#GDBに変換したZmapのZmapTOWNフィーチャデータセットを指定
arcpy.env.workspace = ur"D:\python\zenrin\ZmapTown.gdb\ZmapTOWN"

# フィーチャクラスから属性を取得
for fc in arcpy.ListFeatureClasses():
    if fc ==  "ZmapTOWN_ZMAP_OOAZA":
        data,olist = GetAttribute(fc)
        ooaza = pd.DataFrame(data)
        ooaza.columns = olist

        #重複データとNAMEが空のデータは削除
        ooazaValue = pd.DataFrame(ooaza[ooaza.NAME.notnull()])
        ooazaValue = pd.DataFrame(ooazaValue[ooazaValue.JCODE == int(jCode)])
        ooazaValue = pd.DataFrame(ooazaValue.drop_duplicates(['NAME']))

    elif fc ==  "ZmapTOWN_ZMAP_AZA":
        data,olist = GetAttribute(fc)
        aza = pd.DataFrame(data)
        aza.columns = olist

        #重複データとNAMEが空のデータは削除
        azaValue = pd.DataFrame(aza[aza.NAME.notnull()])
        azaValue = pd.DataFrame(azaValue[azaValue.JCODE == int(jCode)])
        azaValue = pd.DataFrame(azaValue.drop_duplicates(['ACODE','CCODE','NAME']))

    elif fc ==  "ZmapTOWN_ZMAP_GAIKU":
        data,olist = GetAttribute(fc)
        gaiku = pd.DataFrame(data)
        gaiku.columns = olist

        #重複データとNAMEが空のデータは削除
        gaikuValue = pd.DataFrame(gaiku[gaiku.NAME.notnull()])
        gaikuValue = pd.DataFrame(gaikuValue[gaikuValue.JCODE == int(jCode)])
        gaikuValue = pd.DataFrame(gaikuValue.drop_duplicates(['ACODE','CCODE','GCODE','NAME']))

#データフレームをCSV出力
gaikuValue.to_csv("D:\python\zenrin\gaiku.csv",encoding = "utf-8")
azaValue.to_csv(r"D:\python\zenrin\aza.csv",encoding = "utf-8")
ooazaValue.to_csv("D:\python\zenrin\ooaza.csv",encoding = "utf-8")
tatemonoValue.to_csv(r"D:\python\zenrin\tatemono.csv",encoding = "utf-8")

出力したCSVはBULK INSERTなりなんなりでDBに突っ込んでください。←雑ですみません
テーブル定義はZmap-TOWNⅡの各テーブル、フィーチャクラスと同じにしました。

■大字
f:id:sanvarie:20160205202107p:plain

■字丁目
f:id:sanvarie:20160205202151p:plain

■街区
f:id:sanvarie:20160205202224p:plain

■建物
f:id:sanvarie:20160205202255p:plain

どのテーブルもコードばかりでわけがわかりませんね。定義書を見た感じ以下を考慮したSQLを作ればいいのではないかと思います。
・JCODE(拡張市町村コード
・ACODE(大字コード)
・CCODE(字丁目コード)
・GCODE(街区コード)

select d.NAME   大字,
       c.NAME   字,
       b.NAME   街区,
       a.CHIBAN 地番戸番,
       a.NAME   名称
from tatemono a left outer join gaiku_zenrin b 
                    on (a.ACODE = b.ACODE and a.CCODE = b.CCODE and a.GCODE = b.GCODE)
                left outer join aza c 
                    on (a.ACODE = c.ACODE  and a.CCODE = c.CCODE)
                left outer join ooaza d 
                    on a.ACODE = d.ACODE
order by d.NAME,
         c.NAME,
         b.NAME,
         a.CHIBAN,
         a.NAME

結果を見るとこんな感じですね。けっこうあっさりできました。あとはこれをテーブルに突っ込んだり、EXCELに出力したりして利用することができますね!
f:id:sanvarie:20160205202716p:plain

全然記事の趣旨からはそれるのですが、今回の変換したZmap-TOWNⅡやデータコレクションなどを見ていると、明らかに動きが早いと感じています←やはりこれがESRIさんの実力なのか?!
フィーチャの数は結構多いのに、動きがかなり軽くて驚きですね。今度はどうしてこんなに動きを早くすることができるのか、その辺の分析を行ってみたいと思います。

以上、本日は「【PythonSQL】Zmap-TOWNⅡをファイルジオデータベースに変換して住所データ(地番戸番)を抜き出す方法 ~やっぱり便利なPandas~」でした。