東洋経済のCOVID-19データ

東洋経済ONLINEの新型コロナウイルス国内感染の状況は国内の状況を一覧できる便利なサイトである。残念ながらGitHub上のデータの更新は2021-01-31で終了してしまった。そこで,東洋経済のサイトから直接データをダウンロードすることによって追加のグラフを描いてみる。

データはサイト上の data.json というファイルに収められている。これを直接 Python で読み込むこともできるが,ここではいったんファイルに落とす:

wget -N https://toyokeizai.net/sp/visual/tko/covid19/data/data.json

これを読み込む:

import json
import numpy as np
import matplotlib.pyplot as plt

with open("data.json") as f:
    data = json.load(f)

データの構造を見るため,簡単な関数を定義する:

def foo(x, depth=0):
    if type(x) == dict:
        for i in x.keys():
            print(" " * 4 * depth, i, sep="")
            foo(x[i], depth + 1)

foo(data)
updated
    last
        ja
        en
    demography
        ja
        en
transition
    carriers
        from
        values
    cases
        from
        values
    discharged
        from
        values
    serious
        from
        values
    deaths
        from
        values
    pcrtested
        from
        values
    pcrtests
        from
        values
    reproduction
        from
        values
demography
prefectures-data
prefectures-map

最初の部分は更新日時などである:

data["updated"]["last"]["ja"]  # => '最終更新:2021年4月9日'
data["updated"]["demography"]["ja"]  # => '4月7日時点'

以下では都道府県ごとの累計の検査陽性者数と死亡者数を調べる:

carriers = np.array(
    [np.sum(data["prefectures-data"][i]["carriers"]["values"]) for i in range(47)]
)
deaths = np.array(
    [np.sum(data["prefectures-data"][i]["deaths"]["values"]) for i in range(47)]
)

これをプロットする:

kenmei = ["北海道", "青森", "岩手", "宮城", "秋田", "山形", "福島",
          "茨城", "栃木", "群馬", "埼玉", "千葉", "東京", "神奈川",
          "新潟", "富山", "石川", "福井", "山梨", "長野", "岐阜",
          "静岡", "愛知", "三重", "滋賀", "京都", "大阪", "兵庫",
          "奈良", "和歌山", "鳥取", "島根", "岡山", "広島", "山口",
          "徳島", "香川", "愛媛", "高知", "福岡", "佐賀", "長崎",
          "熊本", "大分", "宮崎", "鹿児島", "沖縄"]

plt.clf()
plt.scatter(carriers, deaths)
for x, y, s in zip(carriers, deaths, kenmei):
    plt.text(x, y, s)
plt.xlabel("感染者数")
plt.ylabel("死者数")
都道府県別のCOVID-19感染者数と死者数

感染者数・死者数は当然比例する。人口あたりにすると地域差が見えてくる:

# 2019-10-01推計人口(単位1000人)
population = np.array([5250, 1246, 1227, 2306, 966, 1078, 1846,
     2860, 1934, 1942, 7350, 6259, 13921, 9198, 2223, 1044, 1138, 768,
     811, 2049, 1987, 3644, 7552, 1781, 1414, 2583, 8809, 5466, 1330,
     925, 556, 674, 1890, 2804, 1358, 728, 956, 1339, 698, 5104, 815,
     1327, 1748, 1135, 1073, 1602, 1453])

plt.scatter(carriers / population, deaths / population)
for x, y, s in zip(carriers / population, deaths / population, kenmei):
    plt.text(x, y, s)
plt.xlabel("人口1000人あたり感染者数")
plt.ylabel("人口1000人あたり死者数")
都道府県別のCOVID-19感染者数と死者数

これでもまだ横軸・縦軸の相関が強いので,次のようにしてみる:

plt.scatter(carriers / population, deaths / carriers)
for x, y, s in zip(carriers / population, deaths / carriers, kenmei):
    plt.text(x, y, s)
plt.xlabel("人口1000人あたり感染者数")
plt.ylabel("死者数/感染者数")
都道府県別のCOVID-19感染者数と死者数

左ほどばらついているように見えるので,エラーバー(Clopper-Pearson 95%信頼区間)を描いてみる。エラーバーなしのときのyの範囲を覚えておき,それと同じ範囲を描くようにした:

from statsmodels.stats.proportion import proportion_confint

ci0, ci1 = proportion_confint(deaths, carriers, method='beta')

plt.scatter(carriers / population, deaths / carriers)
y0, y1 = plt.ylim()
plt.errorbar(carriers / population, deaths / carriers,
             [deaths / carriers - ci0, ci1 - deaths / carriers],
             fmt="o", capsize=5)
plt.ylim(y0, y1)
for x, y, s in zip(carriers / population, deaths / carriers, kenmei):
    plt.text(x, y, s)
plt.xlabel("人口1000人あたり感染者数")
plt.ylabel("死者数/感染者数")
都道府県別のCOVID-19感染者数と死者数

Last modified: