当サイトでは以下のページで新型コロナウイルスワクチンの接種状況を公開しています。
ここでは、上記のページで用いられているワクチンの接種状況を可視化するためのプログラムの一部を解説します。政府CIOポータルのワクチン接種状況からデータを取得してPythonを用いてグラフで可視化する方法です。なお、ここでお示ししているコード自体は説明用に改変しているので、上記ページで用いているコードとは異なります。
開発環境
- matplotlib 3.3.4
- ndjson 0.3.1
- Pandas 1.2.1
- Python 3.7.9
新型コロナワクチン接種状況に関するオープンデータ
もともと新型コロナウイルスワクチンの接種状況についての集計データは首相官邸のホームページで公開されていました。現在では、その集計情報に加えて政府CIOポータルにおいてワクチン接種者の属性ごとの接種回数についての情報がオープンデータとして公開されています。
このデータはVRS(ワクチン接種記録システム)に登録されたデータをそのまま公開しているので、データ公開のタイミングとしては首相官邸で公開されるものなどよりも早くなります。ただし、現状ではVRSに医療従事者の優先ワクチン接種の記録は統合できていないので、医療従事者のデータはここには含まれていないことには注意が必要です。現在データの統合作業が行われているようなので、そのうち将来的にはこのデータに医療従事者向けの接種回数も含まれるようになるのかもしれません。
なお、首相官邸で公開されているオープンデータの取得方法は以下の記事をご覧ください。
データの概要
政府CIOポータルで公開されているデータは以下の3種類になります。
- 都道府県別接種回数詳細 (NDJSON形式)
- 接種日別接種回数サマリー (CSV形式)
- 都道府県別累積接種回数サマリー (CSV形式)
このうち、「都道府県別接種回数詳細」がメインのデータになり、ワクチン接種者の以下の属性ごとの接種回数が日別に格納されています。
項目 | 型 | 説明 | 例 | |
---|---|---|---|---|
date | 接種日 | String | YYYY-MM-DD形式の接種日 | “2021-05-18” |
prefecture | 都道府県コード | String | JIS X 0401で標準化されたコード。 全国地方公共団体コードに基づく都道府県コードの先頭2文字に相当します。 例えば、北海道は01、東京都は13となります。 | “13” |
gender | 性別区分 | String | 接種者群の性別を表す区分値 ・M:男性 ・F:女性 ・U:不明 | “F” |
age | 年代区分 | String | 接種者群の年代を表す区分値 ・-64:64歳以下 ・65-:65歳以上 ・UNK:不明 | “65-“ |
medical_worker | 医療従事者フラグ | Boolean | 医療従事者の接種かどうかを表すフラグ ・true:医療従事者 ・false:一般接種者 | false |
status | 接種ステータス区分 | Integer | 接種ステータスを表す区分値 ・1:1回目接種または接種中となる接種ステータス ・2:2回目接種または接種完了となる接種ステータス 2回で接種が完了するワクチンの場合、1回目の接種時のステータスは1となり、2回目の接種時のステータスは2となります。 1回で接種が完了するワクチンの場合、接種時のステータスは2となります。 | 1 |
count | 接種回数 | Integer | (接種日, 都道府県コード, 性別区分, 年代区分, 医療従事者フラグ, 接種ステータス区分) の組に該当するワクチン接種回数 | 8282 |
このデータはNDJSON形式(改行区切りJSON形式)で提供されていて、実際のデータは以下のようになります。
date prefecture gender age medical_worker status count 0 2021-04-12 01 F -64 False 1 7 1 2021-04-12 01 F 65- False 1 84 2 2021-04-12 01 M -64 False 1 1 3 2021-04-12 01 M 65- False 1 21 4 2021-04-12 01 U UNK False 1 1 5 2021-04-12 02 F 65- False 1 142 6 2021-04-12 02 M 65- False 1 53 7 2021-04-12 02 U UNK False 1 2 8 2021-04-12 03 F 65- False 1 23 9 2021-04-12 03 M 65- False 1 27 ...(略)...
上記はデータの最初の10行の抜粋ですが、2021/4/12について都道府県ごとに性別区分・年代区分・医療従事者フラグ・接種ステータスごとに接種回数がcountで表示されています。例えば1行目から、2021/4/12の北海道(01)で64歳以下の女性(非医療従事者)に対して接種された初回のワクチンは7回だと分かります。
なお、母数となる人口データは、総務省が公表している「【総計】令和2年住民基本台帳年齢階級別人口(市区町村別)」を利用しています。また、この統計データはワクチン接種記録システム(VRS)のデータをもとにしています。
「接種日別接種回数サマリー」と「都道府県別累積接種回数サマリー」は「都道府県別接種回数詳細」から得られるデータを日別と都道府県別に集計しなおした要約データになります。
Pythonでデータ取得するための準備
ndjsonモジュールのインストール
このデータはNDJSON形式(改行区切りJSON形式)で提供されているので、NDJSONを扱えるようにndjsonモジュールをインストールします。Anacondaでは提供されていないようなので、以下のようにpipでインストールを行います。
pip install ndjson
ndjsonモジュールについては以下をご覧ください。
NDJSON形式のデータをDataFrameとして取得する
それでは上記モジュールを使用して政府CIOポータルから「都道府県別接種回数詳細 (NDJSON形式)」を取得してみましょう。
import pandas as pd
import requests
import ndjson
result = requests.get('https://vrs-data.cio.go.jp/vaccination/opendata/latest/prefecture.ndjson')
df = pd.DataFrame(ndjson.loads(result.text))
print(df)
date prefecture gender age medical_worker status count 0 2021-04-12 01 F -64 False 1 8 1 2021-04-12 01 F 65- False 1 84 2 2021-04-12 01 M -64 False 1 1 3 2021-04-12 01 M 65- False 1 21 4 2021-04-12 01 U UNK False 1 1 ... ... ... ... ... ... ... ... 19747 2021-06-10 47 M -64 False 1 83 19748 2021-06-10 47 M -64 False 2 20 19749 2021-06-10 47 M 65- False 1 1063 19750 2021-06-10 47 M 65- False 2 579 19751 2021-06-10 47 U UNK False 1 52 [19752 rows x 7 columns]
日別の接種回数と累積の接種回数を可視化する
日別の接種回数と65歳以上の累積の接種回数を可視化するコードをお示しします。
import pandas as pd
import matplotlib.pyplot as plt
import requests
import ndjson
plt.rcParams['font.family'] = "Meiryo"
# 統計データの取得
result = requests.get('https://vrs-data.cio.go.jp/vaccination/opendata/latest/prefecture.ndjson')
df = pd.DataFrame(ndjson.loads(result.text))
df = df.set_index(['date', 'status', 'prefecture', 'gender', 'age', 'medical_worker'])
df_over65_1 = df.query("age == '65-' and status == 1")
df_over65_2 = df.query("age == '65-' and status == 2")
df_under65_1 = df.query("age == '-64' and status == 1")
df_under65_2 = df.query("age == '-64' and status == 2")
df_unknown_1 = df.query("age == 'UNK' and status == 1")
df_unknown_2 = df.query("age == 'UNK' and status == 2")
# DataFrame(日別回数)
df_over65_1_byday = df_over65_1.sum(level='date').rename(columns={'count':'over65_count1'})
df_over65_2_byday = df_over65_2.sum(level='date').rename(columns={'count':'over65_count2'})
df_under65_1_byday = df_under65_1.sum(level='date').rename(columns={'count':'under65_count1'})
df_under65_2_byday = df_under65_2.sum(level='date').rename(columns={'count':'under65_count2'})
df_unknown_1_byday = df_unknown_1.sum(level='date').rename(columns={'count':'unknown_count1'})
df_unknown_2_byday = df_unknown_2.sum(level='date').rename(columns={'count':'unknown_count2'})
df_byday = pd.concat([df_over65_1_byday, df_over65_2_byday, df_under65_1_byday, df_under65_2_byday, df_unknown_1_byday, df_unknown_2_byday], axis='columns')
df_byday = df_byday.fillna(0)
# DataFrame(累積回数)
df_byday_cumsum = df_byday.cumsum()
# DataFrameのインデックスを解除する
df_byday = df_byday.reset_index()
df_byday_cumsum = df_byday_cumsum.reset_index()
# Figureの作成
fig = plt.figure()
# 日別ワクチン接種回数
date = pd.to_datetime(df_byday['date'])
height_unknown = df_byday['unknown_count1'] + df_byday['unknown_count2']
height_under65 = df_byday['under65_count1'] + df_byday['under65_count2']
height_over65 = df_byday['over65_count1'] + df_byday['over65_count2']
ax1 = fig.add_subplot(121)
ax1.grid(axis='y')
bar1 = ax1.bar(date, height_unknown, label='年齢不明')
bar2 = ax1.bar(date, height_under65, bottom = height_unknown, label='12-64歳')
bar3 = ax1.bar(date, height_over65, bottom = height_unknown + height_under65, label='65歳以上')
ax1.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, loc: "{:,}".format(int(x))))
ax1.set_title('新型コロナウイルスワクチン接種回数')
ax1.legend([bar3, bar2, bar1], ['65歳以上', '12-64歳', '年齢不明'])
# 進捗状況(65歳以上)
date = pd.to_datetime(df_byday_cumsum['date'])
cumsum_over65_count1 = df_byday_cumsum['over65_count1']
cumsum_over65_count2 = df_byday_cumsum['over65_count2']
ax2 = fig.add_subplot(122)
ax2.grid(axis='y')
ax2.plot(date, cumsum_over65_count1)
ax2.plot(date, cumsum_over65_count2)
ax2.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, loc: "{:,}".format(int(x))))
ax2.set_title('65歳以上 累積ワクチン接種回数')
ax2.legend(['1回目', '2回目'])
#. グラフの表示
fig.autofmt_xdate()
fig.subplots_adjust(wspace=0.3)
plt.show()
統計データを取得する
9-10行目で政府CIOポータルからNDJSON形式のデータを取得し、DataFrameに変換しています。このDataFrameの回数のデータはcount部分なので、それ以外を12行目でインデックスに指定します。
続いて13-18行目で、取得したDataFrameから65歳以上・64歳以下・年齢不明のそれぞれ1回目・2回目をqueryメソッドを用いて抽出します。
ここで年齢層と接種回数ごとに、さらに接種日や都道府県・性別などで階層化された接種回数が取得されました。これを接種日が同じものはすべて合算して、接種日ごとのデータにまとめましょう。22-27行目でsumメソッドを用いて接種日ごとの合計を求めています。
queryメソッドでは新たなDataFrameが生成されるので、扱いやすいように29行目でdf_bydayにまとめておきましょう。
なお、DataFrameの欠損値は30行目でfillnaメソッドを用いてあらかじめゼロに置き換えておきます。
さらに累積の接種回数を求めるために、ここまで作成したDataFrameの累計を求めておきましょう。34行目でcumsumメソッドを用いて、接種日ごとの接種回数の累計を求めてdf_byday_cumsumに格納しておきましょう。
日別ワクチン接種回数のグラフ化
日別のワクチン接種回数は棒グラフを用いて作成します。
まずは47-50行目で棒グラフのそれぞれの棒の高さを表すデータ系列と横軸の日付のデータ系列を作成しましょう。これらはすべてDataFrameからSeriesとして抽出します。
データの準備ができたらまずは日別のワクチン接種回数のグラフ化です。次の累積接種回数と2つを並べてグラフ化するので、add_subplotでFigureインスタンスの中の領域を2つに分けて左側にグラフ化します。
あとは54-56行目でbarメソッドを用いてグラフを作成するだけです。
累積接種回数(65歳以上)のグラフ化
続いて累積接種回数をグラフ化します。
63-65行目で横軸・縦軸の系列を抽出しています。ここでは65歳以上のデータだけを抽出していますが、この条件の指定次第で64歳以下など他の系列の累積接種回数のグラフを作成することも可能です。
67行目でadd_subplotでグラフを作成する領域の位置を指定しています。今回は折れ線グラフで作成するので、69-70行目でplotメソッドを用いましょう。
コメント