Quantcast
Channel: pandas - よちよちpython
Viewing all articles
Browse latest Browse all 30

【matplotlib】年代別の年間死亡者数とコロナ死亡者数を棒グラフと円グラフで描く

$
0
0

今回は、年代別で新型コロナの死亡者数年間の死亡者数をグラフの作成をしながら比較して見る。
matplotlibでの棒グラフと円グラフ、pandasでの積み上げ棒グラフの練習を兼ねて。


新型コロナは騒動当初から「重症化傾向や死亡者は高齢者、さらには基礎疾患のひとが多い」と言われてきた。コロナのデータを見ても確かにそのようになっている。しかしそれは別にコロナに限ったことではなく、年間を通した死亡者数は高齢者のほうが多い。

年間の年代別死亡者と、新型コロナの年代別死亡者をそれぞれグラフ化することによって、改めてその傾向を見てみる。




【実行環境】

  • Windows10 WSL:Ubuntu
  • Anaconda
  • Python3.8
  • Jupyter Notebook
  • ライブラリ
    • pandas、matplotlib、japanize-matplotlib(豆腐文字化け回避の日本語表示用:個人的事情)
# インストール
$ pip install pandas matplotlib japanize-matplotlib



目次



使用するデータ(3つ)

  • 人口統計、年代別死亡者数
    • 厚生労働省の「人口動態統計年報 主要統計表(最新データ、年次推移)」のページにある、
      「死亡 第4表 性・年齢階級別にみた死亡数・死亡率(人口10万対)の年次推移」をExcelにコピペしたもの

  • 新型コロナの年代別死亡者数
  • 新型コロナの累計死亡者数



人口動態統計年報 年齢階級別にみた死亡数

「人口動態統計年報 主要統計表(最新データ、年次推移)」というページからExcelにコピペしたデータを使う。

import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib


# データファイル (元は厚生労働省のデータ
fname = '年次・年齢階級別の死亡者数.xlsx'

df = pd.read_excel(fname)
df = df.rename(columns={'Unnamed: 0':'年齢階級'})
df
年齢階級19851990199520002005200720082009
00~4108347983704052694102380937473460
15~9179113771235738655552557534
210~14164912421184744590534516487
315~1942124353336223971802159916211467
420~2446694795508740353370304929772960
525~2947254277459648174170364136223561
630~3467335038512955965952541052824931
735~39111278551683970467469767976907786
840~441588415311128141047910238100641003410375
945~492270721728241361973615754149661467414584
1050~543585130258329463584328964245622332122686
1155~594557547541447324599249579497774614641934
1260~645084562728683106068062258585056076761606
1365~696473069931890898905880829800948049182052
1470~749599189813102443116528120825116667115785109527
1575~79121250127523125428131000159362159772163351159471
1680~84123573139549157863147060174185188314198991201406
1785~8986351111120134363148980165385173407183113189913
1890~9434768528147229590913127573134751140585139746
1995~99777212355198312923050503589836476467799
20100歳以上8251569278047899578116781383714949
21総数7522838203059221399616531083796110833411424071141865

年齢階級は5歳ずつに分けてある。年次は1985年~2009年まで飛び飛び。



年次別の年間死亡者と推移の棒グラフ

# データ
y = (df.iloc[21,1:]/10000).tolist() # 万人単位にする為10000で割った
x = list(map(str, df.columns[1:]))

print('年次:',x)
print('死亡者総数:',y)
年次: ['1985', '1990', '1995', '2000', '2005', '2007', '2008', '2009']
死亡者総数: [75.2283, 82.0305, 92.2139, 96.1653, 108.3796, 110.8334, 114.2407, 114.1865]
# 年次別の年間死亡者と推移 グラフ
plt.figure(figsize=(15, 12))
plt.bar(x, y, width=0.6)
plt.title('年次別の年間死亡者と推移', size=20)
plt.xlabel('年次', size=15)
plt.ylabel('年間死亡者総数(万人)', size=14)
plt.xticks(size=15)
plt.yticks(size=15)
plt.grid()
plt.savefig('年次別の年間死亡者と推移棒グラフ.jpg')
plt.show()

