コロナウィルス流行曲線をPythonで描いてみる

 佐藤總夫「自然の数理と社会の数理 II 微分方程式で解析する」(日本評論社)という名著があった。ホントはI, II, IIIと3分冊で出るはずが,I, IIが出た後は音沙汰なしという,当時学部生だったワシが残念に思っていたシリーズである。今回のコロナウィルス騒ぎで散々出てくるあの「流行曲線」という奴,本書に詳しく出てたので,折角だから知識と本の虫干しがてら,Python+SciPyで描いてみることにしよう。つーことで,以下の数学的な記述は全部佐藤著の「第7話 伝染病の伝播」に基づくものなので,詳しく知りたい人は図書館にGoである。理工系大学ならあるんじゃないのかな。

 感染症モデルの中でも一番簡単なものを取り上げる。前提として

  • 感染者を[latex]y = y(u)[/latex], 感受性者(これから感染する可能性のある人)を\(x(u) = x\)とする。
  • 全人口を\(n+1\)とし,増減はないものとする(「死者は出ない」の意)。つまり常に\(x + y = n + 1\)が保持される。
  • 感染者の発生率は\(xy\)に比例する(人々の均等な接触を表現)。
  • 最初の感染者は\(y(0) = 1\)とする。

とする。この時,常微分方程式の初期値問題としては

\[ \frac{dx}{du} = -xy = -x(n+1 – x), x(0) = n \]

となる。新たにどの程度の感染者が現れるかを表現したもの,つまり感染スピードを表わす関数が\(w(u)\)である。上記を解いて\(x(u)\), \(y(u)\)を求め,そこから\(w(u)\)を計算してグラフ化したものが下記の図である。小うるさい人にすれば,人数が単位の\(x(u)\), \(y(u)\)と人/時間が単位の\(w(u)\)を同じ縦軸に描くとは何事だと言いそうであるが,これらの関数の関係を表したものとご理解頂きたい・・・今気がついたが,右軸も使えば良かったんだな,面倒くさいから,やりたい人向けの課題としておく。

 このグラフから,感覚的には次のことはすぐに分かる。

  • 感染を妨げるものはないので,最終的には全員に感染する。
  • 感染が止まるのは全員に感染するからであって,感染するスピードは山なりに変化する。

 初期感染者は今更ゼロにはできないし,できることといえば,感染者を見つけたら素早く感受性者から引き離して\(xy\) を減らすしかない。つまりは初期感染スピード\(w(0)\)を極力減らすしかない訳で,実際,\(w(0) = 10, 20, 30, 40\)まで\(10\)刻みで変えてみると下記のようなグラフを得る。

 このグラフが感染スピードの変化を示しており,当然ながら,初期感染スピードが遅ければ遅いほど感染率極力小さく抑えられることが分かる。現在の厚労省が取っている対策もこれに基づくもので,このグラフはまさしくこのグラフが描いている曲線ということになる。

 つーことで,上のグラフを描くためのPython + SciPyコード例を下記に挙げておく。ちなみに,この常微分方程式は解析解が手計算で求められるので,ピーク時はどこになるとかといった議論も可能である。詳細は佐藤著をご覧頂きたい。

# ode_epidemic.py: 常微分方程式の初期値問題

# numpy
import numpy as np

# integrateパッケージ
import scipy.integrate as spint

# matplotlib
import matplotlib.pyplot as plt

num_div_t = 100
windex = 0

w = [[0.0] * num_div_t for i in range(4)]
#print('w[0] = ', w[0])

# 人口
all_num_people = [11, 21, 31, 41]

