トップページに戻る

Pandas―データ分析(5)応用:都道府県別人口推移

「分離ー適用ー結合」の一例

国勢調査をもとにした人口推移のCSVを使います。
このデータの中には、都道府県別の人口推移があるので、pandasで解析してみましょう。
とりあえず

  • 都道府県別の人口増減を一次近似で求め、その勾配ランキングを作る

という目的でやってみましょう。
データは政府統計の総合窓口(e-Stat)からもらってきました。

In [1]:
# 慣習、下の2つはよく使うからインポートしておく
import pandas as pd

%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
In [2]:
# 最初の5行を出力
with open("c01.csv", "r", encoding="shift-jis") as fp:
    for line in fp.readlines()[:5]:
        print(line.strip())
"都道府県コード","都道府県名","元号","和暦(年)","西暦(年)","注","人口(総数)","人口(男)","人口(女)"
"00","全国","大正",9,1920,"",55963053,28044185,27918868
"01","北海道","大正",9,1920,"",2359183,1244322,1114861
"02","青森県","大正",9,1920,"",756454,381293,375161
"03","岩手県","大正",9,1920,"",845540,421069,424471

pandasだとcsvを一行で読み込むことが出来ます(エンコードは適当に探す)

In [3]:
# 一行でcsvファイルをDataFrameに変換できる
df = pd.read_csv("c01.csv", encoding="shift-jis", skipfooter=2, engine="python")
df = df.rename(columns={"人口(総数)": "全人口", "人口(男)": "男", "人口(女)": "女"})

# 最初の5行
df.head()
Out[3]:
都道府県コード 都道府県名 元号 和暦(年) 西暦(年) 全人口
0 00 全国 大正 9 1920 NaN 55963053 28044185 27918868
1 01 北海道 大正 9 1920 NaN 2359183 1244322 1114861
2 02 青森県 大正 9 1920 NaN 756454 381293 375161
3 03 岩手県 大正 9 1920 NaN 845540 421069 424471
4 04 宮城県 大正 9 1920 NaN 961768 485309 476459
In [4]:
# 最後の5行
df.tail()
Out[4]:
都道府県コード 都道府県名 元号 和暦(年) 西暦(年) 全人口
975 43 熊本県 平成 27 2015 NaN 1786170 841046 945124
976 44 大分県 平成 27 2015 NaN 1166338 551932 614406
977 45 宮崎県 平成 27 2015 NaN 1104069 519242 584827
978 46 鹿児島県 平成 27 2015 NaN 1648177 773061 875116
979 47 沖縄県 平成 27 2015 NaN 1433566 704619 728947
In [5]:
# dfのSeriesを確認
df.columns
Out[5]:
Index(['都道府県コード', '都道府県名', '元号', '和暦(年)', '西暦(年)', '注', '全人口', '男', '女'], dtype='object')
In [6]:
# 各Seriesのdtypeの確認
df.dtypes
Out[6]:
都道府県コード    object
都道府県名      object
元号         object
和暦(年)       int64
西暦(年)       int64
注          object
全人口        object
男          object
女          object
dtype: object
In [7]:
# 人口を数値データに変換
for col in ["全人口", "男", "女"]:
    df[col] = pd.to_numeric(df[col], errors="coerce")

pd.to_numeric?をみると

Signature: pd.to_numeric(arg, errors='raise')

errors : {'ignore', 'raise', 'coerce'}, default 'raise'

  • If 'raise', then invalid parsing will raise an exception
  • If 'coerce', then invalid parsing will be set as NaN
    • If 'ignore', then invalid parsing will return the input

errors="coerce"とキーワード引数を与えてやれば、キャストできないものを欠損値として置き換えてくれるそうです。
デフォルトではエラーを吐き出すという設定になっていますね。

In [8]:
df.dtypes
Out[8]:
都道府県コード     object
都道府県名       object
元号          object
和暦(年)        int64
西暦(年)        int64
注           object
全人口        float64
男          float64
女          float64
dtype: object
In [9]:
# 組み込み関数のset()と似た働き
df["都道府県名"].unique()
Out[9]:
array(['全国', '北海道', '青森県', '岩手県', '宮城県', '秋田県', '山形県', '福島県', '茨城県',
       '栃木県', '群馬県', '埼玉県', '千葉県', '東京都', '神奈川県', '新潟県', '富山県', '石川県',
       '福井県', '山梨県', '長野県', '岐阜県', '静岡県', '愛知県', '三重県', '滋賀県', '京都府',
       '大阪府', '兵庫県', '奈良県', '和歌山県', '鳥取県', '島根県', '岡山県', '広島県', '山口県',
       '徳島県', '香川県', '愛媛県', '高知県', '福岡県', '佐賀県', '長崎県', '熊本県', '大分県',
       '宮崎県', '鹿児島県', '沖縄県', '人口集中地区', '人口集中地区以外の地区'], dtype=object)

都道府県別の時系列を見てみたいので、「全国」と最後の2つは取り除きましょう。
DataFrame.dropはindexが引数に一致している行を削除したDataFrameを返す関数です。

In [10]:
# 都道府県の行だけを抽出する
df = df[df["都道府県名"].isin(df["都道府県名"].unique()[1:-2])]

さて、解析のための準備が整いました。
都道府県名をkeyにしてgroupbyし、その勾配を求める自作関数を作れば良さそうです。
indexはこれから時系列として扱うので西暦に変更しておきます。

In [11]:
df.index = df['西暦(年)']

試しに各都道府県の人口推移をプロットしてみます。

In [12]:
df.groupby("都道府県名")["全人口"].plot(x="西暦")
plt.show()

さて、このDataFrameから人口増減勾配を求める方法を考えましょう。
そのような方法はたくさんありますが今回は擬似逆行列を使って素早く求めましょう。
$$d=Gm$$ のとき$、G^\dagger$を擬似逆行列とすると $$m=G^\dagger d$$ となります。

In [13]:
# Seriesを受け取って、勾配を返す関数
def calc_slope(sr):
    
    # 欠損値を取り除く
    sr = sr.dropna()
    
    # x軸として年を取る
    x = sr.index.values
    
    # Green関数(直線なのでパラメータ2つ)
    G = np.vstack((x, np.ones_like(x))).T
    d = sr.values

    # 直線のパラメータ
    params = np.linalg.pinv(G) @ d
    
    # 勾配のみを返す
    return params[0]
In [14]:
increase_rate = df.groupby("都道府県名")[["全人口", "男", "女"]].agg(calc_slope)
increase_rate.head()
Out[14]:
全人口
都道府県名
三重県 9100.340752 4410.786917 4689.553835
京都府 15529.986617 7108.792782 8421.193835
佐賀県 1806.813083 722.221805 1084.591278
兵庫県 39889.076992 18437.361504 21451.715489
北海道 36862.745263 15877.846165 20984.899098

ようやく、都道府県ごと、ついでに性別別の人口推移勾配が求まりました。

In [15]:
fig, ax = plt.subplots(figsize=(6, 10), dpi=200)
increase_rate.sort_values("全人口").plot.barh(ax=ax)
plt.title("都道府県別人口増減率", fontsize=20)
plt.xlabel("人口増減率(人/年)", fontsize=20)
plt.tight_layout()
plt.show()

完成です。
今回は都道府県別を調べましたが、データさえあれば、(コードをほとんど変えずに)市町村でもできることが分かってもらえると思います。
このようにpandasには汎用性の高い機能がたくさんあり、それらを組み合わせる技術が問われていくのだろうと思います。

もっとPandasを知りたい人へ

参考にしてほしい本として「Pythonによるデータ分析入門(O'REILLY)」があります。
これはPandasを作った人の本であり、(当然ながら)Pandasについてとても詳細に書かれています。
読んだら当然理解できるはずですが、読まなくてもPandasを使いながらググったり、ドキュメントを読んでいると自然と必要な機能は分かってくると思います。

誤字やおかしい点などがあったら @zawawahoge (Twitter) にお気軽にご連絡ください。

トップページに戻る