見出し画像

平行線定量法をWebアプリにしてみた

https://parallel-line-assay-beta.onrender.com

Webアプリを作ってみたくなり、ワクチンの業界にいたので自分には馴染みがあるが、他でつかってるのをあまり聞かない平行線定量法を題材に選んだ。
なぜかワクチンの力価試験ではよく使う。他には、夾雑物がある場合のエンドトキシンの定量などに使ったりするらしいが、詳細は知らない。



原理

理論的な説明は以下のサイトに詳しい。

有効成分量の量に依存して反応量が変わるという試験系がある。
例えば、インフルエンザHAワクチンの場合、一元放射免疫拡散法というのだけど、血清を混ぜ込んだゲルの穴に製剤を入れると、製剤中の抗原量に対して、出来上がる沈降輪の大きさが変わる。
とりあえず、直径が比例するものして、濃度と直径が正比例だとしよう。
こういう反応に対するよくある試験系は、濃度既知の標準品で検量線を引いて、検量線に、検体のリング径をあてこんで、濃度がわかる。というのが多いと思う。
検量線法は、線に対して点で探すイメージ。
対して、平行線定量法は、検体も複数段階で希釈、標準品も複数段階の希釈で、両方とも線のデータがある。
つまり、平行線定量法は、線と線の比較というイメージ
実際に、見てもらったほうが早い。
group2はgroup1に比べて
成分量が2倍入ってたとする。
量あたりのレスポンスは2倍になる。
容量(dose)あたりの反応(response)の違いは、group間での直線の傾きの比として表れる。これが効力比だけど、傾きの比だと扱いづらいので、
「横軸をlog doseにして、平行移動の距離として扱えば計算が楽じゃね?」
というのが、根本的な発想。真数のときに直線だったものを、x軸だけ対数にしたら直線じゃなくなるので、その場合、yも適当に変換してやる必要がある。一番簡単なのは、yも対数を取ってあげる方法。
xy平面で直線なら、log x-log y平面でも直線になるのは自明だ。
しかし、どうなんだという感じはある。
元々は、薬物に対する反応みたいに、対数容量と生体反応が比例する反応に使われた解析法。
対数容量じゃなく実容量と比例するなら、そのまま求めろよというふうに思えてならない。

