住処探しのために、Plotly/Dashでみる私の町の将来人口

年始は今後に関して考え行動する時期にあります。今年はコロナもあり、今後の住環境を考えていました。その際に、果たしてその街の将来人口は？と気になりました。住宅価格は市場あってのものなので、欲しい人が多ければ上がるし、逆も真なりです。そしてそれって人生で最も大きな投資だったりします。

将来人口気になる・・・とググってみたところ、国立社会保障・人口問題研究所という組織が2015年の国勢調査をもとに、2045年までの都道府県・市町村別の日本の地域別将来推計人口（平成30（2018）年推計・5年ごと、男女年齢（5歳）階級別）というデータを作られていることが分かりました（[データソース](http://www.ipss.go.jp/pp-shicyoson/j/shicyoson18/t-page.asp)）。

このデータはたくさんの市区町村の人口を推計されているそうです（原文: 推計の対象とした地域は、平成30（2018）年3月１日現在の１県（福島県）および1,798市区町村（東京23区（特別区）および12政令指定都市※の128区と、この他の766市、713町、168村）です。）。これだけたくさんあると、調べるの大変そう。という感じなのですが、かかっている私のお金の金額も大きい！！ということで、色々調べるためにアプリ化して、そのデータを見れるようにしました。

作った後、おっとそうだった。アドベントカレンダーを忘れていた・・・。これで良い。ということで、本記事は[データ可視化アドベントカレンダー](https://qiita.com/advent-calendar/2020/data-visualization)の12月16日の記事となります。本記事ではデータをPandasで加工して使いやすくし、Dashで動的にデータを見れるアプリケーションを作成する過程を解説します。

DashはPythonのウェブフレームワークで、動的にデータを見せられる優れものです。[なんか本もある](https://www.amazon.co.jp/dp/4254122586/ref=cm_sw_r_tw_dp_z1K-FbMFDZJ9G)みたいですよ。共著者に私が入っていますねw

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

## 今回作成したアプリと環境

アプリケーションはHerokuにデプロイしました。直接触っていただけます（~~無料なので起動が遅かったりしますが・・~~ 12日のイベントにも使おうと思うので、有料の方に移動しました）。

[https://chomoku.herokuapp.com/pyramid](https://chomoku.herokuapp.com/pyramid)

環境は次のような感じです。

Python 3.8.3
dash 1.16.3
pandas 1.1.2

アプリケーションは、ラジオボタンとドロップダウンをもとに、人口を確認したい場所を選択できます。もともとのデータが、都道府県・市区・町村のような感じでわかれていたので、それぞれで可視化できるようにしました。データは実数を見れるようにし、ドロップダウンで複数の位置が選択でき、人口推移の実数が線グラフに表示されます。気になった場所があれば、左クリックでその年齢別人口推移とその時系列変化が棒グラフで確認できます（下のGIFを参照ください）。

<a href="https://gyazo.com/563db9ac98f79dddde8e8f9cd10f899f"><img src="https://i.gyazo.com/563db9ac98f79dddde8e8f9cd10f899f.gif" alt="Image from Gyazo" width="1512.5"/></a>

それではデータ作成、アプリ作成の概要を確認します。

## データ作成

データ作成では、まず国立社会保障・人口問題研究所のページの３．男女･年齢（5歳）階級別の推計結果一覧（Excel 約8.0MB）をダウンロードします。そして、今回は総数の人口ピラミッドを観察するため、そのデータを抜き出すのを、データ作成のゴールとします。

まずはローカルにダウンロードしたデータを読み込みます。

```python
df = pd.read_excel('suikei_kekka.xls')
df.head()
```

出力結果は次のようになります。

<a href="https://gyazo.com/507cb907069ff7420c4c50074bd75622"><img src="https://i.gyazo.com/507cb907069ff7420c4c50074bd75622.png" alt="Image from Gyazo" width="877"/></a>

1行目にはデータの解説が書かれていて、データ自体は1の行からスタートしています。1と2の行がデータのカラムとなっているようです。なので、それを指定してデータを読み込みます。

```python 
df = pd.read_excel('suikei_kekka.xls', header=[2,3)
df.head()
```
<a href="https://gyazo.com/89521bd492005f9060710e4fed69489a"><img src="https://i.gyazo.com/89521bd492005f9060710e4fed69489a.png" alt="Image from Gyazo" width="762"/></a>

いい感じですね。次に年までの列をマルチインデックス化します。まずはインデックスに使うデータを作成します。

```python 
df_index = df.iloc[:,[0,1,2,3,4]].copy() # インデックスにする年までのデータを取得
index_col_name = df_index.columns.get_level_values(0) # カラム名はシングルにするために1番上のデータを取得
df_index.columns = index_col_name  # カラム名に先ほど作ったデータを渡す
```

下のような感じになります。

<a href="https://gyazo.com/f7afe82383349363fdc5d6eb90058441"><img src="https://i.gyazo.com/f7afe82383349363fdc5d6eb90058441.png" alt="Image from Gyazo" width="351"/></a>

データを使ってマルチインデックスにします。

```python
df.index = pd.MultiIndex.from_frame(df_index)
df.head()
```

<a href="https://gyazo.com/e56a5f400e71eb19c5ea9f908ec2d656"><img src="https://i.gyazo.com/e56a5f400e71eb19c5ea9f908ec2d656.png" alt="Image from Gyazo" width="752"/></a>

データは総数だけを用いるので、そのようにします。カラムの一番上の'総数'のデータを取得するとデータが出来上がります。

```python 
sousu = df['総数']
sousu.head()
```

次のような感じでデータが出来上がり！さて、次はアプリケーション作りです。

<a href="https://gyazo.com/fb71ddbf3e2d6e6d29f68ca2e3008691"><img src="https://i.gyazo.com/fb71ddbf3e2d6e6d29f68ca2e3008691.png" alt="Image from Gyazo" width="754"/></a>

## Dashを使ったアプリケーション作り

DashはPythonのウェブフレームワークで、宣言的なUIの作りができます。UIはコンポーネントを用いて組み立てます。そして、コールバックを使って動的にアプリケーションを動かせます。グラフにはPlotly以外にもmatplotlibやholoviewsなどなど、色々使えます。

[コードの全体像はgithubに置いておく](https://github.com/mazarimono/jinko-pyramid)のを確認していただくとして（雑に作って無駄が多くなっています。プルリクください。）、ここではアプリケーションの左側のグラフをクリックしたら右側のグラフに表示される場所が変わる部分と、年ごとのデータを示すために再生ボタンを押すと動く棒グラフの作り方を確認します。

<a href="https://gyazo.com/5890463beb57e76d1a6fe1fa9f9f65f1"><img src="https://i.gyazo.com/5890463beb57e76d1a6fe1fa9f9f65f1.gif" alt="Image from Gyazo" width="1512.5"/></a>

### 線グラフをクリックすると棒グラフの表示要素が切り替わる

ここはコールバックを使っています。コールバックはapp.callbackというデコレータに出力、コールバックの入力のコンポーネントのプロパティを指定して作成します。このアプリケーションでは都道府県と市区町村のUIを作り替えているので、下のコードは実際の都道府県の部分のコールバックとなります。

```python
@app.callback(
    Output('todou_graph_selected', 'figure'), # 出力に右のグラフコンポーネントのfigureを指定
    Input('todou_graph_multi', 'clickData'), # 入力に左のグラフのclickDataを指定
    Input("todou_dropdown", "value"), # 都道府県のドロップダウンの値を指定
)
def update_pop_pyramid(clickData, pref_value):
    # クリックデータがない場合の処理を作成（都道府県のドロップダウンの1つ目の値を渡す）
    if clickData is None:　
        clickData = {'points': [{'hovertext': f'{pref_value[0]}'}]}

    # 選択された都道府県のデータを作成、グラフを作る
    selected_area = clickData['points'][0]['hovertext']
    selected_df = sousu[sousu["市などの別"] == "a"]
    selected_df = selected_df[selected_df["都道府県"].isin([selected_area])]
    selected_df = selected_df.iloc[:, 4:].drop('総数', axis=1)
    melted_df = selected_df.melt(id_vars='年')
    # 上で作成したデータを使ってグラフを作成したものを返り値とする
    return px.bar(melted_df, x='value', y='variable', orientation='h', animation_frame='年', title=f'年齢別人口分布（{selected_area}）')
```

DashのGraphコンポーネントにはclickDataプロパティがあり、それを使うとクリックで得られたデータを用いて色々と処理が可能です。

### 再生ボタンを押すと動くグラフ

上でコードが出ていましたが、再生ボタンを押すと動くグラフを作成するのも、plotlyを使うと簡単です。引数animation_frameに動かしたいデータの列名を渡すだけです。また、再生ボタンを押す以外にも、下にあるスライダを使って、グラフを動かすこともできます。


コードは下のような簡易さです。

```python
 px.bar(melted_df, x='value', y='variable', orientation='h', animation_frame='年', title=f'年齢別人口分布（{selected_area}）')
```

## まとめ

以上のように、データを使って将来人口を見るアプリケーションを作成しました。家とかってノリで買わないと買えない高いものですが、あまりノリ過ぎると40年後の自分が困るので、ちょっと色々見ると良いかもですね。そして、そういうのに役立つデータが無料であるのは非常に良いです。

またこれを使って奥様にタブレットで見ていただいて「こうなんですよー」というのを説明するのも良い感じでできます。

はい。データの中身に関して触れておくと、この記事内でも見て分かるように、日本の多くの地域で今後は**人口が減っていくこと**が予想されています。でもそのような環境下でも、ここでみた滋賀県の草津市のように人口が減らないところもあったりするので、こういう場所を探したいなぁと私は思っています。まぁこれだけで決めるわけではないですが、大きなファクターだと思います。

人口ピラミッドというのはある程度の未来を予測できるもののうち、その確率が高いものとして知られています。なので、住処探し以外にも使えるでしょうね。今後は地図を加えたり、住宅価格を加えたりしてみたいです。

というわけで最後に宣伝です。週明けの1月12日にPythonインタラクティブ・データビジュアライゼーション入門という長いタイトルの本の[著者3人の有料オンラインイベントがジュンク堂さんで行われる](https://startupmj.stores.jp/?category_id=5fc9d5f98a4572598942648a)みたいですよ～。こちらの方もヨロです。

あ、あとちなみにPandasのマルチインデックが苦手という方が多いようです（私もその一人です）が、そういう方にはpapi_tokeiさんの[Pandasのマルチインデックスについて](https://qiita.com/papi_tokei/items/05fe87195f7a772c567a)の記事がおすすめです。