f:id:chayarokurokuro:20210804182832j:plain

年間の死亡者総数は上昇傾向。2009年の総数は114万1865人。2020年のデータはここには載っていないが138万4544人。



年次別の年齢階級ごとの積み上げ棒グラフ

年齢階級ごとの積み上げ棒グラフを、年次ごとに棒にする。

積み上げ棒グラフをmatplotlibで描くと面倒ですが、Pandasのグラフ機能を使うと比較的簡単に描けます。
行が一つの棒に積みあがるグラフになるので、下のコードではデータを転置させている。

# データ 
df_stacked = df.iloc[:-1, :] # 総数行以外に絞り込み
df_stacked = df_stacked.set_index('年齢階級') # インデックスを置換
df_stacked = df_stacked.T # 行と列を転置#  表示
df_stacked
年齢階級0~45~910~1415~1920~2425~2930~3435~3940~4445~49...55~5960~6465~6970~7475~7980~8485~8990~9495~99100歳以上
198510834179116494212466947256733111271588422707...4557550845647309599112125012357386351347687772825
1990798313771242435347954277503885511531121728...4754162728699318981312752313954911112052814123551569
1995704012351184336250874596512968391281424136...44732683108908910244312542815786313436372295198312780
20005269738744239740354817559670461047919736...45992606808905811652813100014706014898090913292304789
20054102655590180233704170595274691023815754...495796225880829120825159362174185165385127573505039578
20073809552534159930493641541076791006414966...4977758505800941166671597721883141734071347515898311678
20083747557516162129773622528276901003414674...4614660767804911157851633511989911831131405856476413837
20093460534487146729603561493177861037514584...4193461606820521095271594712014061899131397466779914949

8 rows × 21 columns

df_stacked.columns
Index(['0~4', '5~9', '10~14', '15~19', '20~24', '25~29', '30~34', '35~39',
       '40~44', '45~49', '50~54', '55~59', '60~64', '65~69', '70~74', '75~79',
       '80~84', '85~89', '90~94', '95~99', '100歳以上'],
      dtype='object', name='年齢階級')
df_stacked.index
Index([1985, 1990, 1995, 2000, 2005, 2007, 2008, 2009], dtype='object')
# 年次別の年代別死亡者総数 積み上げ棒グラフ作成
fig, ax = plt.subplots(figsize=(25,15))

# 積み上げ棒グラフ描画
df_stacked.plot.bar(y=df_stacked.columns, ax=ax, stacked=True)

# タイトル等の設置と設定
plt.title('年次別の年代別死亡者総数積み上げ棒グラフ', size=28)
plt.xlabel('年次', size=20)
plt.ylabel('死亡者総数', size=20)
plt.xticks(size=20, rotation=0)
plt.grid()

# グラフ保存
plt.savefig('年次別の年代別死亡者総数積み上げ棒グラフ.jpg')
# 表示
plt.show()

f:id:chayarokurokuro:20210804182950j:plain

グラフの真ん中に自動的に設置された凡例は上から順に年齢が若い。
一方、グラフは逆に上の方が高齢者。



2列ずつ足した年齢階級のデータを作成

年齢階級が5歳ずつで細かいので、2列ずつ加算していって階級数を半分にする。手作業で。

df_stacked.head(1)
年齢階級0~45~910~1415~1920~2425~2930~3435~3940~4445~49...55~5960~6465~6970~7475~7980~8485~8990~9495~99100歳以上
198510834179116494212466947256733111271588422707...4557550845647309599112125012357386351347687772825

1 rows × 21 columns

