Stan & POPPK (1): 一被験者の薬物動態解析
StanでPopulation pharmacokinetic解析 - yoshidk6’s blog の続きです。
最初のステップとして、一被験者のデータを用いた解析を行います。
(2017/5/27 に、データ・コード含めて更新を行いました。)
(2017/10/26 にコードの再更新を行いました。)
使用する仮想データ
作成された仮想データは、各被験者がTIME=0で薬物を経口投与された後、各時間ごとに血中濃度を測定(CONC
)されたという状況を想定しています。
今回はこのうち、ID==1の被験者のデータを解析します。
simple_pk_stan/sim_pk_20170521.csv at master · yoshidk6/simple_pk_stan · GitHub
図示してみると、薬物が吸収されるに従って血中濃度CONC
が上昇し、次第に体内から排出されるに従って減少していくことが分かります。
library(tidyverse) data.pk <- read_csv("https://raw.githubusercontent.com/yoshidk6/simple_pk_stan/master/data/sim_pk_20170521.csv") data.pk %>% filter(ID==1) %>% ggplot(aes(TIME, CONC)) + geom_line() + geom_point()
Stanモデル
transformed parameters
このブロックで、1-コンパートメントモデルの解析解に基づいて濃度の算出を行っています(算出式に興味が有る方は一つ前の記事を御覧ください)。
薬物動態パラメータから計算された各時点での血中濃度の平均値がmu
に代入されます。
model
Y
(測定値)は標準偏差s_Y
の対数正規分布に従うと設定しています。
各薬物動態パラメータについては、推定を安定させるため弱情報事前分布を設定しています。また、初期値もある程度plausibleな値を中心にランダムに生成するように設定しています*1
GitHubリンク: https://github.com/yoshidk6/simple_pk_stan/blob/master/code/mod_00_single_subj.stan
Rコード
上記のモデルを動かすRのコードは以下の通りです。
library(tidyverse) library(rstan) library(ggmcmc) rstan_options(auto_write=T) options(mc.cores=parallel::detectCores()) data.pk <- read_csv("https://raw.githubusercontent.com/yoshidk6/simple_pk_stan/master/data/sim_pk_20170521.csv") ## Prepare data for Stan data.pk.id1 <- filter(data.pk, ID==1) init <- function(){ list(KA = exp(rnorm(1, log(0.5), 0.2)), CL = exp(rnorm(1, log(0.5), 0.2)), VD = exp(rnorm(1, log(5), 0.2)), s_Y = runif(1, 0.5, 2)) } data <- list(N = nrow(data.pk.id1), TIME = data.pk.id1$TIME, DOSE = 10, # ID==1の被験者への投与量は10と設定しています Y = data.pk.id1$CONC) ## Run Stan fit.stan <- stan(file = "mod_00_single_subj.stan", data = data)
結果の評価
安定した推定結果が得られ、推定値のmean (CL=0.33, VD=5.06, KA=0.93, s_y=0.17)も、もともと設定した値(CL=0.30, VD=4.89, KA=1.0, s_y=0.15)と非常に近い値となりました。推定されたパラメータを元に算出された平均値と90%予測区間も、実測値と比較的良く合っています。
上図を生成するためのコードは以下の通りです。
mcmc.sample <- rstan::extract(fit.stan) y.pred.interval <- mcmc.sample$y_new %>% apply(MARGIN=2, quantile, prob=c(0.05, 0.5, 0.95)) %>% t() %>% tbl_df() bind_cols(data.pk.id1, y.pred.interval) %>% ggplot(aes(TIME, `50%`)) + geom_line() + geom_ribbon(aes(ymin=`5%`, ymax=`95%`), alpha=0.1) + geom_point(data=data.pk.id1, aes(TIME,CONC))
次の記事では、複数被験者のデータを用いたパラメータ推定を行います。
*1:今回用いているモデルには2つの解が存在してしまうことが知られているので(flip-flop)、ラベルスイッチングを何らかの方法で避ける必要がありました。一被験者の場合は値に上下関係をつけることも可能なのですが、後にあるように複数被験者に対して各個人のパラメータを推定すると制限をつけるのが難しくなってしまうため、今回は初期値をうまく設定することにしました。