新型コロナワクチン接種後に死亡として報告された事例をCSVに変換

wget https://www.mhlw.go.jp/content/10906000/000784439.pdf -O data.pdf
import camelot
import pandas as pd

def str2date(s: pd.Series) -> pd.Series:

    df = (
        s.str.extract("(\d{4})年(\d{1,2})月(\d{1,2})日")
        .rename(columns={0: "year", 1: "month", 2: "day"})
        .fillna(0)
        .astype(int)
    )

    return pd.to_datetime(df, errors="coerce")


tables = camelot.read_pdf("data.pdf", pages="2-15")

dfs = [table.df.iloc[2:] for table in tables]

df = pd.concat(dfs)

df.set_axis(
    [
        "No",
        "年齢",
        "性別",
        "接種日",
        "発生日",
        "ロット番号",
        "接種回数",
        "基礎疾患等",
        "死因等",
        "報告医が死因等の判断に至った検査",
        "因果関係",
        "他要因の可能性の有無",
        "前回_因果関係評価",
        "前回_コメント",
        "現在_因果関係評価",
        "現在_コメント",
    ],
    axis=1,
    inplace=True,
)

df["No"] = df["No"].str.replace("注\d", "")

df["接種日"] = str2date(df["接種日"])
df["発生日"] = str2date(df["発生日"])

df["年齢"] = df["年齢"].str.extract("(\d+)歳", expand=False).astype(int)

df["ロット番号"] = df["ロット番号"].str.replace("([\s\S]*)", "").str.strip().mask(df["ロット番号"] == "不明")

df["接種回数"] = df["接種回数"].str.rstrip("回目").mask(df["接種回数"] == "不明")

df1 = df.loc[:, ["No", "年齢", "性別", "接種日", "発生日", "ロット番号", "接種回数"]]

df1.to_csv("output.csv", encoding="utf_8_sig", index=False)

df1

予防接種法に基づく医療機関からの副反応疑い報告状況についてのPDFからCSV変換~前処理

github.com

予防接種法に基づく医療機関からの副反応疑い報告状況について

https://www.mhlw.go.jp/content/10906000/000784435.pdf

github.com

explode は便利

インストール

apt install python3-tk ghostscript
pip install camelot-py[cv]

wget https://www.mhlw.go.jp/content/10906000/000784435.pdf -O data.pdf

CSVに変換

import camelot
import pandas as pd

tables = camelot.read_pdf("data.pdf", pages="2-end", split_text=True)

dfs = [table.df for table in tables]

df = pd.concat(dfs)

df.to_csv("data.csv", encoding="utf_8_sig", index=False, header=False)

前処理

import re
import pandas as pd

!wget https://raw.githubusercontent.com/imabari/covid19-data/master/vaccine/data.csv -O data.csv

df0 = pd.read_csv("data.csv", dtype="object").fillna("")

df0.info()

df0.columns = df0.columns.str.replace("\n", "")

df0["No"] = df0["No"].str.replace("※[1-9]", "").str.strip().astype(int)

df0["年齢"] = df0["年齢"].str.rstrip("歳")
df0["年齢"] = df0["年齢"].mask(df0["年齢"] == "").astype(float).astype("Int64")

df0["性別"] = df0["性別"].replace({"": "不明"})

"""# 整然データ

かのえ/Pattie/柿人 さんのコードを参考にさせていただきました

https://twitter.com/kanoekakihito/status/1397222333505486849

https://github.com/kanoekakihito/tidy_mhlw_data/blob/main/20210523_%E6%96%B0%E5%9E%8B%E3%82%B3%E3%83%AD%E3%83%8A%E3%83%AF%E3%82%AF%E3%83%81%E3%83%B3%E5%89%AF%E5%8F%8D%E5%BF%9CCSV%E6%95%B4%E5%BD%A2.py
"""

df1 = df0.copy()

df1["症状名(PT名)"] = df1["症状名(PT名)"].apply(lambda s: [i.replace("\n", "").strip() for i in re.split("(?<=[))]\n)", s)])
df1["発生日"] = df1["発生日"].str.split()
df1["転帰日"] = df1["転帰日"].str.split()
df1["転帰内容"] = df1["転帰内容"].str.split()

dfs = []

for i, row in df1.iterrows():
    dfs.append(row.apply(pd.Series).T.fillna(method="ffill"))

df2 = pd.concat(dfs).reset_index(drop=True)

