薬剤師のプログラミング学習日記

プログラミングやコンピュータに関する記事を書いていきます

1-コンパートメント点滴静注繰り返し投与のグラフ描画

前回記事「1-コンパートメント点滴静注モデルの血中濃度推移」の点滴静注モデルにおいて、反復投与したときの血中濃度推移のグラフを描きます。
f:id:enokisaute:20200307125304p:plain


反復投与時の血中濃度

投与間隔\tau(ギリシャ文字:タウ)でn回目に投与したときの点滴終了後の血中濃度を表す式は次のようになります。

\small \displaystyle{ C_n=\frac{k_0}{Vd \cdot k_e}(1-e^{-k_e T}) \frac{1-e^{-nk_eτ}}{1-e^{-k_eτ}} e^{-k_e(t-T)}}~~~~~(t≥T)

※T:点滴時間

複雑そうにみえますが、単回投与のときの式との違いは、式の中程に\frac{1-e^{-nk_eτ}}{1-e^{-k_eτ}}があることだけです。
導出はここには書きませんが、C_1, C_2, C_3, ・・・,C_nと考えていくと等比級数の和が現れます。そこで和の公式を使うと、この\frac{1-e^{-nk_eτ}}{1-e^{-k_eτ}}のようにまとめることができます。

点滴開始から終了までの式はこちらです。

\small \displaystyle{ C_n=\frac{k_0}{Vd \cdot k_e}\{(1-e^{-k_e T}) \frac{1-e^{-(n-1)k_eτ}}{1-e^{-k_eτ}} e^{-k_e(t+τ-T)}+(1-e^{-k_e t})\}}~~~~(t<T)


f:id:enokisaute:20200307125346p:plain

n回目の点滴中の血中濃度(図中の青丸)は、n-1回目に投与された残存分(青色点線)+n回目に投与された分の血中濃度となります。これがそれぞれ、式の中カッコ{}内の前半と後半部分に対応しています。なお、ここでのtはn回目に投与開始してからの経過時間です。

血中濃度推移を求めるクラスを作る

では実装してみます。今回は処理をクラスにまとめてみました。

class BloodConc:
    def __init__(self, x0, vd, ke, T, interval):
        self.k0 = x0 / T          # 点滴速度
        self.vd = vd              # 分布容積
        self.k = ke               # 消失速度定数
        self.T = T                # 点滴時間
        self.interval = interval  # 投与間隔
        # 点滴開始~終了時間の経過時間
        self.td = np.linspace(0, T, num=int(T / 0.1), endpoint=False)
        # 点滴終了後~次回投与直前まで
        self.ta = np.linspace(0, interval - T,
                      num=int((interval - T) / 0.1), endpoint=False)
 
    # (1):点滴開始~終了直前
    def __calc_during_div(self, n):
        c = (self.k0 / self.vd / self.k) * ((1 - np.exp(-self.k * self.T))
             * (1 - np.exp(-(n - 1) * self.k * self.interval))
             / (1 - np.exp(-self.k * self.interval))
             * np.exp(-self.k * (self.td + self.interval - self.T))
             + (1 - np.exp(-self.k * self.td)))
        return c.tolist()
 
    # (2):点滴終了時~次回投与直前
    def __calc_after_div(self, n):
        c = (self.k0 / self.vd / self.k) * ((1 - np.exp(-self.k * self.T))
             * (1 - np.exp(-n * self.k * self.interval))
             / (1 - np.exp(-self.k * self.interval))
             * np.exp(-self.k * self.ta))
        return c.tolist()
 
    # (1)+(2):点滴開始~次回投与直前
    def get_section_conc(self, n):
        c1 = self.__calc_during_div(n)
        c2 = self.__calc_after_div(n)
        c1.extend(c2)
        return c1
クラスとは

プログラムで利用する部品(オブジェクト)の設計図のようなものです。どのようなデータを持つか、どのような命令(メソッド)を持つかを定義します。

何をするクラスか

n回目の点滴中と点滴終了後の血中濃度を別々に計算(コメント(1)と(2)のメソッド:上で示した数式が使われています)し、それらを合わせることで投与間隔時間分の血中濃度として返します。

動かし方

