棒グラフ・積み重ね棒グラフ

2022年の学校保健統計調査の身長の年齢別分布から男女17歳の身長を棒グラフにする。重なりがわかるように、少し透明(alpha=0.7)にした。元データは ‰ で 0.1 刻みだが、10倍して整数に直した。丸め誤差のため、合計 10000 にならない。

import matplotlib.pyplot as plt

# 高等学校 男/女 17歳 137-198cm 1/10000

m17 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 5, 3, 9, 20, 22,
       44, 54, 82, 123, 154, 222, 294, 339, 443, 524, 587, 622, 626,
       723, 693, 692, 656, 579, 499, 400, 367, 302, 234, 192, 137,
       109, 80, 49, 32, 30, 18, 12, 12, 1, 2, 0, 1, 1, 1, 0, 0, 1]

f17 = [3, 1, 3, 3, 4, 10, 16, 20, 39, 54, 76, 139, 184, 262, 342, 376,
       481, 599, 649, 721, 715, 720, 692, 731, 628, 562, 435, 394,
       292, 253, 184, 129, 102, 64, 40, 27, 16, 12, 8, 8, 2, 1, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

plt.bar(range(137, 199), m17, alpha=0.7, label="男性")
plt.bar(range(137, 199), f17, alpha=0.7, label="女性")
plt.legend()
plt.xlabel("身長(cm)")
plt.ylabel("割合(1万人中)")
17歳男女の身長

男女ともほぼ正規分布である。男女を合わせたら2峰になるだろうか。積み重ね棒グラフにしてみる。

plt.bar(range(137, 199), m17, label="男性")
plt.bar(range(137, 199), f17, bottom=m17, label="女性")
plt.legend()
plt.xlabel("身長(cm)")
plt.ylabel("割合(1万人中)")
17歳男女の身長

2峰というよりは頭が平らなカルデラのようになった。

世の中には正規分布の頭をつぶしたような分布はけっこう多い。共通テストの得点分布も、科目によっては、カルデラに近いものもある。受験者層が広い場合は、単一の正規分布ではなく、正規分布を重ねたような分布(混合正規分布)になるのは不思議ではない。

ちなみに、

import pandas as pd

df = pd.DataFrame({"男性": m17, "女性": f17})
df.plot(kind='bar', stacked=True)

でも積み重ね棒グラフが描けるが、横軸が名義尺度になってしまうようだ。