df3 = df2["症状名(PT名)"].str.extract("(.+)[((](.+?)[))]").rename(columns={0:"症状名", 1:"PT名"})
df3["PT名"] = df3["PT名"].str.split("|")

df4 = df2.join(df3).explode("PT名")

df4["症状名"] = df4["症状名"].str.strip()
df4["PT名"] = df4["PT名"].str.strip()

df4["No"] = df2["No"].astype(int)
df4["年齢"] = df2["年齢"].astype("Int64")

df4.info()

df4

df4.to_csv("output.csv", index=False, encoding="utf_8_sig")

"""# ダウンロード"""

files.download("output.csv")

"""# 症状別報告件数"""

df4["症状"] = df4["症状名"] + "(" + df4["PT名"] + ")"

df4["症状"].value_counts()

"""# 集計確認"""

df1 = df0.copy()
df1.set_index("No", inplace=True)

"""## アナフィラキシー"""

df1["症状名(PT名)"].str.contains("アナフィラキシー").sum()

"""## 性別"""

# 性別 副反応疑い報告数
df1["性別"].value_counts()

# 性別 重篤報告数
df1.loc[df1["重篤度(報告医評価)"] == "重い", "性別"].value_counts()

# 性別 死亡報告数
df1.loc[df1["転帰内容"].str.contains("死亡"), "性別"].value_counts()

"""## 年齢別"""

labels = [
    "0~9歳",
    "10~19歳",
    "20~29歳",
    "30~39歳",
    "40~49歳",
    "50~59歳",
    "60~69歳",
    "70~79歳",
    "80歳以上",
]

df1["年代"] = pd.cut(
    df1["年齢"],
    [0, 10, 20, 30, 40, 50, 60, 70, 80, 120],
    include_lowest=True,
    right=False,
    labels=labels,
).astype(str)

df1["年代"] = df1["年代"].mask(df1["年齢"].isnull(), "不明")

# 年齢別副反応疑い報告数
df1["年代"].value_counts().reindex(labels + ["不明"]).fillna(0).astype(int)

# 年齢別重篤報告数
df1.loc[df1["重篤度(報告医評価)"] == "重い", "年代"].value_counts().reindex(labels + ["不明"]).fillna(0).astype(int)

# 年齢別死亡報告数
df1.loc[df1["転帰内容"].str.contains("死亡"), "年代"].value_counts().reindex(labels + ["不明"]).fillna(0).astype(int)

プロボウラー資格取得テストの成績のPDFを変換

!wget https://www.jpba.or.jp/information/protest/2021/1st_East_M15W12.pdf -O data.pdf
!pip install tabula-py
import pandas as pd
from tabula import read_pdf

headers = [
    "順位",
    "受験番号",
    "氏名",
    "ふりがな",
    "T/PIN",
    "年齢",
    "登録地",
    "利き腕",
    "1-3G",
    "1S",
    "4-6G",
    "2S",
    "7-9G",
    "3S",
    "10-12G",
    "4S",
    "合計",
    "平均",
    "ランキング",
]

dfs = read_pdf("data.pdf", pages="all", lattice=True, pandas_options={"header": None})

df0 = (
    dfs[0]
    .iloc[2:]
    .set_axis(headers, axis=1)
    .dropna(subset=["順位"])
    .set_index(["順位", "氏名"])
)

df1 = df0["1-3G"].str.split(expand=True).rename(columns={0: "1G", 1: "2G", 2: "3G"})
df2 = df0["4-6G"].str.split(expand=True).rename(columns={0: "4G", 1: "5G", 2: "6G"})
df3 = df0["7-9G"].str.split(expand=True).rename(columns={0: "7G", 1: "8G", 2: "9G"})
df4 = (
    df0["10-12G"].str.split(expand=True).rename(columns={0: "10G", 1: "11G", 2: "12G"})
)

df = pd.concat([df1, df2, df3, df4], axis=1).astype(int)

df.sum(axis=1)

df0["合計"].str.replace(",", "").astype(int)

df0["平均"].astype(float)

df.mean(axis=1).round(2)

df

都道府県別直近7日のコロナ死亡率を計算

5/5だったので最新はどうなのか気になったので計算してみた

dot.asahi.com

web.sapmed.ac.jp

import pandas as pd
import requests

import pathlib


def fetch_file(url, dir="."):

    p = pathlib.Path(dir, pathlib.PurePath(url).name)
    p.parent.mkdir(parents=True, exist_ok=True)

    r = requests.get(url)
    r.raise_for_status()

    with p.open(mode="wb") as fw:
        fw.write(r.content)
    return p


