グラフ型データベースを使って COVID-19 のクラスターを可視化した

# はじめに

新型コロナウイルス (COVID-19) のクラスター感染が連日ニュースで報道されていますが、実際にどのような属性のクラスターが発生しているのでしょうか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54003/0616df69-d901-ee70-a3d8-b3195bd57a8d.png)
引用元: [愛知県内の感染者・検査件数](https://www.pref.aichi.jp/site/covid19-aichi/kansensya-kensa.html)

例えば、愛知県の場合は、上記のような表形式で発生事例が公開されています。
「接触状況」のカラムから、データ同士を繋げると、ネットワーク構造の可視化でクラスターを発見できそうです。

愛知県は残念ながらPDFでしか情報を公開しておらず、データの可搬性が全然考えられていません。
幸いなことに、このPDFデータを機械が判読可能な形に有志が変換して集めているサービスを見つけたので、[こちらのデータ](http://linkdata.org/work/rdf1s8260i)を使うことにしました。

# グラフ型データベースへのデータの登録

今回扱うようなネットワーク構造を扱うには、グラフ型データベースが相性がよさそうです。
別のプロジェクトでも使ったことのある Neo4j を使うことにしました。

## 簡単な例

例えば、以下のクエリを叩くことで、陽性者Aと、Aと接触のあった陽性者Bの関係を登録することができます。

```
create (a:Person {name: "A"})-[:CONTACTED]->(b:Person {name: "B"}) return *
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54003/16fb72b4-db0c-3147-cf7a-7468403ff036.png)
可視化には Neo4j に標準で付属しているブラウザ駆動のコンソールが備わっていて便利です。
 
## データのパース

公開されている元PDFのカラムがそのまま http://linkdata.org/work/rdf1s8260i に csv 形式などで登録されているため、多少データの整形をしなければなりません。

「No. 1と接触」「No. 3、No.5〜10と接触」のように、フォーマットが統一されていないのが一番手間でした。
ここは正規表現を駆使して、全部の表現を網羅できるようにしました。

## データの可視化
	
全データを追加するクエリを自動生成して、データを登録すると、ネットワーク構造の可視化ができるようになります。
登録されたデータから最大ノード数を 100 にしてクエリを発行しました。

```
MATCH (p:Person)-[:CONTACTED]->(q:Person) RETURN * ORDER BY p.date asc LIMIT 100
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54003/de2ee702-0eed-af09-63f1-22e7070bc0bc.png)
簡単なクエリでも、接触による伝搬がよく可視化されていると思います。
全データを追加したときに、年齢や性別の情報もいれたので、それらも可視化可能です。

例えば、上の可視化を拡大すると、年齢がラベルに表示されているのがわかります。
高齢者を中心としたクラスターを発見できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54003/b92dce5b-747a-c185-1bae-c130c55b31aa.png)

# 大規模なクラスターの検索

グラフ型データベースの最大の特徴は、データ同士の繋がりの深さなどを検索しやすいことです。
例えば、以下のクエリで、各人が合計何人に伝搬したか数え上げることができます。

```
MATCH (p:Person)-[c:CONTACTED*1..]->(q:Person) RETURN COUNT(DISTINCT c)
```

このデータを Person のプロパティに加えると、結果的に大人数に影響を及ぼしたノードを発見できます。
以下のようなクエリでプロパティを追加します。

```
MATCH (p:Person) SET p.n_descendant = 32
```

試しに、32人以上の大規模なクラスターを見つけてみましょう。

```
MATCH (p:Person)-[:CONTACTED*1..]->(q:Person) WHERE p.n_descendant > 32 RETURN*
```
大規模なクラスターのみを可視化できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54003/b82fbb79-e3f3-2309-4272-6ff723dc92b6.png)

7月ごろからしきりに言われている若者クラスターも発見できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54003/b65b0721-4569-090d-4ec6-6c67c3ddd609.png)

# ウェブアプリの実装

せっかくなので、このデータを誰でも触りやすいようにウェブアプリを作ってみました。

https://covid19.hashup.pro/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54003/51e80293-59fd-7dd4-574e-d0ff349c69d4.png)