for num_people in all_num_people:
    # 初期感染者
    num_infected_people = 1
    # 初期感受性者
    num_noninfected_people = num_people - num_infected_people

    # 陽的形式の右辺
    # y' = func(t, x) = -x(n+1-x)
    def func(t, y):
    #	return [-y[0] * (num_people - y[0])]
        return np.array([-y[0] * (num_people - y[0]), y[1] * (num_people - y[1])])

    # 初期値
    # y(0) = [n, 1]
    #y0 = [num_noninfected_people]
    y0 = [num_noninfected_people, num_infected_people]

    # t = [0, 1]
    t_interval = [0.0, 1.0]
    #print(t_interval)

    # 常微分方程式を解く
    #ret = spint.solve_ivp(func, t_interval, y0)
    ret = spint.solve_ivp(func, t_interval, y0, t_eval = np.linspace(t_interval[0], t_interval[1], num_div_t))

    # 感染者の増加率を計算
    w[windex][0] = num_noninfected_people # 初期感染者発生率
    for index in range(1, ret.t.size):
        w[windex][index] = (ret.y[1, index] - ret.y[1, index - 1]) / (ret.t[index] - ret.t[index - 1])
    windex += 1

    # 結果を表示
    #print(ret)

    # yを表示
    #print(ret.y)

# wを表示
#print('w[0] = ', w[0])

# t-yグラフを描画
# グラフ初期化
figure, axis = plt.subplots()

# 値をセット
#axis.plot(ret.t, ret.y[0, :], label='x(u)')
#axis.plot(ret.t, ret.y[1, :], label='y(u)')
axis.plot(ret.t, w[0], label='w(0) = '+ str(all_num_people[0] - 1))
axis.plot(ret.t, w[1], label='w(0) = '+ str(all_num_people[1] - 1))
axis.plot(ret.t, w[2], label='w(0) = '+ str(all_num_people[2] - 1))
axis.plot(ret.t, w[3], label='w(0) = '+ str(all_num_people[3] - 1))

# x軸,y軸,グラフタイトルをセット
axis.set(xlabel = 't', ylabel = 'w', title = 'Epidemic model')

# グリッドを描画
axis.grid()

# 凡例
axis.legend()

# グラフ保存ファイル名
figure.savefig('ode_epidemic_w.png')

# グラフを画面に描画
plt.show()

3/8(日) 駿府・雨

 山松ゆうきちの漫画のような「さかざんざんざん」という土砂降りの日。冬らしくないが,春を感じさせるような暖かいものでもない氷雨。今年はソメイヨシノの開花が次週にも迫っているようだが,そう簡単にいくかどうか。次週末は駿府城公園を探索してみよう。標準木,どうなっているかなぁ。

 静岡市内の警察署に出頭してきた。免許更新なのだが,ワシは優良ドライバーなので,圏内のどこの警察署でも30分のビデオを見るだけで更新できるのである。うっかりして床屋に行きそびれてしまい,髪も髭も伸び放題,ボサボサ状態の写真で写ることになった。ま,5年間の辛抱である。

 本学紀要原稿を書き上げ,それを流用してPython数値計算入門(仮)の多倍長精度計算の章を全面的に書き直した。今のところPythonにはQDのようなマルチコンポーネント型多倍長精度演算の高速なライブラリがないようなので,紀要原稿ではワシのCライブラリベースのモノを使ってのベンチマークテストを行い,Python数値計算の方はmpmathとgmpy2の比較を詳細に行った。ちと手間であったが,還暦まではせめて紀要原稿の一本ぐらいはコンスタントに書いていきたいものである。
 コロナウイルスが蔓延ってあらゆる出張やイベント予定がパーになっている今月をチャンスとし,Python本の方は偏微分方程式の章の書き足しと,補間計算の解説全面改稿,疎行列とソルバーの記述追記を目指したい。これができれば,あとはグラフィックスの方をどこまで追記できるかだなぁ。頑張りましょう。