実際、別にできなくはない(勾配比検定法http://www.snap-tck.com/room04/c01/stat/stat13/stat1303.html
ただ、対数変換によって、xy平面では直線ではなく多少反った容量反応曲線であっても、log x-log y平面でも直線で近似できるようになるので、使い買ってはいい。

インフルエンザHAワクチンの力価試験

インフルエンザHAワクチンでの力価試験だと、横軸が検体と、容量が標準品の希釈倍数、反応をリングの直径として解析する。
容量は対数容量に、反応も対数を取った値で計算をする。
BioAssistAssayという感染症研究所が配ったソフトと聞いているけれど、詳細は不明。ソースコードは明らかなんだろうか。
インフルエンザHAワクチンの抗原量と沈降輪のサイズは、実は正比例じゃなくて反ってる。
ちなみに、理論的には、沈降輪の面積とはつまり抗原抗体複合体の量であるはず。従って、抗原量と面積が比例するはずだ。
ということは、直径は面積の平方根に比例するはず。
「じゃあ、希釈倍数と直径の平方根なら直線になるのか?直線同士だったら、容量を対数なんかにしないで勾配比検定が使えるのか?」
という疑問がわくけど、そうはいかない。
反応を直径と定義した場合、上に凸の容量反応曲線になりそうだが、実際はそうはならない。試料(抗原)を入れる穴の部分があるからだ。
リングの面積から、穴の面積を引いた面積というのが、成分量と比例するわけだ。
それに、濃度が高ければ無限に大きくなり続けるわけではない。リングが大きくなりすぎると、辺縁が不明瞭になってよめなくなっていく。
加えて、穴があるともう一つ問題がある。
勾配比検定となると、原点を通る直線を仮定しなければならないのだけど、原点を通るはずがない。だって、最小のリングサイズは穴のサイズだから、それ以上の大きさはあっても、それ以下にはなりようがない。
傾きの比で効力比を計算する勾配比検定だと、同じ切片を持つ仮定が必要になるのだけど、そこがうまくいかなかったらしい。
平行線定量法だと、平行線の平行移動の距離を効力比の対数となるのだが、そちらだと、上手くいったとのこと。
上手くいったってなんやねん。
って思うけど、つまり、「平行であるという前提が無茶とはいえなそうなので、とりあえず効力比として計算しても許してちょ(はーと)
昔の人って適当だなぁ・・・
ざっくり言えば、非平行性が有意でなかったら、共通の傾きを仮想して、そのときの平行移動の距離が効力比の対数として計算、という流れ。
ちなみに、知らない人がこの解析に関わると、フィットしない高濃度のデータを除外するべきかどうかで議論があったりする。
「それは恣意的だからダメだ!」とだいたいご立腹する。
まあ、そんなことを言うと、そもそも解析できるようにご都合で対数変換してる時点で変な話なんで、そこじゃないだろって思う。
有意だったらダメとか、そうじゃなかったらいいというロジック自体が、0.05という数字に根拠なんかないわけだし。有意じゃないからって平行というわけじゃないんだけど。
(なお、Webアプリでも5%で有意じゃなかったらLines are parallelと表示させるようにはしてる。だって、平行でないとは言い切れない、みたいな二重否定ってウザいので、嘘になるけど、平行って言いきってる。)

ジフテリアワクチンの力価試験

容量を希釈倍数、反応をELISAのODとしている。
容量も反応もともに対数をとってから、平行線定量法を行ってる。
けっこう綺麗に、容量と反応が直線なので、対数にしないでそのまま勾配比検定すべきなのでは?
と思うのだけど、なんでかはわからない。
イメージこんな感じ。Excelで描かせた汚い図。


x:容量 y:反応


x:対数容量 y:対数反応

インフルエンザHAワクチンの力価試験と一緒で、非平行性の検定で、非平行性が有意じゃないということを確認して、効力比を計算にうつる。
あと、分散の一様性を検定したりする。
分散の一様性をもって、残差の正規性を検定してるということなのかな?そんな理屈通らないんだけど。
ポワソン分布とかみたいに、平均と分散になんらかの関連があったりすると、解析の前提が崩れるということなのかもしれない。
生の反応の値(ODの読み値)の誤差がどう分布するかを議論するのはわかる。正規分布すると仮定するのか、一様分布を仮定するのか。議論したってまあいい気はする。
でも、対数にしちゃったらどうなんすかね・・・
値が大きいところ(容量が高値のところ)では、対数で小さくなる分、生の値での分散比べて変換後の分散は過少に評価され、小さいところではその逆なはずで。あれか、
「解析するうえで仮定が無茶なとは言えない=無茶じゃない=常識的な範囲で許容できる変換(なわけあるかい)だから許せ」
みたいなことなのかな。
無駄だと思ったので、今回のWebアプリには分散の一様性の検定は実装せず。残差プロットだけ実装した。

Webアプリの概要

計算の概要

容量(Dose)については常用対数に変換、反応(Response)については、任意の変換を選ばせることにした。対数(Log)、Sqrt(平方根)、Box-Cox、Logitを用意。変換については後述。
submitボタンで計算してグラフも描いてくれる。
計算の中身は、groupをダミー変数にして、statmodelsで線形モデルに当てはめてる。最初は交差項をつくって、交差項の信頼区間から非平行性の検定を実施。
5%の優位水準を下回らなかったら、交差項があるモデルを破棄して、交差項がない、同じ傾きを仮定したモデルに当てはめる。
groupと切片の重回帰の係数からgroup間での平行移動量を算出。
これが効力比の対数ということなので、真数に戻してあげる。
一応、効力比だけでなく、各パラメータの信頼区間を出してあげるようにした。

グラフは別に大したことをやってない。
元の容量と反応の散布図、横軸だけ対数にして同じ図、横が対数で縦が変換後の値にした図、この三つ目の図にだけ、共通の傾きの線を重ねる。
それから、おまけで残差プロットを用意。

変換

理想は、変換しない(None)で横軸が対数軸にしたときに平行なら、考えないでいい。けどそんなうまいのはあまりない。
元の容量反応が最初から直線だったら、変換はLogを選べば横軸が対数になってもそのままのはず。あるいは、下に凸でも対数変換で直線になるので、直線じゃなかったとしても試す価値あり。
平方根は、対数と逆に上に凸の容量反応曲線だったときに有効。
それに、理論的に見ても容量と反応の平方根が比例するという系がありそうな気がするので実装してみた(でも、考えてみたら、対数容量と反応の平方根が比例ならとにかく、容量と反応の平方根が比例しても仕方ないよね。たぶん、使うことはなさげ)。
Box-Coxは万能、使えばわかる。正規分布するように変換されて、各種解析もしやすいし、どんなデータもだいたいうまくフィットする。
Logitは、反応が比率(0~1)のとき。
容量を殺虫剤の濃度にして、反応を虫を何割殺したかという比率の値にしたときなど。

開発環境などなど

バックエンドはPython、使ったライブラリは以下。

  • Flask

  • pandas

  • statsmodels

  • scipy

  • seaborn

  • matplotlib

  • gunicorn

フロントエンドのhtmlとCSSとJavaScriptはChatGPT様に頼りっぱなし。
入力のインターフェースが不満。スプレッドシート上のテーブルからコピペできるといいのだけど、無料で使えるものがなかったので、1データ1行で入力させる方式に。
どうせ満足いくインターフェースが作れないなら、Streamlitで作ればよかった。

場所など


Renderという無料で動かしてくれるサービスがあって、Herokuの有料化の受け皿らしい。Githubから連携するだけでデプロイできた。便利。



この記事が気に入ったらサポートをしてみませんか?