こんなプロットができた
こちらのページで見れます
Githubのレポジトリにて公開しています。COVID-19 Python plot
null
きっかけ
昨今、COVID-19(コロナウイルス)の文字を見ない日はありません。それほど現在の世の中にはCOVID-19に関する情報、データが出回っています。
COVID-19に関する論文もたくさん出ていますし、データもオープンになっているものがたくさんあります。
プログラミングを学んでいる身として、データ分析・可視化の練習になるのでは、と思い今回いろいろなプロットを作ってみました。
また、Python会という団体での新歓イベントの一環として、時流に乗ってこのようなデータを扱ってみたらなじみやすいのでは、と思ったのも一つです。
全体のコード
github gistを使用して、Jupyter notebookを埋め込んであります。詳細はこちらのコードをご確認ください。
ハンズオンを行いました
【オンラインハンズオン開催!】— 阪医python会 (@oumed_python) April 14, 2020
☑️日にち:4/18(土) & 4/25(土)
☑️時間:19:00〜21:00(途中参加、退出OKです)
☑️内容:COVID-19のデータを可視化してみよう
☑️対象:どなたでも!(他大学、一般の方からの参加もお待ちしています!)
当日はzoomを使用します。
参加希望の方→詳細はリプにて! pic.twitter.com/m5KYaarYNc
ハンズオンで使用したスライドをのせておきます。
使用したデータ
今回可視化に用いたデータはこちらのレポジトリにあるデータです。他にも、WHOや厚労省がオープンにしているデータもありましたが、いかんせんWeb上のテキストとして表示されているだけで、ファイルとして扱いにくかったので、今回は使いませんでした。
その点こちらのレポジトリでは、毎日データが更新されており、データもcsv形式でまとめられていて、非常に扱いやすかったです。
ちなみに、こちらのレポジトリのデータは、
Coronavirus COVID-19 (2019-nCoV)
というCOVID-19に関する様々な数字がチェックできるサイトにて使用されていると思われます。
また、論文も公表されています。
An interactive web-based dashboard to track COVID-19 in real time - The Lancet Infectious Diseases
使用したライブラリ
pandas
csvファイルの扱いに長けています。定番ですね。pycountry
国名を国名コードに変換できるライブラリです。
可視化
- matplotlib
- pandas_bokeh
- Folium
可視化の流れ
以下、コードの詳しい説明はしませんが、ポイントだけ記しておこうと思います。
データを見てみる
今回使ったデータは、レポジトリの中でも、COVID-19/csse_covid_19_data/csse_covid_19_time_series/
にあるデータです。
日付ごとの数値を記録してあります。
種類は3つあり、
- timeseriescovid19confirmedglobal.csv
- timeseriescovid19deathsglobal.csv
- timeseriescovid19recoveredglobal.csv
データの様子
縦に日付、横に国名のファイルです。
2020/1/22から始まり、現在まであります。
データを整える
さて、ここからPythonでデータを扱っていきます。上記の記録されたファイル、そのままではきれいに可視化できません。
都合のよいようにカスタマイズしていきます。
整えるポイント
いらないカラム(列)の削除
df.drop(columns=['Province/State', 'Lat', 'Long'])
Country/Regionごとにまとめる
df.groupby('Country/Region').mean()
同じ国でも地域ごとに1行ずつデータがあったので、国ごとに1つにまとめます。
カラムとインデックスの反転
df.T
「カラムに国名、インデックスに日付」がくるように全体を転置します。国名→国名コードに変換する
たとえば、JapanをJPNに変換します。pycountry.countries.get(name='Japan').alpha_3
以下で使う、コロプレス図は国名を3文字コードで認識するので、今のうちに変換しておきます。
pycountryというライブラリを使います。
- 国名→3文字コード
- 3文字コード→2文字コード
- 2文字コード→3文字コード
import pycountry
# 空のリスト作成
list_country_code = []
list_country_ = []
# 国名を3文字コードに変換していく
for i in list(df_time_confirmed_sum.columns):
try:
list_country_code.append(pycountry.countries.get(name=i).alpha_3)
list_country_.append(i)
except:
print(i)
ライブラリの変換だけでは、うまく国名を認識してくれないものもあるので、
それらはprintして打ち出し、手動で変換しました。
国名コードはこちらを参考に。
List of countries by regional classification - Meta
可視化していく
データがきれいになったので、可視化してみます。以下のデータはすべて、4/10現在までのデータになります。
国ごとの、日付に沿った確認患者数の折れ線グラフ
日本
country = "JPN"
df_time_confirmed_sum[country].plot()
plt.title(country)
#plt.savefig('fig/plot_japan_no_yaxis.pdf')
USA
country = "USA"
df_time_confirmed_sum[country].plot()
plt.title(country)
#plt.savefig('fig/plot_usa_no_yaxis.pdf')
アメリカが感染者数の最大値だったので、y軸の範囲を設定しなおして、
もう一度日本を見てみると…
country = "JPN"
df_time_confirmed_sum[country].plot()
plt.title(country)
plt.ylim([0, today_max_round])
#plt.savefig('fig/plot_japan.pdf')
感染確認数上位10の国を比較したグラフ
dataframeから、上位10ヶ国を抜き出します。df_time_confirmed_sum.max().sort_values(ascending=False)[0:10]
折れ線図
df_time_confirmed_sum[list_top10_country].plot()
plt.title("confirmed top10")
#plt.savefig('fig/plot_top10_confirmed.pdf')
棒グラフ
4/10におけるデータの棒グラフです。df_time_confirmed_sum[list_top10_country][-1:].plot.bar()
plt.title("confirmed top10")
#plt.savefig('fig/bar_top10_confirmed.pdf')
インタラクティブな図を作成
ここまでは日頃よく作っている可視化のグラフです。今回はインタラクティブな、カーソルでぐりぐり動かしてグラフ上の数値などを見ることのできる、プロット・地図を描いてみました。
折れ線グラフ
pandas-bokehというライブラリを使います。- USAとESP(スペイン)を比較
import pandas_bokeh
pandas_bokeh.output_notebook()
df_time_confirmed_sum[["USA", "ESP"]].plot_bokeh.line()
- 感染者数top10ヶ国の比較
df_time_confirmed_sum[list_top10_country].plot_bokeh.line()
- 棒グラフ
df_time_confirmed_sum[list_top10_country][-1:].plot_bokeh.bar()
コロプレス図を作成
こちらを使用します。Foliumで描画するためには、
- GeoJSON もしくは TopoJSON 形式のファイル
- コロプレス図を色分けするための値を含む pandas の DataFrame
世界地図のGeoJSONファイルは、
こちらを使用しました。
まずは普通の世界地図をplotしてみます。
import folium
m = folium.Map(location=[10, 35], zoom_start=1.5)
geojson = "./world.geo.json/countries.geo.json"
folium.GeoJson(geojson).add_to(m)
m
dataframeに、国名コードと値が並ぶように調整をしてplotしてみると、
m = folium.Map(location=[10, 35], zoom_start=1.5)
geojson = "./world.geo.json/countries.geo.json"
folium.GeoJson(geojson).add_to(m)
m.choropleth(geo_data=geojson, data=df_latest,
columns=['country', 'number'],
key_on='feature.id',
fill_color='YlGnBu', reset=True)
m
colormapの変更もできます。
m = folium.Map(location=[10, 35], zoom_start=1.5)
geojson = "./world.geo.json/countries.geo.json"
folium.GeoJson(geojson).add_to(m)
m.choropleth(geo_data=geojson, data=df_latest,
columns=['country', 'number'],
key_on='feature.id',
fill_color='YlOrRd', reset=True)
m
- マーカーを追加してみる
地図上にピンを刺して、数値などを表示できます。
今回はtop10の国について、首都の位置に感染者数のピンをおいてみます。
m = folium.Map(location=[10, 35], zoom_start=1.5)
geojson = "./world.geo.json/countries.geo.json"
folium.GeoJson(geojson).add_to(m)
m.choropleth(geo_data=geojson, data=df_latest,
columns=['country', 'number'],
key_on='feature.id',
fill_color='YlOrRd', reset=True)
# マーカーの追加
for i in list_top10_country:
capital = df_capital[df_capital["code3"] == i]
folium.Marker(
[capital["Capital Latitude"], capital["Capital Longitude"]],
popup=df_time_confirmed_sum[-1:][i][0]
).add_to(m)
m
1つのfolium.Mapオブジェクトに対して、forループでマーカーを追加できました。
- 日付を指定してplotしてみる
df_test = df_time_confirmed_sum.loc["2/1/20"].T.reset_index()
df_test.columns = ["country", "number"]
df_test.head()
なので、
m = folium.Map(location=[10, 35], zoom_start=1.5)
geojson = "./world.geo.json/countries.geo.json"
folium.GeoJson(geojson).add_to(m)
m.choropleth(geo_data=geojson, data=df_test,
columns=['country', 'number'],
key_on='feature.id',
fill_color='YlOrRd', reset=True)
m
でplotできます。
まとめ
- 自分で各国の数字を眺めていると、ニュースなどの情報がよりわかりやすくなるのかも
- 今回はただ数字のデータからその状況をグラフとして「見える化」したにすぎないので、 何かしらの意味が見いだせるような解析もしてみたいところ
コードや説明で間違っているところがあれば、教えてもらえると幸いです。
記事の感想をリアクションでお願いします!