カリオストロ伯爵配下の街の居酒屋で出てきそうなミートボールパスタ@静岡

 神さんとコロナ騒ぎで閑散とした街中を散策するも,ラーメン屋には客が入っているし,人通りは少ないが,人々の外出意欲が全くなくなったということではなさそう。マスクもあるところにはあるモンで,まだ我が家には備蓄はあるが,少し買い足しておいた。どこに売っていたかは書いてあげないのである。ワシらは老舗の洋食屋さんで昭和チックなランチセットを食して満足した。

 そーいや,ボチボチ額縁ょ〜就任一年になるんだなぁ。と言っても慣らし運転もいいところで,未だにあれこれ迷うこと多かれど,色々な情報が集まってくると学習するところも多かった。今後の大仕事は教員評価だが,大筋,自分が見知っているところと違う点は少ないことも分かった。まぁ査読論文・査読付き国際研究集会・著作等々,第三者の目が通ってパブリッシュされたものがどんだけあるかで仕事ぶりは分かる訳で,どんだけ言い訳しようともそれが全て。「論文書いて」と言えば済む,簡単なお仕事です額縁ょ〜は。任期はあと一年なので,せいぜい小うるさく嫌がられながら頑張りましょう。

 次週はPython仕事しながら今月末に締め切りのある国際研究集会用の仕事せにゃ。コロナ騒ぎのグローバル化でどこの集会の開催も危ういけど,人にハッパかけるなら自分もある程度はやらんとねぇ。声のでかい役立たずの評論家モドキにはなるまいぞなるまいぞ。

 風呂入って寝ます。

2/29(土) 駿府・曇時々雨

 今年は暖冬で春はすぐそこにあると思っていたら,冬将軍が最後のひと頑張りをしてくれたおかげで今週はいつもの寒さに戻っている。早咲きの桜や梅は終わりかけであるが,本命の染井吉野が開くのはまだ先のようである。

静岡マラソンもコロナウイルス禍で中止の憂き目にあう

 にしてもコロナウィルスの奴,なかなか生命力溢れるご活躍で,学会シーズンのはずの3月の予定が軒並み潰れまくっている。日本応用数理学会とかHPC研究会とか,ろくすっぽ人の集まらならないマイナーなところから,情報処理学会のように大所帯のところまで中止中止中止である。ワシが行く予定だった出張講義も先方の方からお断りされる始末。おかけで「原稿執筆にはぴったりの状況になりましたね」などと編集者の方から言われるし,実際,今日は神さんが軽い風邪で寝込んでしまったせいで,滞っていた紀要原稿も,それを流用して書く予定だったPython数値計算本の第4章もあらかた出来上がってしまった。この調子ではPython本は今月中に偏微分方程式のところもできてしまいそうだし,余勢で情報数学基礎本の新章まで書いてしまいそうである。ま,原稿執筆とプログラミングには最適な状況であることは間違い無いので,せいぜい有意義に過ごすことにしたい。

 同年輩の方の訃報は気になるもので,筒井康隆のご長男逝去のニュースには驚いた。ツツイストなら皆知っている方であるが,食道癌,気がついたときにはステージが進んでいたとのこと。ワシも喉に違和感があって医者に行き,内視鏡で調べてもらったら逆流性胃腸炎と言われたので,癌かどうかの判断は自分では難しいモンなんだろう。ワシの手元には御子息が挿画を手がけた「聖痕」の単行本があるので,これを眺めながら合掌することにしたい。・・・そうそう,この小説の主人公,造形のモデルはこの御子息だったんじゃないのかなぁと,読み終えてから思ったんだっけ。

蜜蝋という手法によるものだとのこと

 神さんの風邪,軽いものだったようで,アイスとうどんとカスタードケーキ食ってベッドでiPhone見ながらゴロゴロしている。食欲は旺盛だし,咳も全く出ないので,コロナでは無い模様。こう急激に寒くなっては,コロナ以外のインフルエンザや風邪やノロが蔓延る訳で,日本政府のお節介で2週間の遠出ができなくなったのを幸い,せいぜい家と職場でやるべきことに傾注しないとなぁ。いつ死ぬかわからんし。

 つーことで,なるべくここの更新もマメにやりたいものである。