パラメータを与えてインスタンス(オブジェクト)を生成後、呼ぶのはメソッドget_section_conc()だけです。引数nに1, 2, 3...と何回目の投与かを指定して繰り返し呼び、その結果を繋ぎ合わせていくことで反復投与の血中濃度を生成します。

bc = BloodConc(x0, vd, ke, T, interval)
conc = []        # 血中濃度
 
# 1~n回目の投与までの血中濃度を加えていく
for i in range(1, n + 1):
    conc.extend(bc.get_section_conc(i))


インスタンス変数

個々のインスタンスが持つ固有のデータを扱う変数のことをインスタンス変数(アトリビュート)といいます。ここではVdやke、投与間隔などが該当し、インスタンスの生成時に初期化メソッド(コンストラクタ)__init__()内で初期化しています。
点滴中の経過時間(td)と点滴終了後~次回点滴直前までの経過時間(ta)も、毎回生成する必要がない(決まった時間間隔である)ためこの中で生成しています。

こちらがコード全文です。今まで同様に、Vdやkeなどのパラメータは適当な数字です。

import numpy as np
import matplotlib.pyplot as plt
 
class BloodConc:
    def __init__(self, x0, vd, ke, T, interval):
        self.k0 = x0 / T          # 点滴速度
        self.vd = vd              # 分布容積
        self.k = ke               # 消失速度定数
        self.T = T                # 点滴時間
        self.interval = interval  # 投与間隔
        # 点滴開始~終了時間の経過時間
        self.td = np.linspace(0, T, num=int(T / 0.1), endpoint=False)
        # 点滴終了後~次回投与直前まで
        self.ta = np.linspace(0, interval - T,
                      num=int((interval - T) / 0.1), endpoint=False)
 
    # (1):点滴開始~終了直前
    def __calc_during_div(self, n):
        c = (self.k0 / self.vd / self.k) * ((1 - np.exp(-self.k * self.T))
             * (1 - np.exp(-(n - 1) * self.k * self.interval))
             / (1 - np.exp(-self.k * self.interval))
             * np.exp(-self.k * (self.td + self.interval - self.T))
             + (1 - np.exp(-self.k * self.td)))
        return c.tolist()
 
    # (2):点滴終了時~次回投与直前
    def __calc_after_div(self, n):
        c = (self.k0 / self.vd / self.k) * ((1 - np.exp(-self.k * self.T))
             * (1 - np.exp(-n * self.k * self.interval))
             / (1 - np.exp(-self.k * self.interval))
             * np.exp(-self.k * self.ta))
        return c.tolist()
 
    # (1)+(2):点滴開始~次回投与直前
    def get_section_conc(self, n):
        c1 = self.__calc_during_div(n)
        c2 = self.__calc_after_div(n)
        c1.extend(c2)
        return c1
 

if __name__ == '__main__':
    # T>intervalとならないように注意
    # intervalは24の約数で指定
    x0 = 100         # 投与量(mg)
    vd = 12          # 分布容積(L)
    t_half = 10      # 半減期(hr)
    ke = np.log(2) / t_half        # 消失速度定数(hr^-1)
    T = 3            # 点滴時間(hr)
    interval = 12    # 投与間隔(hr)
    days = 3         # 何日投与するか
 
    n = int(days * 24 / interval)  # 投与回数
    print('n: ', n)
 
    bc = BloodConc(x0, vd, ke, T, interval)
    conc = []        # 血中濃度
 
    # 1~n回目の投与までの血中濃度を加えていく
    for i in range(1, n + 1):
        conc.extend(bc.get_section_conc(i))
 
    period = 24 * days
    time = np.linspace(0, period, int(period / 0.1), endpoint=False)
    # intervalが24の約数以外のときは長さが合わなくなるため調整
    # time = time[0:len(conc)]
 
    plt.plot(time, conc, color='blue')
    plt.ylabel('血中濃度[μg/mL]')
    plt.xlabel('時間[hr]')
    plt.title('1-コンパートメント点滴静注繰り返し投与')
    plt.xlim(0,)
    plt.ylim(0,)
    plt.grid(linestyle='dashed')
    plt.show()

参考文献

・みんなのPython 第3版
9. クラス — Python 3.8.3rc1 ドキュメント