NVIDIAのRAPIDSでコロナの感染者の推移の予測

#なにがしたいの？
最近使い始めた科学計算ライブラリのRAPIDSを使って、コロナウイルスの感染者数の推移を予想してみる。
ライブラリを使う練習です。

#どうやってやるの？
RAPIDSには、簡単な適合予測変換パラダイムを提供してくれるcuMLというライブラリがあります。
RAPIDSの公式ページを参考に、Dockerで環境を構築したあと、ブラウザでJupyter notebookを開きます。

グラフ表示のサンプルを実行してみます。
/cuml/arima_demo.ipynb
を選択して実行します。
男女の人口推移の予測波形などのサンプルを実行できます。

#コロナ感染者の推移のデータを取得する

人口統計などをJupyter notebookに表示するのは、ここを参考に。
[JupyterでCSVファイルを視覚化してみよう](https://news.mynavi.jp/article/zeropython-3/)

感染者集をJupyter notebookに表示するなら、オリジナルデータは厚生省からのデータを取ってくるべきですが、厚生省のデータはPDFで提供されるという謎仕様なので、こちらのサイトから引っ張ります。

[COVID-19 Japan](https://www.stopcovid19.jp/#ja)

前日のCSVだけでなく、いままでの推移を見ようとすると、集約版のデータが役に立ちそうです。
[集約版CSV](https://www.stopcovid19.jp/data/covid19japan-all.csv)

Rapids.cuDFに読み込ませて表示してみます。

```
import cudf

df= cudf.read_csv('https://www.stopcovid19.jp/data/covid19japan.csv')
print(df)
```

![Screenshot from 2020-05-03 13-19-22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328520/8c574bf1-15b3-00b1-fd00-dd603f84d8a5.png)

それっぽく表示されました。

集約版のほうも読み込んでみます。
GPUで処理する必要はないので、pandasで読み込みます。（cudfだとエラーが出ました）

```
df_index= pd.read_csv('https://www.stopcovid19.jp/data/covid19japan-all.csv')
print(df_index)
```

![Screenshot from 2020-05-03 13-42-22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328520/7683021b-d3dc-f4f9-fc48-f12c1cda0d77.png)

こんな感じで、だらだら出てきました。2020/03/18からのデータのインデックスが出てきました。
これを順番に読み込んで、[日付,県,データ各種]になった三次元のデータにします。
しかし、連続で読み込むとエラーが発生しました。

# 岩手県問題
コロナの感染者が0で推移中(2020/5/1現在)の岩手県は、感染者数は0となっていますが、統計のとり方が微妙で、死者数や退院数にNULLが入っていたりします。
こういう不揃いなデータは数値を補完する必要があります。統計中の何箇所かはNULLがありましたので、一括して0とします。

```python:データを読み込んでNULLを0に変更する
    # cudfにCSVファイルを読み込み
    df= cudf.read_csv(str_url_csv)
    # fillna(0)でNULLを0に変更し、浮動小数点になった数値をastypeでint64に変更する
    df = df.fillna(0).astype(cp.int64)

```

うまく整形されたリストが表示されたので、これをループで回せば処理ができます。

## (メモ)コンテナの中にデータを入れる方法
(自分用のメモ)
DockerコンテナでRAPIDSを操作していると、外から中にデータやファイルをコピーしたくなります。
そんなときは、VSCodeのリモートアクセスの拡張機能（Remote Development）をダウンロードして、'Remote-Containers:Attach to Running Container'でコンテナの中に接続します。
その後、/rapids/notebook/以下のフォルダを選んで、Jupyter Notebookで実行できるファイルなどにアクセスしたり、必要なデータをコピーしたりします。
（VSCodeをファイラーのように扱えます。右のウィンドウから左のウィンドウにドラッグドロップできます）
![Screenshot from 2020-05-04 09-55-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328520/f8241662-05fe-efa5-a1a3-c53fc9103480.png)

#3/26日問題
なぜかリストの中に、3/26のデータが存在しませんでした。
厚生省のPDFを変換したはずなので、この日は発表がなかったのでしょうか？

date_rangeを使って、日付インデックスを作って並べると日付がずれてしまいます。

```python:だめなやり方
index_str = cudf.date_range(start='3/18/2020', periods=cnt, freq='D')
```
集約リストの日付の部分を使うことにします。

```python:集約リストの日付を使う
# 集約リストの日付インデックスを保存
index_str = df_index.loc[:,'lastUpdate']
```

# 三次元データに整理する
任意の県のデータを引っ張りやすくするため、データを全部三次元のリストに変換します。
cntで数を数えて処理を分岐するのは、df処理としては微妙な気がしますので、うまいやり方を教えてください。
[チュートリアル](https://docs.rapids.ai/api/cudf/stable/10min-cudf-cupy.html?highlight=dataframe)
ここを参考にデータを整形しています。


```python:三次元にする
# 集約リストからcsvのアドレスを取得
df_url_csv = df_index.loc[:,'url_csv']

cnt = 0

# すべてのデータを読み込んで三次元の配列に収める
for str_url_csv in df_url_csv:
    print(str_url_csv)
    df= cudf.read_csv(str_url_csv)
    df = df.fillna(0).astype(cp.int64)
    
    try:
        # dfから数値の列を取り出し
        df2 = df.loc[:,['npatients','ncurrentpatients','nexits','ndeaths']]
        # cupyの二次元arrayに変換
        arr_cupy = cp.fromDlpack(df2.to_dlpack())
        # 3次元に拡張する
        arr_3d_new = arr_cupy[cp.newaxis, :, :]
        
        if cnt == 0:
            # 最初のデータをコピー
            arr_3d = arr_3d_new
        else:    
            # 配列を３次元の配列に追加する
            arr_3d = cp.concatenate((arr_3d,arr_3d_new),axis=0)
    except:
        print('error \n')
        print(df2)
        
    cnt = cnt + 1
    
```

#大雑把にグラフにしてみる
RAPIDSのサンプルプログラムを真似して、ざっくりと表示してみます。


```python:グラフ表示
#グラフ表記
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

# Seriesの型をdatetimeに変更する
index_date = pd.to_datetime(index_str)

fig, ax = plt.subplots()
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d'))
plt.plot(index_date, df_pref_graph['npatients'].to_array())

plt.show()

fig, ax = plt.subplots()
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d'))
plt.plot(index_date, df_pref_graph['npatients_diff'].to_array())

plt.show()

```

たぶんこれでいいはず。
日付の部分にいちいち西暦が表示されるとよく見えないので、月日だけにしています。

matplotlibの表示サンプルなどを参考にしてみました。
https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.subplot.html


![Screenshot from 2020-05-06 13-03-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328520/cf10b436-41ff-bfc1-6b86-fd1ba4cd29f6.png)

愛知県のデータは４月に感染者の陽性、陰性の取り違えでマイナスになっているのでもうぐちゃぐちゃですね。



# 参考になる資料のサイト

cuDFのAPIのDoc
https://rapidsai.github.io/projects/cudf/en/0.8.0/index.html

こういう高度なグラフが書きたい。
https://examples.pyviz.org/index.html

# 全ソースコード
手直ししながら記事を書いたので、最終的に動かしたコードを記録。

```python:RAPIDSのコンテナで動くコード

import cudf
import cupy as cp
import pandas as pd

# 集約リストを読み込み
df_index = pd.read_csv('https://www.stopcovid19.jp/data/covid19japan-all.csv')
# 集約リストの日付インデックスを保存
index_str = df_index.loc[:,'lastUpdate']


# 集約リストからcsvのアドレスを取得
df_url_csv = df_index.loc[:,'url_csv']

cnt = 0

# すべてのデータを読み込んで三次元の配列に収める
for str_url_csv in df_url_csv:
    print(str_url_csv)
    df= cudf.read_csv(str_url_csv)
    df = df.fillna(0).astype(cp.int64)
    
    try:
        # dfから数値の列を取り出し
        df2 = df.loc[:,['npatients','ncurrentpatients','nexits','ndeaths']]
        # cupyの二次元arrayに変換
        arr_cupy = cp.fromDlpack(df2.to_dlpack())
        # 3次元に拡張する
        arr_3d_new = arr_cupy[cp.newaxis, :, :]
        
        if cnt == 0:
            # 最初のデータをコピー
            arr_3d = arr_3d_new
        else:    
            # 配列を３次元の配列に追加する
            arr_3d = cp.concatenate((arr_3d,arr_3d_new),axis=0)
    except:
        print('error \n')
        print(df2)
        
    cnt = cnt + 1
    


# 県を限定してデータの配列を得る
arr_pref = arr_3d[:,18]
# cupy配列からcuDFに変換する
df_pref = cudf.DataFrame.from_gpu_matrix(arr_pref)
print(df_pref)
# columnsとindexを更新する
# 患者数/入院/退院/死亡者 = 'npatients','ncurrentpatients','nexits','ndeaths'
columns_str = ['npatients','ncurrentpatients','nexits','ndeaths']
#index_str = pd.date_range(start='3/18/2020', periods=cnt, freq='D')
df_pref.columns = columns_str
df_pref.index = index_str



# 患者数の増加数を算出し、nameを'npatients_diff'とする
series_diff = df_pref['npatients'].diff()
series_diff.name = 'npatients_diff'
# 
df_pref_graph = cudf.concat([df_pref,series_diff],axis=1)
print(df_pref_graph)



#グラフ表記
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

# Seriesの型をdatetimeに変更する
index_date = pd.to_datetime(index_str)

fig, ax = plt.subplots()
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d'))
plt.plot(index_date, df_pref_graph['npatients'].to_array())

plt.show()

fig, ax = plt.subplots()
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d'))
plt.plot(index_date, df_pref_graph['npatients_diff'].to_array())

plt.show()
```