1/11(土) 駿府・曇後晴

 明けましておめでとうございます。本年もよろしくお願い致します。

 今更ではあるが2020年最初の投稿なので定番の挨拶から。しかし,のっけから残念な訃報があってかなりブルーである。

 昨年6月には主宰されていた数値解析シンポジウムへのお誘いも受けていたし,普通に活躍されているものと思っていたが,本年早々に急逝されたとのことで仰天した。ソースがはっきりするまではオープンな場で言及しないようにしていたのだが,新聞記事になったのでTweetした次第。学長補佐というと,かなりの激務という印象で,責任感が強い方だったので,無理してストレスも溜まっていたのかなと勝手に推察している。人格者ほど早逝される傾向にあるが,何にしろ残念である。ワシも長生きするつもりもないのだけれど,何分人間の質が悪いので,無駄に生きながらえてしまいそうな気配があるが,そうなればせいぜい悪あがきしようと考えている。ワシみたいな人見知りのコミュ障とお付き合いいただいたことに感謝致します。合掌。

 つーことで,悪あがきしながら次週半ば締め切りの論文のためのプログラミングとベンチマークに勤しんでいる。何とかなりそうというところで案の定,〆切がextended,2週間も伸びてしまった。まぁ推敲の時間が十分取れたと解釈して,元々の締め切り日を目指してこの三連休は頑張るつもり。最初のお披露目は3月のHPC研究会かな。久々の札幌開催なので,行きやすくなったのはありがたし。オッサンらしく,蘊蓄で時間とって嫌がられて進ぜようぞ。

 松の内はいつもの通り,東照宮と浅間神社を詣でる。日本平から見る富士山はいつもながら見事である。 

日本平から清水港の方向に富士山を望む

 本日は鏡割りがてら,毎年買っている干支フィギュアを取り出す。本年で十二支コンプリートである。来年からはなるべく同メーカーのキャラで二巡目を目指したい。全部揃う頃には定年2年前である。どうなっているかなぁ。

ミニ鏡餅の干支キャラクターフィギュアコンプリート

 昨年は多倍長計算本を出せたが,今年は何とかPython本を出したい。年度内に記述を充実させたいが,額縁ょ~としての業務も大変なことになりそうなので,せいぜい頑張ります。情報数学基礎の新装版も出そうだし,充実した一年にしたいところ。

 生きて活動できるうちに,ジタバタしますよワシは。

12/31(火) 駿府・晴

 これから正月を迎えようというのに,本日の日中の気温は20℃,日本海側には寒気が吹き付けているようなのでフェーン現象かな? 冬とは思えないほど汗ばむ陽気である。

 本日は予告通り,神さんが実家にご帰還あそばされておるので,ワシはひとり者状態。例によって旨煮(左図)は作るものの,今回は年越しソバ兼増煮汁(右図)も合わせて作ることになった。ということで下記のように作成したのである。

 ちなみに,兼用汁は煮込んだ途端に青いネギがクタクタの茶色に変色してしまうので,食う時には地味汁と化すのである。旨煮については,少し濃い目の味付けにしたのでアクセントは着いたかとは思うが,里芋の煮崩れを気にしすぎて硬めになってしまった。お年寄り向きではないかもしれん。明日神さんとこに持っていくので,堅いところは神さんに食ってもらうことにしよう。

 さて,今年は査読論文相当の発表1件単行本1冊出版できたので,額縁ょ〜しながらも,ワシとしてはまぁまぁ仕事の成果が出せた年と言える。問題は来年もこのペースで仕事ができるかどうかだが,この正月はひとり者タイムをプログラミングに費やしているので,多少なりとも足掛かりはできるかなあとは思う。Python本については予定より難航しているものの,一応,章立てはできたし,必要最低限のPythonスクリプトは突っ込めたので,とりあえず2月までに完成度を上げて,3月中には偏微分方程式のところを何とかしたいところ。もうひと頑張りでは済まず,もう3頑張りは必要になると思われるが,ワシの老後を楽しく過ごせるかどうかの試金石でもあるからして,50代のおっさんの踏ん張りどころ,最近前に出てきた腹を引っ込めるためのエクササイズに励みつつ,せいぜい足掻いてみるつもりである。

 ということで,本年最後のご挨拶をして締めることにする。

 2019年は多方面の方々にお世話になりました。来年もよろしくお願い致します。