## 採用した主なライブラリ
### React + TypeScript
React は業務で利用していたこともあって、慣れてはいましたが、TypeScript を一から導入したのは初めてでした。型のサポートがやはり強力で、一度使うと型がないと不安になりますね。大規模なアプリにはならなさそうだったので Redux のようなステート管理ライブラリは使いませんでした。
### Material UI
時々業務で使うことがあったのですが、JSベースのCSSなど、書き方を半強制的してくるのがイマイチだと思っていました。カレンダーのUIがあるという理由のみで採用しました。実際に使ってみると、JSベースのCSSだとスコープの見通しがよくなったり、値のちょっとした変更がしやすく、かなり気に入りました。これまで Semantic UI を気に入って使っていたのですが、これからは Material UI を導入することが多くなりそうです。
### Neo4j on Docker
Neo4j を Docker 上で走らせるようにしました。無料のコミュニティ版だと、データベースの読み書きの権限を詳細に設定できませんでした。できるだけケチりたいので、色々考えたところ、Read Only モードがあったので、それを使ってフロントエンドと繋ぐことにしました。
### NeoVis
Neo4j の公式 JS ライブラリです。React が公式でサポートされていないので、導入にやや苦労しました。vis.js がベースとなっていて、ノードの属性によって色や大きさを変更できます。今回のプロジェクトでは、居住地や性別、年齢などによって動的にノードの色を変更できるように使いました。

## 主な機能

アプリはできるだけシンプルに留めました。
表示するノードは、右下の設定アイコンから設定できるようになっており、ここの項目から自動的にクエリを発行してフェッチするようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54003/11eafa46-8846-082b-9a11-c4533cc7420e.png)

推したい機能のひとつは、「ヒント」を用意したことです。
実際に他の人に触ってみてもらったところ、眺めるだけでどう使えばよいかわからないとのコメントをもらいました。
そこで、表示設定のパラメータの変更を言語化した項目も用意しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54003/eebfe65e-ba14-4518-6003-99f1bc38a979.png)

色分けの機能をつけており、例えば、都市間の発生事例伝搬を可視化することができます。
下図の例では、小牧市のスーパースプレッダーと思われる人物が、名古屋市に移動したことにより、感染を広めてしまった、と予想することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54003/19183805-2bd0-1c8a-3d72-55cf44a61db4.png)


# 苦労した点

データの収集や分析を行う上で、一番苦労したのは、データ整形についてです。
総務省も地方公共団体におけるデータ利活用を促進しようとしています。
https://www.soumu.go.jp/menu_seisaku/ictseisaku/ictriyou/bigdata.html
しかし、愛知県では、公式の情報は PDF のような機械可読性が低いデータでしか公開されていませんでした。
PDFで公開されている表の中身も、少し工夫するだけで、データ加工の手間が省けるにと、大変もどかしい気持ちになりました。

県を跨いだ伝搬の発生も耳にするので、三重県や岐阜県のデータも収集してみようと思いましたが、公開されているデータが扱いにくく、諦めました。

自分がやっている研究では、出てくるデータがある程度コントロールされているので、データ加工の難しさに苦労したことは少なかったです。
初めて、一般向けに公開されたデータを触ってみて、機械学習などの分析の前段階のデータ収集段階の大変さを痛感しました。

# 感想

ニュースでクラスターが発生しているとは聞くものの、どのような属性のクラスターが発生しているのかわかりませんでした。
自治体が公表しているデータを加工することで、実際に発生しているクラスターを観察することができました。

更に、若者クラスターを見つけたり、都市間で伝搬している様子をみて、危機意識を持つこともできました。
こういった情報は他の人にも役に立つと思ったので、ウェブアプリとして一般公開するに至りました。
コメントや感想などを寄せていただけると嬉しいです。

最後に、今回ネットワークグラフの可視化をやってみるきっかけになった記事を貼っておきます。
名古屋大学の奥村先生が中京テレビが公開しているデータを元に、GraphViz で感染経路の可視化を行なった記事です。
https://oxon.hatenablog.com/entry/2020/04/09/105305

ニュースの情報だけに頼るのではなく、一次情報や、それを分析したデータから身の回りで起こっていることを観察するという研究者として大事な考え方を学ぶことができました。