pythonを使って京阪神エリアのコロナウイルス新規感染者数をプロット

コロナウイルスの流行に端を発する、データ処理についてのシリーズ記事ですが、今回でようやくひとつのゴールに辿り着けそうです。
今日の目標は、以下のプロットを、shellからのコマンド一発で生成する方法についてです。
京阪神+αエリアのCOVID19新規発症者数の推移(4/15日10時現在)

スクリプトは、shellスクリプトとpython3のスクリプトから成り立っています。
要素としては、これまでの記事で紹介したコマンドがほとんどです。
(データ列の名前だったり、少し書き換えている部分もあります。)

適当なフォルダを作って、そこに、以下の2つのファイルを作成したら、
ターミナルで「sh COVID_count.sh」と入力するだけで、瞬時に上のようなグラフが作成されるはずです(ターミナルからのシェルスクリプト実行についてはこちら)。

______________________

COVID_count.sh
______________________
mkdir $(date +%m%d)
cp COVID_count.py $(date +%m%d)
cd $(date +%m%d)

curl https://dl.dropboxusercontent.com/s/6mztoeb6xf78g5w/COVID-19.csv | cut -d ',' -f 1,6,8,10,11,24,27 | sed -e 's|/2020||g' -e 's|,4/|,2020/4/|g' -e 's|,3/|,2020/3/|g' -e 's|,2/|,2020/2/|g' -e 's|,1/|,2020/1/|g' > COVID_19_$(date +%m%d).csv
grep -e 京都府 COVID_19_$(date +%m%d).csv | cut -d ',' -f 1,3,4,5 | nkf -s > COVID_19_kyoto.csv
grep -e 大阪 COVID_19_$(date +%m%d).csv | cut -d ',' -f 1,3,4,5 | nkf -s > COVID_19_osaka.csv
grep -e 兵庫 COVID_19_$(date +%m%d).csv | cut -d ',' -f 1,3,4,5 | nkf -s > COVID_19_hyogo.csv
grep -e 奈良 COVID_19_$(date +%m%d).csv | cut -d ',' -f 1,3,4,5 | nkf -s > COVID_19_nara.csv
grep -e 滋賀 COVID_19_$(date +%m%d).csv | cut -d ',' -f 1,3,4,5 | nkf -s > COVID_19_shiga.csv
grep -e 岡山 COVID_19_$(date +%m%d).csv | cut -d ',' -f 1,3,4,5 | nkf -s > COVID_19_okayama.csv
grep -e 東京 COVID_19_$(date +%m%d).csv | cut -d ',' -f 1,3,4,5 | nkf -s > COVID_19_tokyo.csv

python3 COVID_count.py

mv keihanshin.png keihanshin_$(date +%m%d).png
______________________

mkdir コマンドで、その日の日付が入ったフォルダ"$(date +%m%d)"を作っています。
cp コマンドで、python のスクリプト "COVID_count.py" を、作成したフォルダの中に、
コピーして放り込んでいます。
cd コマンドで、作成したフォルダの中に入り込みます。

続いて、curl, cut, sed, grep を使って、日本全国のコロナウイルス感染者についての情報の、ダウンロードと、グラフ作成に向けた前処理を行っています。詳細はこちらの記事参照

前処理が終わったら、python3 でパイソンを起動して、下に示したCOVID_count.py スクリプトを走らせています。

最後の "mv コマンド" は、不要といえば不要ですが、作成したグラフに日付を入れるための操作を施しています。これは、pythonで、フィギュアの名前をつける時に指定してやることができるかもしれません。

______________________

COVID_count.py
______________________

import pandas as pd

COVID_19_osaka = pd.read_csv('COVID_19_osaka.csv',encoding='cp932',names=['id', 'osaka', 'place_diag','place_living'])
COVID_19_hyogo= pd.read_csv('COVID_19_hyogo.csv',encoding='cp932',names=['id', 'hyogo', 'place_diag','place_living'])
COVID_19_kyoto = pd.read_csv('COVID_19_kyoto.csv',encoding='cp932',names=['id', 'kyoto', 'place_diag','place_living'])
COVID_19_nara = pd.read_csv('COVID_19_nara.csv',encoding='cp932',names=['id', 'nara', 'place_diag','place_living'])
COVID_19_shiga = pd.read_csv('COVID_19_shiga.csv',encoding='cp932',names=['id', 'shiga', 'place_diag','place_living'])

