ここでは、経度・緯度に対する人口データを対応づけたデータ分析方法について言及します。
人口データの入手先: 国土数値情報 ダウンロードサービスの下の方にある「1kmメッシュ別将来推計人口(H29国政局推計)(shape形式版)」を使用しています。以下は、千葉県のデータを利用しています。
はじめに、データのロードを行います。人口データはshapeファイルと呼ばれるデータを使用しているので、ちょっと扱いがややこしいことに注意する必要があります。まず、以下をインストールします。
import shapefile
# 読み込み, SHIFT-JISで日本語対応
src = shapefile.Reader('Mesh3_POP_12.shx',encoding='SHIFT-JIS')
これでロードできました。ひとつ注意点ですが、Mesh3_POP_12.shxのみならず、dbf, prj, shxを同じディレクトリに置いておかないと、メッシュデータを使えません。
# 地域nにアクセス
n=0
Place = src.shape(n).points[0]
Dat = src.record(n)
print(Place)
print(Dat)
Placeは経度緯度というのは想像がつくと思いますが、Datは数字がいっぱいあります。Datの列idはそれぞれ以下の意味を持ちます。
POPは2010年分があるため7列分となりますが、INDEXは2020年からのため6列となることに注意する必要があります。なお、INDEXとは2010年の人口を100としたときの人口割合となります。 ヘッダの並びは、以下で参照できます。
db = shapefile.Reader('Mesh3_POP_12.dbf',encoding='SHIFT-JIS') db.__geo_interface__
詳細は、以下を参照(ただ、データの並びとか結構わかりにくい)。
国土数値情報 1kmメッシュ別将来推計人口(H29国政局推計)(shape形式版)
これが理解できると、以下のように地域コードに対する人口を得ることができます。
n=0
print("座標:", src.shape(n).points[0])
print("基準地域メッシュコード:", src.record(n)[0])
print("市町村コード:", src.record(n)[1])
print("2010年総人口:", src.record(n)[2], "人")
print("2020年推定総人口:", src.record(n)[3], "人")
print("2025年推定総人口:", src.record(n)[4], "人")
print("...")
理解を終えたところで、Foliumで使用しやすいようにデータを加工しています。さて、勘のいい人なら気がついたかもしれませんが、経度と緯度の並びが、実は逆になっています。そのため、これに注意して変数を作っていきます。
今回は、2010年の総人口を解析に使用することにします。
Place = []
MeshCode = []
Population = []
# (なぜか0番目に埼玉が混ざっているので1から)
for i in range(1, len(src)): # len(src)は千葉県内のメッシュの数
# 座標の取得
a = src.shape(i).points[0][0]
b = src.shape(i).points[0][1]
Place.append([float(b), float(a)]) # 経度と緯度を逆にし、Foliumの順に
# メッシュコードの取得
MeshCode.append(str(src.record(i)[0]))
# 2010年の総人口を取得
Population.append(src.record(i)[2])
続いて、地図を作成し、マーカの上に人口を表示するプログラムを組んでみます。
import folium as fl
import geocoder as ge
from folium.features import DivIcon
# 千葉県の中心を取得
Central = ge.arcgis("千葉県")
Central = Central.latlng
def MakeBox(in_text):
out_text = '''
<div style="text-align: center;
font-size: 5pt;
color: black;
padding-top: 1px;
height: 30px;
width: 100px;
background: white;
border: 2px solid;
border-radius: 30%;">'''
out_text = out_text+ in_text + '</div>'
return out_text
# マップ作成
map1 = fl.Map(location = Central,
zoom_start = 14,
tiles = 'openstreetmap')
# マーカ設置
for i in range(0, len(Place)):
html_text = "MeshCode: " + MeshCode[i] + "</br>"+ "Population: " + str(Population[i])
fl.Marker(location = Place[i], icon=DivIcon(html=MakeBox(html_text))).add_to(map1)
map1
どこに人口が多いのか、わかるようになりました。Zoomが小さいと重いので注意してください。駅付近は人口が多いとか、海や山は人口が少ないとか、そんなことがわかります。
もうちょっとわかりやすくみたい人は、HeatMapを利用してください。HeatMap関数の第一引数に経度、緯度、人口のリストを入れます。
と、ドキュメントに書いているが、なかなか調整が難しいので思考錯誤で...
from folium.plugins import HeatMap
# マップ作成
map2 = fl.Map(location = Central,
zoom_start = 9,
tiles = 'openstreetmap')
# 経度、緯度、人口の並びのリストを作成
heatmap_dat = []
for i in range(0, len(Place)):
heatmap_dat.append([Place[i][0], Place[i][1], Population[i]])
# ヒートマップ作成
HeatMap(heatmap_dat, radius=30, blur=60).add_to(map2)
map2
みやすいと思いきや、みにくいとも言えます。使えそうなときに使う感じで良いでしょう。