Geoデータと統計データを重ねて可視化する


この記事はデータ可視化アドベントカレンダーの12月23日の記事を30日に書いています。まぁありですね。

この記事では、日本地図に各都道府県の将来推計人口を表示したいと思います。e-statsを使うと2020年~2045年の各都道府県の推計人口が取れますので、それをアニメーションで地図にプロットします。

地図のプロットにはfolium、plotlyを使います。

環境

Google Colaboratory
plotly

geopandas
shapely
folium

まずは都道府県のデータを入手する

まず都道府県をプロットするため、その位置データを手に入れます。各都道府県の県庁所在地のデータがないかなと思いましたがなかったので、国土交通省の国土数値情報の行政区域データを用い、都道府県の中心のデータを作成しプロットしようと思います。

まずは、全国のデータを入手するために、一番下にあるzipファイルをダウンロードします。

続いてそのファイルを解凍すると次のように7個のデータが出現します。

次にgeojsonファイルをgeopandasのread_fileメソッドで読み込みます。データは次に確認しているように11.5万行の都道府県名、位置データなどを持っています。

次に座標参照系を確認します。EPSG:6668になっています。リンク先のデータによると日本測地系2011と呼ばれるもののようです。どうも西日本と東日本では異なるもののようです。データの可視化などでは「World Geodetic System 1984」を使いたいので、CRSを変更します。

さて、作成したいデータは都道府県の中心データなので、雑に都道府県の全ポリゴンを合体させて、そこの中心点を取ります。それにはshapelyを用います。次のコードは北海道のデータを使った例です。

# 北海道だけのデータフレームを作成
hokkaido = data[data['N03_001'] == '北海道']
# 北海道のgeometry値を全部持つMultiPolygonを作成し、中心点を取る
center_hokkaido = shapely.geometry.MultiPolygon(hokkaido.geometry.values).centroid 

次に、中心点をfoliumを使って可視化します。

# mapオブジェクトを作成し、中心点に先ほど作った中心点を置く
m = folium.Map([center_hokkaido.y, center_hokkaido.x], zoom_start=8)
# 指定したポイントにマーカーを置く
folium.Marker([center_hokkaido.y, center_hokkaido.x]).add_to(m)

まぁ中心点っぽいものが作れているので、とりあえずこの方法で、各都道府県の位置データを作成します。ここではループで回して、リストに県名、経度緯度を格納し、GeoDataFrameを作成します。

ken_list = list()
center_list = list()
for ken in data['N03_001'].unique():
  ken_data = data[data['N03_001'] == ken]
  ken_center = shapely.geometry.MultiPolygon(ken_data.geometry.values).centroid
  ken_list.append(ken)
  center_list.append(ken_center)

ken_data = gpd.GeoDataFrame()
ken_data['name'] = ken_list 
ken_data['geometry'] = center_list
ken_data = ken_data.set_index('name')

出来たデータ

将来推計人口データの取得

各都道府県の将来推計人口データの取得はe-statsから行います。同ページからダウンロードして、不要なコラムを削除してコラム名をシンプルに作り変えます。

jinko = pd.read_csv('/content/FEI_PREF_201230204425.csv', encoding='shift_jis')
jinko = jinko.drop(['調査年', '/項目'], axis=1)
jinko.columns = ['地域', 2020, 2025, 2030, 2035, 2040, 2045]
jinko = jinko.set_index('地域')
jinko_t = jinko.T 
jinko_t = jinko_t / jinko_t.loc[2020] * 100
jinko = jinko_t.T  

できるデータ。

位置データと推計人口データをガッシャンコ

2つのデータをくっつけます。mergeメソッドを使うと簡単です。下では2つのデータをインデックスをもとにくっつけたあと、経度と緯度の列を作り、geometry列を削除しています。

merge_data = jinko.merge(ken_data, left_index=True, right_index=True)
merge_data['x'] = merge_data.geometry.map(lambda x: x.x)
merge_data['y'] = merge_data.geometry.map(lambda x: x.y)
merge_data = merge_data.drop('geometry', axis=1)
merge_data = merge_data.reset_index()
merge_data.head()

縦長のデータを作成

可視化がやりやすいロングフォームなデータにmeltを使って変形します。id_varsで各データにつけておきたい要素を指定します。ロングフォームは整然データと呼ばれる方が多いです(整然データとは何か)。あと、年のデータを文字列にしておきます。

merged_melt = pd.melt(merge_data, id_vars=['index', 'x', 'y'])
merged_melt['variable'] = merged_melt['variable'].astype('int')
merged_melt.info()

これで各都道府県の2020年の人口を100としたデータ with 経度緯度情報ができました。

plotly.expressを用いて可視化する

さて、最後に作成したデータをplotly.expressを用いて可視化します。人口指数を円で表現するscatter_mapbox関数を使います。ちなみにこの関数はmapboxを利用して地図を表示するため、mapboxのトークンが必要となります。

import plotly.express as px 
# マップボックスのトークンの設定
px.set_mapbox_access_token('your token')
# グラフの描画
px.scatter_mapbox(
    merged_melt,
    lat="y",
    lon="x",
    size="value",
    hover_name="index",
    animation_frame="variable",
    height=800,
    color="value",
    color_continuous_scale=px.colors.sequential.Viridis,
    size_max=30,
    zoom=4,
)

すると下の動画のように、再生ボタンがついたグラフが表示され、再生ボタンをクリックすると時系列でデータが動きます。このようなアニメーションのグラフは引数animation_frameに動かしたい列名(今回の場合'variable')を渡すと、指定した文字列(数値を文字列に変換して渡しています)でグラフが動くようになります。

まとめ

本投稿では各都道府県の位置データを作成したあと、各都道府県の人口の推計値をくっつけ、動的なグラフで可視化しました。plotlyを使うと、簡単に複雑な動きをするグラフが作れます。

さて、これで各地の人口がどのように変化するか分かるようになりました。しかし一方で、これでは時系列の推移などが見れないなんて不満が出てきます・・。それを次の投稿では解決します(続きは明日)!!

興味を持っていただけたら、LGTMしていただけると幸いです。

ノートブック: https://colab.research.google.com/drive/1q-bgBGNYiqdBbNWv_fcgxA3oyACnksYc?usp=sharing (多分データが足りずに動かなくなるので近く修正します。)