# 2列ずつ足したデータを生成
df_stacked2 = pd.DataFrame() # 空のデータフレーム# 空データフレームに横に結合
df_stacked2 = pd.concat([
    df_stacked.iloc[:, 0:2].sum(axis=1),
    df_stacked.iloc[:, 2:4].sum(axis=1),
    df_stacked.iloc[:, 4:6].sum(axis=1),
    df_stacked.iloc[:, 6:8].sum(axis=1),
    df_stacked.iloc[:, 8:10].sum(axis=1),
    df_stacked.iloc[:, 10:12].sum(axis=1),
    df_stacked.iloc[:, 12:14].sum(axis=1),
    df_stacked.iloc[:, 14:16].sum(axis=1),
    df_stacked.iloc[:, 16:18].sum(axis=1),
    df_stacked.iloc[:, 18:20].sum(axis=1),
    df_stacked.iloc[:, 20:22].sum(axis=1)
], axis=1)

# カラム名の変更
df_stacked2 = df_stacked2.rename(columns={0:'0~9', 1:'10~19', 2:'20~29', 3:'30~39',4:'40~49', 5:'50~59',6:'60~69', 7:'70~79',8:'80~89',9:'90~99',10:'100歳以上'})

# 表示
df_stacked2
0~910~1920~2930~3940~4950~5960~6970~7980~8990~99100歳以上
1985126255861939417860385918142611557521724120992442540825
1990936055959072135893703977799132659217336250669651691569
1995827545469683119683695077678157399227871292226921262780
20006007314188521264230215818351497382475282960401201434789
20054757239275401342125992785431430872801873395701780769578
200743612133669013089250307433913859927643936172119373411678
200843042137659912972247086946714125827913638210420534913837
200939941954652112717249596462014365826899839131920754514949
# 年次別の年代別死亡者総数 積み上げ棒グラフ作成
fig, ax = plt.subplots(figsize=(25,15))

# 積み上げ棒グラフ
df_stacked2.plot.bar(y=df_stacked2.columns, ax=ax, stacked=True)

# タイトル等
plt.title('年次別の年代別死亡者総数積み上げ棒グラフ', size=28)
plt.xlabel('年次', size=20)
plt.ylabel('死亡者総数', size=20)
plt.xticks(size=20, rotation=0)
plt.grid()

# 画像保存
plt.savefig('年次別の年代別死亡者総数積み上げ棒グラフ2.jpg')
# 表示
plt.show()

20210804183101

凡例は上から若い順、棒グラフは上から高齢者。天に近い。
ピンクの60~69歳以上の年齢階級までが棒のほとんどを占めている。



2009年の年代別死亡者総数の棒グラフ

今度は、データの最新年次の2009年を見る。
横軸:年齢階級縦軸:死亡者総数の棒グラフを描く。

# 2009年のデータ
pd.DataFrame(df_stacked2.iloc[-1, :])
2009
0~93994
10~191954
20~296521
30~3912717
40~4924959
50~5964620
60~69143658
70~79268998
80~89391319
90~99207545
100歳以上14949
# 2009年の年代別棒グラフ# データ
label = df_stacked2.columns
y_data = df_stacked2.iloc[-1, :].values

# グラフ描画
plt.figure(figsize=(18,15))
plt.bar(label, y_data, color='purple')
plt.title('2009年の年代別死亡者総数', size=25)
plt.xlabel('年代', size=20)
plt.ylabel('死亡者総数', size=20)
plt.xticks(size=20)
plt.grid()

plt.savefig('2009年の年代別死亡者総数棒グラフ.jpg')
plt.show()

f:id:chayarokurokuro:20210804183420j:plain

平均寿命の定義は、「その年に生まれた子が何歳まで生きるか」つまり余命。その年に亡くなった方の平均年齢ではない。測定値ではなく、予測値。
日本の平均寿命が延びた大きな要因は、上下水道の完備だそうだ。新生児の死亡数が激減した。我が町では江戸時代にヨーロッパ人が持ち込んだ感染症が流行った際に水路の完備を行ったりしている。水は大切。



2009年の年代別死亡者総数の円グラフ