# 人口

p1 = fetch_file("https://www.stat.go.jp/data/nihon/zuhyou/n210200200.xlsx")
df1 = pd.read_excel(
    p1, header=None, skiprows=9, skipfooter=3, index_col=0, usecols=[0, 6]
)

df1.set_axis(["総人口"], axis=1, inplace=True)
df1.index.name = "都道府県"

# NHK死亡者数

p2 = fetch_file(
    "https://www3.nhk.or.jp/n-data/opendata/coronavirus/nhk_news_covid19_prefectures_daily_data.csv"
)
df2 = pd.read_csv(p2, parse_dates=[0])

pv = df2.pivot(index="日付", columns="都道府県名", values="各地の死者数_累計")

# 前週との差分

pv_diff = pv.diff(7)
pv_diff

# 最新
se = pv_diff.iloc[-1]
# se = pv_diff.loc[pd.Timestamp("2021-05-05")]

se.index = se.index.str.rstrip("府県")
se.rename(index={"東京都": "東京"}, inplace=True)
se.name = "死亡者数"

df3 = df1.join(se)
df3

# 100万人あたり
df3["死亡率"] = df3["死亡者数"] / (df3["総人口"] / 1000)

df3["死亡率"].sort_values(ascending=False)

何も考えず「rstrip("都道府県")」にすると「北海道」は「北海」、「京都府」は「京」だけになるという知見を得られた(w

楽天モバイルの基地局の地図を作製

楽天モバイル https://www.tele.soumu.go.jp/musen/SearchServlet?pageID=4&IT=G&DFCD=0000524258&DD=2&styleNumber=00

https://www.tele.soumu.go.jp/musen/SearchServlet?SC=1&pageID=3&SelectID=3&CONFIRM=0&NA=%8Ay%93V%83%82%83o%83C%83%8B%8A%94%8E%AE%89%EF%8E%D0&CATINDEXCD=A001&IT=G&HC=38&HV=202&MK=&TSNJK=&FF=&TF=&HZ=3&NA2=%8Ay%93V%83%82%83o%83C%83%8B%8A%94%8E%AE%89%EF%8E%D0&NA1=%8Ay%93V%83%82%83o%83C%83%8B%8A%94%8E%AE%89%EF%8E%D0&DFY=&DFM=&DFD=&DTY=&DTM=&DTD=&SK=2&DC=100&as_fid=a45270860a8cb3e7a7b65b2b8a54a42896f8841a#result

import pandas as pd
import folium

url = "https://docs.google.com/spreadsheets/d/e/2PACX-1vS74zyg2Q6lC4N0591Bx2_7BhPjir1gRGv8KY3_aoXOA07j8-hNasD_e430ER5T7xTU2cy973sw9wiX/pub?gid=0&single=true&output=csv"

df = pd.read_csv(url)

df

colors = {"開局": "green", "未開局": "yellow"}

imabari_map = folium.Map(location=[34.06604300, 132.99765800], zoom_start=12)

for i, r in df.iterrows():

    color = colors.get(r["status"], "black")

    folium.Marker(
        location=[r["latitude"], r["longtude"]],
        popup=r["name"],
        icon=folium.Icon(color=color, icon="signal"),
    ).add_to(imabari_map)
    folium.Circle(
        location=[r["latitude"], r["longtude"]],
        popup=r["name"],
        radius=2000,
        color=color,
        fill=True,
        fill_color=color,
    ).add_to(imabari_map)

# ここからは下は勝手に基地局追加

# かみとくの湯
folium.Circle(
    location=[34.039893248086905, 133.01205912457712],
    radius=2000,
    color="red",
    fill=True,
    fill_color="red",
).add_to(imabari_map)

# 市営体育館
folium.Circle(
    location=[34.07259426656803, 132.99259956654348],
    radius=2000,
    color="red",
    fill=True,
    fill_color="red",
).add_to(imabari_map)

# 県病院
folium.Circle(
    location=[34.08573221092478, 132.9887154862471],
    radius=2000,
    color="red",
    fill=True,
    fill_color="red",
).add_to(imabari_map)

# イオン新都市
folium.Circle(
    location=[34.04196921477711, 132.9608585492133],
    radius=2000,
    color="red",
    fill=True,
    fill_color="red",
).add_to(imabari_map)

# 地図描画
imabari_map