目的
年齢別人口の男女比を都道府県ごとにクラスタリング分析してみる。
前回記事2つを踏まえて、今回の分析を実施しましたので、適宜前記事を参照ください。
国勢調査データのダウンロードと前処理
前回記事と同じ。詳細は前回記事を参照
import pandas as pd
import numpy as np
import unicodedata
def prepro_kokusei(data_path: str) -> pd.DataFrame:
'''
国勢調査の統計データを前処理する関数
Params:
data_path: str
zip_fileのあるパス
Returns:
df: pd.DataFrame
前処理済みのデータ
'''
df = pd.read_csv(data_path, encoding='cp932', header=[0, 1])
front_col = [col for col in df.columns.get_level_values(0) if not col.startswith('T00')]
back_col = [col for col in df.columns.get_level_values(1) if not col.startswith("Unnamed:")]
new_col = front_col + back_col
df.columns = new_col
for col in df.loc[:, '総数、年齢「不詳」含む':].columns:
df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0).astype(int)
# 変更用の辞書を作成
henko_dict = {
'年齢「不詳」含む': 'all',
'総数': 'total_',
'男': 'men_',
'女': 'women_',
'の': '',
'、': '',
'歳': '_age',
'未満': '_less',
'以上': '_over',
'~': '_'
}
# 変更したいカラム名のリストを変数に格納
cols = list(df.columns)
# 変更用の辞書を反映する
for k, v in henko_dict.items():
cols = [col.replace(k, v) for col in cols]
# 全角の数値を半角に変換
cols = [unicodedata.normalize('NFKC', col) for col in cols]
# カラム名を作成したものに置き換え
df.columns = cols
# 市区町村のみ抽出
df = df[df['HYOSYO']==1]
# 不要なデータを削除
df.drop(['HYOSYO','NAME','HTKSYORI','HTKSAKI', 'GASSAN'],axis=1,inplace=True)
return df
人口データ処理
取得できたデータフレームを処理し、男女比を計算する。
- 年齢別男女別の人口のみが必要なため、それ以外のデータ列を削除
- 男女別のデータフレームに分離(のちのため、総人口としてもデータフレーム化)
- 男女差、男女比を計算
# 人口データ処理
def get_men_women_ratio(df):
# men women のみ必要なので、それ以外は削除する
# 削除するカラム名(menを含まないカラム名、なお、womenにmenは含まれる)
del_columns = [ col for col in df.columns if not 'men' in col]
# 削除するカラム名(総人口のallを含むカラム名)
del_columns += [ col for col in df.columns if 'all' in col]
# 削除するカラム名(5歳刻み以外のカラム名)
del_columns += [ col for col in df.columns if '15_age_less' in col]
del_columns += [ col for col in df.columns if '15_64_age' in col]
del_columns += [ col for col in df.columns if '65_age_over' in col]
# 不要なカラムを削除
df.drop( del_columns, axis=1, inplace=True)
# _age は不要なので削除
cols = [col.replace('_age', '') for col in df.columns]
df.columns = cols
# 男女別に分離して合計
# 男性
del_columns = [ col for col in df.columns if 'women' in col]
df_men = df.drop( del_columns, axis=1)
cols = [col.replace('men_', '') for col in df_men.columns]
df_men.columns = cols
df_men_sum = df_men.sum(axis=0)
# 女性
del_columns = [ col for col in df.columns if not 'women' in col]
df_women = df.drop( del_columns, axis=1)
cols = [col.replace('women_', '') for col in df_women.columns]
df_women.columns = cols
df_women_sum = df_women.sum(axis=0)
# 男女別人口をマージ
df_sum = pd.DataFrame(data=[df_men_sum,df_women_sum],index=['men','women']).T
df_sum
# 合計、男女差、男女比を計算
df_sum['total'] = df_sum.sum(axis=1)
df_sum['diff'] = df_sum['men'] - df_sum['women']
df_sum['ratio'] = df_sum['men'] / df_sum['women'] * 100
return df_sum
データ確認
福島県と大阪府のデータを見てみる。
df_07 = prepro_kokusei('./data/tblT001082C07.zip') # 福島県
df_07 = get_men_women_ratio(df_07)
df_07
men women total diff ratio
0_4 30690 29909 60599 781 102.611254
5_9 35789 33911 69700 1878 105.538026
10_14 38889 36964 75853 1925 105.207770
15_19 42169 39011 81180 3158 108.095153
20_24 37448 32551 69999 4897 115.044085
25_29 41082 36357 77439 4725 112.996122
30_34 45940 41989 87929 3951 109.409607
35_39 52093 48246 100339 3847 107.973718
40_44 59183 54559 113742 4624 108.475229
45_49 64456 59844 124300 4612 107.706704
50_54 57946 55647 113593 2299 104.131400
55_59 61032 59410 120442 1622 102.730180
60_64 65995 65283 131278 712 101.090636
65_69 72211 73120 145331 -909 98.756838
70_74 67159 69280 136439 -2121 96.938510
75_over 111044 180011 291055 -68967 61.687341
df_27 = prepro_kokusei('./data/tblT001082C27.zip') # 大阪府
df_27 = get_men_women_ratio(df_27)
df_27
men women total diff ratio
0_4 162354 155060 317414 7294 104.703986
5_9 176474 169466 345940 7008 104.135343
10_14 187534 178611 366145 8923 104.995773
15_19 203718 197103 400821 6615 103.356113
20_24 231542 235653 467195 -4111 98.255486
25_29 224908 233048 457956 -8140 96.507157
30_34 230653 236371 467024 -5718 97.580922
35_39 247335 254147 501482 -6812 97.319661
40_44 280736 291626 572362 -10890 96.265765
45_49 350481 361438 711919 -10957 96.968498
50_54 311958 321721 633679 -9763 96.965383
55_59 264101 273984 538085 -9883 96.392855
60_64 218762 230219 448981 -11457 95.023434
65_69 237306 261943 499249 -24637 90.594519
70_74 284877 333855 618732 -48978 85.329559
75_over 493162 750580 1243742 -257418 65.704122
男女比(ratio)の傾向が違うようだ。
福島県は、60代まで100%以上なのに対し、大阪府は、20代で早々100%を下回る。
この要因を探るべく、全都道府県のデータを可視化して、分析してみる。
全都道府県の処理
pref_list.csv については、前記事参照。
都道府県ごとにデータを読み込み、前処理し、男女比、男女別人口をデータフレーム化する。
pref_list = pd.read_csv('./data/pref_list.csv',index_col=0)
# 都道府県ごとの年齢別人口男女比のデータフレーム
df_ratio = pd.DataFrame()
# 都道府県ごとの年齢別男女別人口のデータフレーム
df_men = pd.DataFrame()
df_women = pd.DataFrame()
# 都道府県のループ
for pref_no, row in pref_list.iterrows():
# 都道府県名称
pref_name = row['都道府県名']
# ファイル名称
filename = './data/tblT001082C' + str(pref_no).zfill(2) + '.zip'
# 読み込みと前処理
df = prepro_kokusei(filename)
# 人口データ処理
df = get_men_women_ratio(df)
# 男女比
df_ratio[pref_name] = df['ratio']
# 男女別人口
df_men[pref_name] = df['men']
df_women[pref_name] = df['women']
print(df_ratio)
北海道 青森県 岩手県 宮城県 秋田県 \
0_4 104.579874 103.410701 104.232978 105.498728 103.962873
5_9 104.393506 105.360513 104.281249 105.564115 104.094406
10_14 105.551300 103.895555 105.590726 104.717378 106.062336
15_19 105.252171 107.265637 106.175072 105.957728 106.155330
20_24 104.474317 110.310762 110.124739 107.047419 112.151163
25_29 100.935962 107.391422 106.817981 102.284923 108.706159
30_34 100.444689 103.293929 105.171951 102.384538 103.849200
35_39 97.978531 100.938865 103.356171 100.365235 104.477612
40_44 97.769903 101.477859 104.656374 102.261284 105.514589
45_49 97.300952 99.062150 105.771977 102.509347 101.473243
50_54 92.765815 95.326722 100.525141 102.097266 97.674419
55_59 91.209515 93.466124 100.526117 99.044007 94.416626
60_64 91.875965 90.324438 98.213912 96.773974 94.110750
65_69 88.379142 89.508252 95.870718 94.629748 92.568437
70_74 82.406836 85.384755 90.875134 91.975451 88.998000
75_over 60.812486 55.569690 58.513527 64.023940 56.012671
可視化
全都道府県をまとめて可視化する。
import matplotlib.pyplot as plt
import japanize_matplotlib
fig_size_x = 12
fig_size_y = 5
fig = plt.figure(figsize=(fig_size_x, fig_size_y))
plt.plot(df_ratio)
plt.title( '年齢別人口男女比(都道府県別)')
plt.xlabel('年代')
plt.ylabel('男性/女性の比率(%)')
plt.grid(axis='y')
plt.grid(axis='x')
plt.show()
男性/女性の比率(%)は、女性100人いた場合、男性が何人いるか、を示している、と考えやすい。
100%以上の場合は、男性が多く(女性が少ない)、100%以下の場合は、男性が少ない(女性が多い)。
10代前半までは、105%前後で、各都道府県でのばらつきが少ない。これは以下の理由であろう。
- 遺伝的に男が生まれやすい(105%であること理由)
- 乳幼児死亡率は男が高い(体が弱い)ため、
- 狩りや戦争で男が死ぬ確率が高いため、
- ⇒種を保存するための遺伝的な傾向である
- 現代では乳幼児死亡率は下がり、男女差もない(10代前半まで変わらない理由1)
- 10代前半までは生まれた土地(都道府県)から移動することが少ない(10代前半まで変わらない理由2)
- 仮に親の転勤があっても単身赴任するため、同じ土地に残ることが多いのだろう。
ということが要因と考えられる。
10代後半以降は、都道府県でばらつきが多いが、全体的に、年齢を追うごとに、男性の比率が下がっていき、75歳以上となると、極端に下がり、60%~70%まで下がる。
これは、乳幼児死亡率だけでなく、20代以降にも男性の死亡率が高いのだろうか?乳幼児死亡率は現代では大きく改善したが、20代以上の男性の死亡率は改善しないのか?
20代以降の多くの男性が海外に移住する、もしくは、20代以降の外国人女性が日本に移住してくる、ということがこの数値にまで表れてくるとは考えにくい。
ましてや、(世界的に見れば戦争はなくなってはいないが)日本では戦争はないので男性が戦争で亡くなるということもないだろう。
次に、男女比率をクラスタリング分析してみる。
クラスタリング分析
クラスタリング分析については、前記事を参照。
from scipy.cluster import hierarchy
import japanize_matplotlib
fig = plt.figure(figsize=(fig_size_x, fig_size_y))
method = 'ward'
Z = hierarchy.linkage(df_ratio.T, method=method)
hierarchy.dendrogram(Z, color_threshold=0,labels=df_ratio.columns)
plt.ylabel('distance')
plt.title( '年齢別人口男女比')
plt.xticks(rotation=90)
plt.show()
地理的な条件は全く考慮していないはずであるのに、近隣地域が、近くに配置されているのが不思議である。
例えば、左側には神奈川、埼玉、千葉、東京の首都圏が、中央右側には、奈良県、京都府、大阪府の関西圏が隣接している。
これを、当てはまりのよさそうな、5クラスタに分類してみる。
from sklearn.cluster import AgglomerativeClustering
n_clusters = 5
clustering = AgglomerativeClustering(linkage=method, n_clusters=n_clusters)
clustering.fit(df_ratio.T)
df_clustering_result = pd.DataFrame( clustering.labels_, index=df_ratio.columns, columns=['label'])
print(df_clustering_result.head())
label
北海道 0
青森県 0
岩手県 3
宮城県 0
秋田県 3
各クラスタ毎に可視化、及び、考察
全国平均、及び、各クラスタの平均をとり、可視化する。
fig = plt.figure(figsize=(fig_size_x, fig_size_y))
#全国平均
df_men_sum = df_men.sum(axis=1)
df_women_sum = df_women.sum(axis=1)
df_total_ratio = df_men_sum / df_women_sum * 100
plt.plot(df_total_ratio,label='全国平均', lw=5, ls=':')
# クラスタ毎に処理
for i in range(n_clusters):
df_work = pd.DataFrame()
for j, rec in df_clustering_result.iterrows():
# 対象クラスタに分類された結果のみ抽出
if rec.label==i:
# インデックス(=都道府県名称)
name = j
df_work[name] = df_ratio[name]
# クラスタ毎の平均をプロット
plt.plot(df_work.mean(axis=1),label=f'#{i}クラスタ')
plt.title( '年齢別人口男女比(全国平均、クラスタ別)')
plt.xlabel('年代')
plt.ylabel('男性/女性の比率(%)')
plt.grid(axis='y')
plt.grid(axis='x')
plt.legend()
#plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0, fontsize=18)
plt.show()
男女比が上がる(男性比率が100%を超えるか)か、上がるとすればどの年代までか、により、分類されているようである。
その後は、ゆるやかに(全国平均と同様に)男性比率が下がっているようである。(一つを除いて)
クラスタ毎に傾向を分析するため、クラスタ内全都道府県のグラフを、全国平均とともに可視化する。
# クラスタ毎に処理
for i in range(n_clusters):
fig = plt.figure(figsize=(fig_size_x, fig_size_y))
#全国平均
plt.plot(df_total_ratio,label='全国平均', lw=5, ls=':')
for j, rec in df_clustering_result.iterrows():
# 対象クラスタに分類された結果のみ抽出
if rec.label==i:
plt.plot(df_ratio[j],label=f'{j}')
plt.title( f'年齢別人口男女比(#{i}クラスタ)')
plt.xlabel('年代')
plt.ylabel('男性/女性の比率(%)')
plt.grid(axis='y')
plt.grid(axis='x')
plt.legend()
plt.show()
#0 クラスタ
北海道、東北(北部)、中国、四国が多い。
全国平均にもっとも近いクラスタである。
他地域からの転入や他地域への転出が少ないと考えられる。これは、首都圏から遠いためではないだろうか?
#1 クラスタ
首都圏が多いが、沖縄県も含まれる。
50代まで、男女比率がほぼ105%である。
日本全国で見ると、男性比率は20代以降徐々に減少しているにもかかわらず、男女比一定となっている。
50代まで、男女比が変わらないのは、医療体制が整っており、男性の死亡率が低いためか、他地域から転入してくるのか、謎である。
沖縄県は、他地域からの転入は考えられないので、長寿県ということから20代以降の男性死亡率が低いためと考えると、首都圏でも男性死亡率が低いのであろうか?
#2 クラスタ
関西と九州が多い。
20代前半に、男性比率が減少している。
大阪、福岡だけなら、20代女性が、他地域から転入してくる、とも考えられるが、
関西、九州全域で同じ傾向であることを考えると、20代の男性が、首都圏に転出する。と考えたほうが無難ではないだろうか。
#3 クラスタ
東北(北部)、北陸、甲信などが多い。
20代前半に、男性比率が上昇している。
これも、他地域から男性が転入してくるということは考えにくいので、20代前半の女性が、首都圏に転出しているのだろう。
#4 クラスタ
北関東や東海など、首都圏の近隣県が多い。
20代から、男性比率が上昇し、20代後半でさらに上昇している。
首都圏が近いため、20代前半はもちろん、20代後半になっても、女性の首都圏への転出が多いのだろう。
20代前半より、20代後半のほうが男性比率が高い(女性比率が低い)のは謎である。
通常、高校卒業、大学卒業で上京するだろうが、20代後半でさらに多くの女性が上京しているのだろうか?
まとめ
年齢別男女人口比で、地域特性が見られたが、解釈が難しく、いろいろな推測ができるので、面白かった。
- 首都圏近隣から女性が首都圏に転入してくる。
- 首都圏への距離が近い地域では、男性より、女性のほうが、首都圏への憧れが強く、上京する傾向が強い。
- 首都圏への距離が近いと、女性でも上京しやすい(帰省しやすい、親の了承も得やすい)
- 関西、九州から、それより多くの男性が首都圏に転入してくる。そのため、首都圏では男性比率が高い傾向となる。
- 首都圏への距離が遠くとも、男性は首都圏へ憧れ、上京する。(関西、九州のみ)
- 首都圏への距離が遠いと、女性は上京しにくい(帰省しにくい、親の了承も得にくい)
- 首都圏から遠い地域からは、首都圏への転入が少ない。
- 首都圏への距離が遠い、北海道、東北(北部)、中国、四国では、地元にとどまる傾向が強い。
九州は首都圏から遠いはずだが、それでも男性が首都圏に転入してくるということは、九州男児は、果敢に都を目指して挑戦しているのだろう。(勝手に長〇さんをイメージしてしまう。死にたいくらいに憧れた花の都"大東京"♬)
また、平均寿命は男性より女性が長いので、50代もしくは60代以降に、女性比率が高くなるのだろうと思っていたが、20代以降にその傾向が表れているということは大きな驚きであった。(死亡率が原因なのかどうかは私にはわからないが、)
以上の考察は、推測なので、実際とあっているのかはわかりません。