上の棒グラフを円グラフのパーセンテージで表す。

# 2009年の年代別円グラフ#データ
data = df_stacked2.iloc[-1, :].values # データ
label = df_stacked2.columns  # ラベル名# 円グラフ描画
plt.figure(figsize=(15,15))

plt.pie(
    x=data,   # データ
    labels=label,  # ラベルの設置
    autopct='%1.1f%%', # パーセント表示のオンとフォーマット設定
    startangle=90, # スタート位置を0時から
)

# タイトル設置
plt.title('2009年の年代別 年間死亡者総数 円グラフ', size=20)
# ラベルのフォントサイズ
plt.rcParams['font.size'] = 18# 保存
plt.savefig('2009年の年代別死亡者総数円グラフ.jpg')

# 表示
plt.show()

f:id:chayarokurokuro:20210804183502j:plain

数値や文字が重なって見えないところがあるが、直し方がわからないのでそのままにしている。

matplotlibの円グラフは、デフォルトで時計の3時から右回りになっている。そのためplt.pie()の引数startangleで0時からに変更した。
外国では3時から右回りが円グラフの当たり前な描き方なのか?と思って海外メディアの円グラフの画像を検索したが、特にそうではない。直交座標の象限を利用してあるのか?と思ったが、それなら左回りになるでしょうし。

円グラフのスタートはデータの最終行から始まっている。ということは、0時スタートに変更したが、直交座標の象限通りにデータの最上行から左回りで描画されているとも考えられる。これだな。



コロナの年代別死亡者数

データは東洋経済オンラインのdemography.csvというファイル。年代別のコロナのデータが入っている。
データの期間は不明。たぶん2020年3月ぐらいから現在2021年7月28日までの、1年以上の累計。

# コロナの年代別死亡者データ (元は東洋経済オンライン
fname = 'demography.csv'# csvファイル読込
df_demo = pd.read_csv(fname)
df_demo
yearmonthdateage_grouptested_positivehospitalizedseriousdeath
0202172810歳未満30813254700
1202172810代68613503400
2202172820代2017581438009
3202172830代1341459810129
4202172840代1300031037427116
5202172850代114826934865317
6202172860代708646192100990
7202172870代6025158841373076
8202172880代以上589055390798346
92021728不明1057412375317

ワクチン接種が始まる前までは、20代は2,3人だったのに。ワクチン死。



コロナの年代別死亡者総数 棒グラフ

横軸:age_group縦軸:deathで棒グラフを描く。

# 棒グラフ描画# データ
x = df_demo['age_group']
y = df_demo['death']

# 描画
plt.figure(figsize=(15,12))
plt.bar(x, y)

# タイトル等
plt.title('コロナの年代別死亡者総数棒グラフ', size=25)
plt.xlabel('年代', size=18)
plt.ylabel('死亡者総数', size=18)
plt.xticks(size=18)
plt.grid()

# 保存
plt.savefig('コロナの年代別死亡者総数棒グラフ.jpg')

# 表示
plt.show()

f:id:chayarokurokuro:20210804183643j:plain



コロナの年代別死亡者総数 円グラフ

# コロナの年代別円グラフ#データ
label = df_demo['age_group']  # ラベル名
data = df_demo['death']   # データ# 円グラフ描画
plt.figure(figsize=(15,15))

plt.pie(
    x=data,   # データ
    labels=label,  # ラベルの設置
    autopct='%1.1f%%', # パーセント表示のオンとフォーマット設定
    startangle=90, # スタート位置を0時から
)

# タイトル設置
plt.title('コロナの年代別死亡者総数円グラフ', size=20)
# ラベルのフォントサイズ
plt.rcParams['font.size'] = 18# 保存
plt.savefig('コロナの年代別死亡者総数円グラフ.jpg')
# 表示
plt.show()

f:id:chayarokurokuro:20210804183725j:plain
コロナの年代別死亡者数 円グラフ

これは、決定的に、高齢者寄りが顕著。

