<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Bayesian Statistics | Siqi Zheng</title><link>https://siqi-zheng.rbind.io/tag/bayesian-statistics/</link><atom:link href="https://siqi-zheng.rbind.io/tag/bayesian-statistics/index.xml" rel="self" type="application/rss+xml"/><description>Bayesian Statistics</description><generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>en-us</language><lastBuildDate>Wed, 04 Aug 2021 01:00:00 +0000</lastBuildDate><image><url>https://siqi-zheng.rbind.io/images/icon_hu1f65844ca26c0df97a9719a407d829c0_98767_512x512_fill_lanczos_center_2.png</url><title>Bayesian Statistics</title><link>https://siqi-zheng.rbind.io/tag/bayesian-statistics/</link></image><item><title>Modelling the dynamics of a Chalmydia infection</title><link>https://siqi-zheng.rbind.io/post/2021-08-04-bayes-bio-model-1/</link><pubDate>Wed, 04 Aug 2021 01:00:00 +0000</pubDate><guid>https://siqi-zheng.rbind.io/post/2021-08-04-bayes-bio-model-1/</guid><description>&lt;p>The assignment requirements can be found here above by clicking the &amp;lsquo;assignment&amp;rsquo; icon.&lt;/p>
&lt;ul>
&lt;li>
&lt;a href="#task-1">Task 1&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#task-2">Task 2&lt;/a>
&lt;ul>
&lt;li>
&lt;a href="#a-note-on-selection-of-priors">A note on selection of priors&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#dose-1">Dose 1&lt;/a>
&lt;ul>
&lt;li>
&lt;a href="#prior-predictive-check-for-model-on-dose-1-data">Prior Predictive Check for Model on Dose 1 Data&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#posterior-predictive-check-for-model-on-dose-1-data">Posterior Predictive Check for Model on Dose 1 Data&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#leave-one-out-cross-validation-for-dose-1">Leave one out cross validation for dose 1&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;a href="#dose-2">Dose 2&lt;/a>
&lt;ul>
&lt;li>
&lt;a href="#prior-predictive-check-for-model-on-dose-2-data">Prior Predictive Check for Model on Dose 2 Data&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#posterior-predictive-check-for-model-on-dose-2-data">Posterior Predictive Check for Model on Dose 2 Data&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#leave-one-out-cross-validation-for-dose-2">Leave one out cross validation for dose 2&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;a href="#dose-3">Dose 3&lt;/a>
&lt;ul>
&lt;li>
&lt;a href="#prior-predictive-check-for-model-on-dose-3-data">Prior Predictive Check for Model on Dose 3 Data&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#posterior-predictive-check-for-model-on-dose-3-data">Posterior Predictive Check for Model on Dose 3 Data&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#leave-one-out-cross-validation-for-dose-3">Leave one out cross validation for dose 3&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;a href="#dose-4">Dose 4&lt;/a>
&lt;ul>
&lt;li>
&lt;a href="#prior-predictive-check-for-model-on-dose-4-data">Prior Predictive Check for Model on Dose 4 Data&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#posterior-predictive-check-for-model-on-dose-4-data">Posterior Predictive Check for Model on Dose 4 Data&lt;/a>&lt;/li>
&lt;li>
&lt;a href="#leave-one-out-cross-validation-for-dose-4">Leave one out cross validation for dose 4&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;a href="#remarks">Remarks&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;a href="#task-3">Task 3&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="task-1">Task 1&lt;/h2>
&lt;p>We have
$$ \frac{dE}{dt} = 0.004 - 2 E(t) - \kappa_1C(t) E(t) $$
$$ \frac{dC}{dt} = P \kappa_2 I(t) - \mu C(t) - \kappa_1 C(t) E(t) $$
$$ \frac{dI}{dt} = \kappa_1 C(t) E(t) - \gamma I(t) - \kappa_2 I(t) $$&lt;/p>
&lt;p>The following codes load the data. Note that dose 1 to dose 4 correspond to dose 10 to 10&lt;sup>4&lt;/sup>.&lt;/p>
&lt;pre>&lt;code>data = readRDS(&amp;quot;rank_et_al_2003_data.RDS&amp;quot;)
dose1 &amp;lt;- data[1:10,]
dose2 &amp;lt;- data[11:20,]
dose3 &amp;lt;- data[21:30,]
dose4 &amp;lt;- data[31:40,]
dose5 &amp;lt;- data[41:50,]
&lt;/code>&lt;/pre>
&lt;p>The following codes examine whether the model is written correctly.&lt;/p>
&lt;pre>&lt;code>model &amp;lt;- function (t, y, parms) {
dy1 &amp;lt;- (40 * 10 ^ (-4)) - 2 * y[1] - params[1] * y[2] * y[1]
dy2 &amp;lt;- params[2] * params[3] * y[3] - params[4] * y[2] - params[1] * y[2] * y[1]
dy3 &amp;lt;- params[1] * y[2] * y[1] - params[5] * y[3] - params[3] * y[3]
list(c(dy1, dy2, dy3))
}
yini &amp;lt;- c(E = 0.96, C = 0.001, I = 0)
params &amp;lt;- c(
kappa1 = 1000,
P = 1000,
kappa2 = 1.3, #0.4-1.3
C = 1.2,
gamma = 1.2
)
out &amp;lt;- ode(y=yini, t=seq(0,30,0.1), model, parameters)
df_out &amp;lt;- as.data.frame(out)
# An estimate of the differential equations
summary(df_out$C)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.001 1.728 1.728 15.164 1.832 248.361
# An overview of the data
head(data)
## t C dose number
## 1 3 0.000 10^1 2
## 2 6 46.829 10^1 2
## 3 9 9.106 10^1 2
## 4 12 18.862 10^1 2
## 5 15 25.366 10^1 2
## 6 18 21.463 10^1 2
&lt;/code>&lt;/pre>
&lt;p>The following codes are for r2.stan (model from the differential equations.)&lt;/p>
&lt;pre>&lt;code>functions {
vector rhs(real t, vector y,
real P, real kappa1, real kappa2, real gamma, real mu) {
vector[3] dydt;
dydt[1] = (40 * 1e-4) - 2 * y[1] - kappa1 * y[2] * y[1];
dydt[2] = P * kappa2 * y[3] - mu * y[2] - kappa1 * y[2] * y[1];
dydt[3] = kappa1 * y[2] * y[1] - gamma * y[3] - kappa2 * y[3];
return dydt;
}
}
data {
int&amp;lt;lower=0&amp;gt; N;
vector [N] y;
real t[N]; // This must be an array!
// Control
int&amp;lt;lower=0, upper = 1&amp;gt; only_prior;
}
parameters {
real&amp;lt;lower = 0, upper = 2000&amp;gt; P;
real&amp;lt;lower = 0, upper = 2000&amp;gt; kappa1;
real&amp;lt;lower = 0.01, upper = 1.5&amp;gt; kappa2;
real&amp;lt;lower = 0.01, upper = 1.5&amp;gt; gamma;
real&amp;lt;lower = 0.01, upper = 1.5&amp;gt; mu;
real&amp;lt;lower = 0&amp;gt; c;
}
transformed parameters {
// [a, b] makes a row_vector, [a, b]' makes a column vector
// 0 is an int! 0.0 is a real!
vector[N] C; // Outputted
{ // Local computation - isn't saved or outputted!
vector[3] solution[N] = ode_bdf(rhs, [0.96, c, 0.0]', 0, t, P, kappa1, kappa2, gamma, mu);
for(i in 1:N){
C[i] = solution[i,2];
}
}
}
model{
c ~ uniform(0,1)
P ~ uniform(0, 2000);
kappa1 ~ uniform(0, 2000);
kappa2 ~ uniform(0.01, 1.5);
gamma ~ uniform(0.01, 1.5);
mu ~ uniform(0.01, 1.5);
if(only_prior == 0) {
y ~ normal(C, 50);
}
}
generated quantities {
vector&amp;lt;lower=0&amp;gt;[N] y_pred;
vector&amp;lt;lower=0&amp;gt;[N] log_lik;
for (i in 1:N) {
y_pred[i] = abs(normal_rng(C[i], 50)); // abs because minnimum is 0 and 30 is chosen because the standard deviation of the dataset is around 50,
// that is, if we are only interested in values larger than zero, then
log_lik[i] = abs(normal_lpdf(y[i] | C[i], 50));
}
}
&lt;/code>&lt;/pre>
&lt;p>Since when 0.4 &amp;lt; &lt;em>κ&lt;/em>&lt;sub>2&lt;/sub> &amp;lt; 1.4, the max of C(t) is between 100 &amp;lt; &lt;em>C&lt;/em>(&lt;em>t&lt;/em>) &amp;lt; 250 as 0.01 &amp;lt; &lt;em>C&lt;/em>(0) &amp;lt; 1. Hence we may assume that the mean of &lt;em>κ&lt;/em>&lt;sub>2&lt;/sub> is 0.9 and the standard deviation of it is 0.3 so that it is highly probable to take values in the range of $[0.3,1.5]$. A uniform distribution is used because we do not know the exact distribution and it is hard to estimate the standard deviation of each parameter.&lt;/p>
&lt;p>Therefore, we assume a weakly informative prior for other parameters in stan as well. In particular, uniform distribution that covers the value given as an example. This is largely due to two reasons. First, most parameters that require priors do not have sufficient information for us to set up a good distribution. Furthermore, since there are five different doses in the dataset, a distribution that can take values in a large range is preferred. As you will see later on, this choice provides a fair estimate of the parameters.&lt;/p>
&lt;p>We assume the parameters in the 10&lt;sup>3&lt;/sup> scale to be from 0 to 2000. The lower bound 0 is pretty self-explanatory, the upper bound is taken by 1000 + (1000 - lower bound). Similarly, we take 1.5 as upper bound for other parameters because of the range of &lt;em>κ&lt;/em>&lt;sub>2&lt;/sub>.&lt;/p>
&lt;p>To estimate the rate of change of C at t = 0, we use the data for average C on day 3 and then divided by 3 (3 days) for each dose. This assumes that the rate of C is increasing so that C(0) is not underestimated, which is reasonable given that C increases until the dose takes effect. However, this could have some limitations. Hence we will further address this issue in task 3. C(0) will therefore be an average of all estimates of C(0) from 5 doses.&lt;/p>
&lt;pre>&lt;code>mod &amp;lt;- cmdstan_model(&amp;quot;r2.stan&amp;quot;)
&lt;/code>&lt;/pre>
&lt;h2 id="task-2">Task 2&lt;/h2>
&lt;h3 id="a-note-on-selection-of-priors">A note on selection of priors&lt;/h3>
&lt;p>I have attempted different range of values for the uniform distribution, however, the posterior predictive check shows that the noise is higher than expected and the model does not fit very well. I have tried different models including normal distribution and uniform distribution with other parameters, but the actual result is not better than this. Hence uniform distribution is used. However, I would still suggest future researchers to collect more data (1 data per day) or apply other models specifically for this question.&lt;/p>
&lt;h3 id="dose-1">Dose 1&lt;/h3>
&lt;h4 id="prior-predictive-check-for-model-on-dose-1-data">Prior Predictive Check for Model on Dose 1 Data&lt;/h4>
&lt;pre>&lt;code>mcmc_hist(fit$draws(&amp;quot;C&amp;quot;))
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="dose1-prior-predictive-check-1.png" alt="">&lt;/p>
&lt;pre>&lt;code>mcmc_hist(fit$draws(&amp;quot;y_pred&amp;quot;))
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="dose1-prior-predictive-check-2.png" alt="">&lt;/p>
&lt;h4 id="posterior-predictive-check-for-model-on-dose-1-data">Posterior Predictive Check for Model on Dose 1 Data&lt;/h4>
&lt;pre>&lt;code>yrep = fit$draws() %&amp;gt;% reshape2::melt() %&amp;gt;% filter(str_detect(variable, &amp;quot;y_pred&amp;quot;)) %&amp;gt;%
extract(col = variable, into = &amp;quot;ind&amp;quot;,
regex = &amp;quot;y_pred\\[([0-9]*)\\]&amp;quot;,
convert = TRUE) %&amp;gt;%
pivot_wider(id_cols = c(&amp;quot;chain&amp;quot;,&amp;quot;iteration&amp;quot;),
names_from = &amp;quot;ind&amp;quot;) %&amp;gt;%
select(-c(&amp;quot;chain&amp;quot;, &amp;quot;iteration&amp;quot;)) %&amp;gt;% as.matrix
ppc_stat(dose1$C, yrep, stat = &amp;quot;min&amp;quot;)
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="dose1-posterior-predictive-check-1.png" alt="">&lt;/p>
&lt;h4 id="leave-one-out-cross-validation-for-dose-1">Leave one out cross validation for dose 1&lt;/h4>
&lt;pre>&lt;code>## By default, it looks for something called &amp;quot;log_lik&amp;quot;, but you can override this
## with the variables = argument. Eg if you called your log-likelihood &amp;quot;ll&amp;quot;,
## you could run loo1 &amp;lt;- fit$loo(save_psis=TRUE, variable = &amp;quot;ll&amp;quot;)
loo1 &amp;lt;- fit$loo(save_psis=TRUE)
print(loo1)
##
## Computed from 4000 by 10 log-likelihood matrix
##
## Estimate SE
## elpd_loo 49.1 0.4
## p_loo 0.3 0.3
## looic -98.3 0.7
## ------
## Monte Carlo SE of elpd_loo is NA.
##
## Pareto k diagnostic values:
## Count Pct. Min. n_eff
## (-Inf, 0.5] (good) 6 60.0% 2223
## (0.5, 0.7] (ok) 0 0.0% &amp;lt;NA&amp;gt;
## (0.7, 1] (bad) 0 0.0% &amp;lt;NA&amp;gt;
## (1, Inf) (very bad) 4 40.0% 2420
## See help('pareto-k-diagnostic') for details.
plot(loo1)
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="loo1-1.png" alt="">&lt;/p>
&lt;p>All except five of our points are good from the leave one out cross validation for model. This is not very great, but we may take a look at the estimate of C(0) to determine if we really identify C(0) fairly.&lt;/p>
&lt;h3 id="dose-2">Dose 2&lt;/h3>
&lt;h4 id="prior-predictive-check-for-model-on-dose-2-data">Prior Predictive Check for Model on Dose 2 Data&lt;/h4>
&lt;pre>&lt;code>mcmc_hist(fit2$draws(&amp;quot;C&amp;quot;))
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="dose2-prior-predictive-check-1.png" alt="">&lt;/p>
&lt;pre>&lt;code>mcmc_hist(fit2$draws(&amp;quot;y_pred&amp;quot;))
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="dose2-prior-predictive-check-2.png" alt="">&lt;/p>
&lt;h4 id="posterior-predictive-check-for-model-on-dose-2-data">Posterior Predictive Check for Model on Dose 2 Data&lt;/h4>
&lt;pre>&lt;code>yrep2 = fit2$draws() %&amp;gt;% reshape2::melt() %&amp;gt;% filter(str_detect(variable, &amp;quot;y_pred&amp;quot;)) %&amp;gt;%
extract(col = variable, into = &amp;quot;ind&amp;quot;,
regex = &amp;quot;y_pred\\[([0-9]*)\\]&amp;quot;,
convert = TRUE) %&amp;gt;%
pivot_wider(id_cols = c(&amp;quot;chain&amp;quot;,&amp;quot;iteration&amp;quot;),
names_from = &amp;quot;ind&amp;quot;) %&amp;gt;%
select(-c(&amp;quot;chain&amp;quot;, &amp;quot;iteration&amp;quot;)) %&amp;gt;% as.matrix
ppc_stat(dose2$C, yrep2, stat = &amp;quot;min&amp;quot;)
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="dose2-posterior-predictive-check-1.png" alt="">&lt;/p>
&lt;h4 id="leave-one-out-cross-validation-for-dose-2">Leave one out cross validation for dose 2&lt;/h4>
&lt;pre>&lt;code>loo2 &amp;lt;- fit2$loo(save_psis=TRUE)
print(loo2)
##
## Computed from 4000 by 10 log-likelihood matrix
##
## Estimate SE
## elpd_loo 49.7 0.7
## p_loo 0.5 0.4
## looic -99.4 1.4
## ------
## Monte Carlo SE of elpd_loo is NA.
##
## Pareto k diagnostic values:
## Count Pct. Min. n_eff
## (-Inf, 0.5] (good) 6 60.0% 2138
## (0.5, 0.7] (ok) 0 0.0% &amp;lt;NA&amp;gt;
## (0.7, 1] (bad) 0 0.0% &amp;lt;NA&amp;gt;
## (1, Inf) (very bad) 4 40.0% 1931
## See help('pareto-k-diagnostic') for details.
plot(loo2)
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="loo2-1.png" alt="">&lt;/p>
&lt;h3 id="dose-3">Dose 3&lt;/h3>
&lt;h4 id="prior-predictive-check-for-model-on-dose-3-data">Prior Predictive Check for Model on Dose 3 Data&lt;/h4>
&lt;pre>&lt;code>mcmc_hist(fit3$draws(&amp;quot;C&amp;quot;))
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="dose3-prior-predictive-check-1.png" alt="">&lt;/p>
&lt;pre>&lt;code>mcmc_hist(fit3$draws(&amp;quot;y_pred&amp;quot;))
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="dose3-prior-predictive-check-2.png" alt="">&lt;/p>
&lt;h4 id="posterior-predictive-check-for-model-on-dose-3-data">Posterior Predictive Check for Model on Dose 3 Data&lt;/h4>
&lt;pre>&lt;code>yrep3 = fit3$draws() %&amp;gt;% reshape2::melt() %&amp;gt;% filter(str_detect(variable, &amp;quot;y_pred&amp;quot;)) %&amp;gt;%
extract(col = variable, into = &amp;quot;ind&amp;quot;,
regex = &amp;quot;y_pred\\[([0-9]*)\\]&amp;quot;,
convert = TRUE) %&amp;gt;%
pivot_wider(id_cols = c(&amp;quot;chain&amp;quot;,&amp;quot;iteration&amp;quot;),
names_from = &amp;quot;ind&amp;quot;) %&amp;gt;%
select(-c(&amp;quot;chain&amp;quot;, &amp;quot;iteration&amp;quot;)) %&amp;gt;% as.matrix
ppc_stat(dose3$C, yrep3, stat = &amp;quot;min&amp;quot;)
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="dose3-posterior-predictive-check-1.png" alt="">&lt;/p>
&lt;h4 id="leave-one-out-cross-validation-for-dose-3">Leave one out cross validation for dose 3&lt;/h4>
&lt;pre>&lt;code>loo3 &amp;lt;- fit3$loo(save_psis=TRUE)
print(loo3)
##
## Computed from 4000 by 10 log-likelihood matrix
##
## Estimate SE
## elpd_loo 51.0 1.3
## p_loo 3.7 2.1
## looic -101.9 2.5
## ------
## Monte Carlo SE of elpd_loo is 0.0.
##
## All Pareto k estimates are good (k &amp;lt; 0.5).
## See help('pareto-k-diagnostic') for details.
plot(loo3)
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="loo3-1.png" alt="">&lt;/p>
&lt;h3 id="dose-4">Dose 4&lt;/h3>
&lt;h4 id="prior-predictive-check-for-model-on-dose-4-data">Prior Predictive Check for Model on Dose 4 Data&lt;/h4>
&lt;pre>&lt;code>mcmc_hist(fit4$draws(&amp;quot;C&amp;quot;))
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="dose4-prior-predictive-check-1.png" alt="">&lt;/p>
&lt;pre>&lt;code>mcmc_hist(fit4$draws(&amp;quot;y_pred&amp;quot;))
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="dose4-prior-predictive-check-2.png" alt="">&lt;/p>
&lt;h4 id="posterior-predictive-check-for-model-on-dose-4-data">Posterior Predictive Check for Model on Dose 4 Data&lt;/h4>
&lt;pre>&lt;code>yrep4 = fit4$draws() %&amp;gt;% reshape2::melt() %&amp;gt;% filter(str_detect(variable, &amp;quot;y_pred&amp;quot;)) %&amp;gt;%
extract(col = variable, into = &amp;quot;ind&amp;quot;,
regex = &amp;quot;y_pred\\[([0-9]*)\\]&amp;quot;,
convert = TRUE) %&amp;gt;%
pivot_wider(id_cols = c(&amp;quot;chain&amp;quot;,&amp;quot;iteration&amp;quot;),
names_from = &amp;quot;ind&amp;quot;) %&amp;gt;%
select(-c(&amp;quot;chain&amp;quot;, &amp;quot;iteration&amp;quot;)) %&amp;gt;% as.matrix
ppc_stat(dose4$C, yrep4, stat = &amp;quot;min&amp;quot;)
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="dose4-posterior-predictive-check-1.png" alt="">&lt;/p>
&lt;h4 id="leave-one-out-cross-validation-for-dose-4">Leave one out cross validation for dose 4&lt;/h4>
&lt;pre>&lt;code>loo4 &amp;lt;- fit4$loo(save_psis=TRUE)
print(loo4)
##
## Computed from 4000 by 10 log-likelihood matrix
##
## Estimate SE
## elpd_loo 52.5 2.9
## p_loo 3.3 2.2
## looic -105.0 5.9
## ------
## Monte Carlo SE of elpd_loo is 0.0.
##
## All Pareto k estimates are good (k &amp;lt; 0.5).
## See help('pareto-k-diagnostic') for details.
plot(loo4)
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="loo4-1.png" alt="">&lt;/p>
&lt;h3 id="remarks">Remarks&lt;/h3>
&lt;p>From the prior predictive check, we can see the estimated distribution is more heavy-tailed than the actual distribution. From the posterior predictive check, T(y) is the skewness. The model captures the observed statistic to some extent for 4 doses, but leave one out cross validation shows that the model fits the the data for dose 3 and 4 better as all points from dose 3 and 4 are good.&lt;/p>
&lt;h2 id="task-3">Task 3&lt;/h2>
&lt;pre>&lt;code>vec_c0 &amp;lt;- unlist(c0_estimate)
hist(vec_c0, breaks=20)
&lt;/code>&lt;/pre>
&lt;p>&lt;img src="unnamed-chunk-2-1.png" alt="">
The advantage about estimating C(0) here is that this approach uses all available data and keep the statistical power of all data, since we are conditioning on all data; however, it takes a long time to produce the results. For instance, a laptop with one core will need more than an hour for this task.&lt;/p></description></item></channel></rss>