COVID_19_osaka["osaka"] = pd.to_datetime(COVID_19_osaka["osaka"])
COVID_19_hyogo["hyogo"] = pd.to_datetime(COVID_19_hyogo["hyogo"])
COVID_19_kyoto["kyoto"] = pd.to_datetime(COVID_19_kyoto["kyoto"])
COVID_19_nara["nara"] = pd.to_datetime(COVID_19_nara["nara"])
COVID_19_shiga["shiga"] = pd.to_datetime(COVID_19_shiga["shiga"])

osaka_num=COVID_19_osaka["osaka"].value_counts()
hyogo_num=COVID_19_hyogo["hyogo"].value_counts()
kyoto_num=COVID_19_kyoto["kyoto"].value_counts()
nara_num=COVID_19_nara["nara"].value_counts()
shiga_num=COVID_19_shiga["shiga"].value_counts()

kinki_num = pd.concat([osaka_num,hyogo_num,kyoto_num,nara_num,shiga_num],axis=1,join='outer')

ax=kinki_num.fillna(0).plot(figsize=(6,6),title="New COVID-19 Patients Found in KeiHanShin+α Area",grid=True)
fig=ax.get_figure()
fig.savefig('keihanshin')
______________________

つづいて、pythonのスクリプト。

初めに pandas を読み込んでいます。このあたりの操作は、前前回の記事であつかいました。
pd.read_csv で、csv ファイルを、pandas で扱うことのできるデータに変換しています。
pd.to_datetime で、データのフォーマットを日付形式に変え、
.value_counts() で、同じ日の患者数を数え上げています。

続いて、
pd.concat() で、データの描画に使うデータ列だけを結合して、新しいデータの集合体(データフレーム) kinki_num を合成しています。
axis = 1 という引数を与えて、横方向に結合させています。
join = 'outer' は、外部結合してな!という指示です。

このようにして作成したデータを描画しているのが最後のブロックです。

kinki_num のファイルで、感染者が出ていないところはすべて空欄になっています。

ax=kinki_num.fillna().plot()

この行で、kinki_num を、fillna コマンドで処理し、plot コマンドでプロットにして、
axという名前で保存しています。

.fillna(0) としているので、空白データ(NaN と表示される)はすべて 0 になります。
".plot()" コマンドで、カッコの中になにも入れなくても、結構きれいなグラフはかけます。

今回は、
figsize = で、サイズの指定
title = で、グラフのタイトル
grid = で、補助線を入れるように支持しています。

fig=ax.get_figure() 、"プロット"を作るためのデータを"画像"データへと変換し、
fig.savefig('keihanshin') で、fig の絵を、'keihanshin' という名前で出力するよう指示しています。


ぜひぜひ、ご自身の環境でも、試していただけたらと思います。

[あとがき]
初めは、ウェブブラウザでダウンロードしてきたcsvファイルを手作業で編集してグラフを作成していました。エクセルを普段使わないもので、初めは集計の仕方、グラフの編集の仕方を調べながら1時間位かけて、最初のグラフをつくったと思います。 

エクセルでのグラフ描画2回目では、操作を覚えていたので大体5分くらいでしょうか。
shellを使って、データの処理をするようになって、2分
いまや、スクリプトを走らせれば、ターミナルを起動する所から、20秒あればグラフは作成できてしまいます。

10倍以上の高速化ができたと思います。
自学には5時間以上はかかっているので、100回くらい、プロットの更新作業をすれば、
使った時間がペイされることになります。(それまでには、コロナウイルスは収束していてほしいものですが。)

きっと、同じような作業にぶち当たったときには、60分くらいで同等のスクリプトを書けるようになっているはず。書いたものをシェアできるのも、プログラミングのいいところですね。

もっとスマートに同様のプロットを作成する方法もあると思います。
しかし、独学でも、積み木を積み上げるように勉強していけば、ある程度のことができるということをわかっていただけたらハッピーです。


[参考]
プロットを作成する際によく使われるライブラリには、matplotlibや、seabornがあるが、今回はできるだけ単純にしたかったので、pandasの他になにもインポートすることなく使うことができる、pandasのプロット機能だけでグラフ描画をしました。

fillna と concat については、以下のサイトで比較的わかりやすく説明されています。


コメント

このブログの人気の投稿

VNCで見ている画面と自分のマシンの間でのコピー&ペースト

Natural Bond Orbital (NBO) Analysis, 自然軌道解析をやってみる

Lanl2DZの使い方