字の重なりの解消法がわからないので放置した。

# 年代別死亡者総数占有率
df_dtrate = pd.DataFrame([df_demo['age_group'], df_demo['death'],  df_demo['death']/df_demo['death'].sum()])
print('60代~80代以上:', df_dtrate.iloc[1,:][6:9].sum())
df_dtrate
60代~80代以上: 12412
0123456789
age_group10歳未満10代20代30代40代50代60代70代80代以上不明
death0092911631799030768346317
death0.00.00.0006820.0021970.0087880.0240150.0750.233030.6322730.024015



コロナの月別死亡者集計

最後に、厚生労働省オープンデータdeath_total.csvを月別で集計し、棒グラフにする。



コロナの累計死亡者を日毎に変換

このデータは累計データになっているので、日毎に変換する。

import numpy as np

# 厚労省オープンデータ コロナの死亡者数データ
fname = 'death_total.csv'# CSVを日付インデックスにして読み込み
df_total = pd.read_csv(fname, index_col=0, parse_dates=True)
# 日毎に変換
df_d_daily = np.append(1, np.diff(df_total['死亡者数']))
# 死亡者数列を日毎に置換
df_total['死亡者数'] = df_d_daily
# 死亡者数列名のカラム名を変更
df_total = df_total.rename(columns={'死亡者数':'死亡者数(日毎)'})
# 表示
df_total
死亡者数(日毎)
日付
2020-02-141
2020-02-150
2020-02-160
2020-02-170
2020-02-180
......
2021-07-239
2021-07-248
2021-07-255
2021-07-268
2021-07-2714

530 rows × 1 columns



月別で集計

Pandasのresample().sum()を使うと、時系列データの一定期間の集計が簡単にできる。
インデックスは日付列で。

# 月別で集計
mon_data = df_total.resample('m').sum()
mon_data
死亡者数(日毎)
日付
2020-02-295
2020-03-3151
2020-04-30359
2020-05-31477
2020-06-3081
2020-07-3137
2020-08-31285
2020-09-30275
2020-10-31195
2020-11-30373
2020-12-311321
2021-01-312261
2021-02-282165
2021-03-311274
2021-04-301067
2021-05-312818
2021-06-301732
2021-07-31369



月別集計データの棒グラフ

集計した月別データを棒グラフにする。

# 月別データから棒グラフ# データ
data = mon_data['死亡者数(日毎)'].values
label = mon_data.index

# 棒グラフ
plt.figure(figsize=(15,8))
plt.bar(label, data, width=15)

# タイトル等
plt.title('コロナの死亡者数月別集計棒グラフ~2021-7-27まで', size=25)
plt.xlabel('日付', size=18)
plt.ylabel('人数', size=18)
plt.xticks(size=18)
plt.grid()

# 保存と表示
plt.savefig('コロナの死亡者数月別集計棒グラフ~2021-7-27まで.jpg')
plt.show()

f:id:chayarokurokuro:20210804183845j:plain
コロナの月別死亡者集計 棒グラフ

冬が多いのは分かるが、2021年6月・7月 5月・6月の死亡者数の多さは不自然。高齢者がワクチン接種し始めたころだ。ワクチン死かな。



おわりに

日本では年間138万人以上が亡くなる(2020年)。その多くを寿命を迎えるお年頃の高齢者が占める。コロナにしても極端に高齢者に偏る。そして、コロナの年間死亡人数は全体の年間死亡者総数の1%未満。1年以上ワクチンがなくとも幸い死亡者はそこまで増えていない。

結局コロナ騒動は、少数の高齢者が風邪ひいてコロナウィルス由来の肺炎で亡くなったのをカウントして大騒ぎする政治的イベントだという疑念は晴れない。しかも国際的に行われている。

大人な方は、「シラケつつ乗る、これである。」でこんな馬鹿な騒動を傍観しているんでしょうか?

長くなりました、以上です。


Viewing all articles
Browse latest Browse all 30

Trending Articles