{"id":723,"date":"2015-07-03T08:11:07","date_gmt":"2015-07-03T08:11:07","guid":{"rendered":"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/?p=723"},"modified":"2025-02-26T13:21:37","modified_gmt":"2025-02-26T13:21:37","slug":"stan-vs-openbugs-controlled-from-stata","status":"publish","type":"post","link":"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/2015\/07\/03\/stan-vs-openbugs-controlled-from-stata\/","title":{"rendered":"Stan vs OpenBUGS (controlled from Stata)"},"content":{"rendered":"<p>A rather long posting this week for which I apologise. I would have split this\u00a0posting over two weeks but I am about to go on my summer holiday and I wanted\u00a0to avoid a long gap between the two halves.<\/p>\n<p>I have spent\u00a0the last few\u00a0weeks discussing how <strong>Stan<\/strong> can be called from <strong>Stata<\/strong> and now the time has come to test the process with a realistic problem. To create a\u00a0comparison, I thought that I would take a problem that is challenging for OpenBUGS and see whether Stan offers any advantages. In the spirit of this blog, the question ought to be,<br \/>\n<strong>\u00a0\u00a0\u00a0 is it as easy to run Stan from Stata, as it is to run OpenBUGS from Stata?<\/strong><br \/>\nbut the answer to that question is clearly, yes, so inevitably we will get drawn into the issue,<br \/>\n<strong>is Stan\u00a0as good as\u00a0OpenBUGS?<\/strong><\/p>\n<p>For my test problem I have chosen a network meta-analysis as described in,<\/p>\n<p style=\"padding-left: 60px\">White I.R., Barrett J.K., Jackson D, Higgins J.P.T.<br \/>\n<strong>Consistency and inconsistency in network meta-analysis: model estimation using multivariate meta-regression<\/strong><br \/>\n<em>Research Synthesis Methods<\/em> 2012;3:111-125<\/p>\n<p>In that paper the authors\u00a0present the data for a worked example and give the WinBUGS code for fitting their model; so much of my work is done for me.\u00a0What is more,\u00a0their analysis was performed with three chains, each with a burn-in of 30,000 and a run length of 150,000 so the model is clearly challenging enough to make a good test.<\/p>\n<p>I\u2019ve blogged about network meta-analysis before <a href=\"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/2014\/07\/18\/network-meta-analysis-in-stata\/\">here<\/a> and <a href=\"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/2014\/07\/25\/network-meta-analysis-with-winbugs-and-stata\/\">here<\/a>. I have to admit to having some doubts about its usefulness\u00a0but I was impressed that\u00a0the paper by White et al. addresses one of\u00a0my main concerns, how\u00a0do we detect\u00a0when\u00a0a network meta-analysis is inconsistent?<\/p>\n<p>The example used in the paper\u00a0is a meta-analysis of\u00a028 trials of drug treatments given to people who had had a heart attack. The outcome was the number of deaths in the first month after treatment. 8 different drugs were compared in the trials but the designs varied; for instance,\u00a0some compared streptokinase with alteplase, some compared streptokinase with urokinase, yet others compared alteplase with urokinase and so on.<\/p>\n<p>Well, if streptokinase is better than alteplase by one unit on some outcome scale and alteplase is better than urokinase by one unit on the same scale, then streptokinase\u00a0ought to\u00a0be better than urokinase by two units. If this is so, then the data are said to be consistent. It is possible however that the streptokinase-urokinase trials were different in some systematic way, perhaps they were conducted more recently or they all come from the USA.\u00a0If they do differ systematically then\u00a0the directly measured effect\u00a0may not be consistent with the indirectly implied effect. White et al. refer to the set of treatments compared in a study as the \u2018design\u2019 and handle inconsistency by treating it as an interaction between the treatment effect and the design.<\/p>\n<p>There is much more to the model that they propose but I do not think that it is necessary for us to understand all of the details as our primary interest is in seeing if Stan can handle it.<\/p>\n<p>Let\u2019s first fit the model with design by treatment interaction using OpenBUGS and the code provided in White et al. I have removed a few lines from White et al.&#8217;s program that calculate derived quantities that are not essential for the estimation. The data, taken from Table 1 of the paper, are in a file called <strong>thrombolytic.dta<\/strong> that is available from my webpage along with all of the\u00a0Stata code .<\/p>\n<p>Here is the full Stata program.<\/p>\n<p><span style=\"color: #0000ff\">use &#8220;thrombolytic.dta&#8221;, clear<\/span><br \/>\n<span style=\"color: #339966\"> * Number of treatments in each study<\/span><br \/>\n<span style=\"color: #0000ff\"> sort study<\/span><br \/>\n<span style=\"color: #0000ff\"> by study: egen nt = count(trt&gt;0)<\/span><br \/>\n<span style=\"color: #339966\"> * offsets &#8211; row numbers for start of each study or design<\/span><br \/>\n<span style=\"color: #0000ff\"> sort design study trt<\/span><br \/>\n<span style=\"color: #0000ff\"> gen os = _n*(study != study[_n-1])<\/span><br \/>\n<span style=\"color: #0000ff\"> gen os_design = _n*(design != design[_n-1])<\/span><br \/>\n<span style=\"color: #0000ff\"> by design: egen b = min(trt)<\/span><br \/>\n<span style=\"color: #0000ff\"> replace os = 59 in 58<\/span><br \/>\n<span style=\"color: #339966\"> * Write data to file<\/span><br \/>\n<span style=\"color: #0000ff\"> wbslist (vect study design trt b r n, format(%5.0f) name(study d t b r n) ) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\">\u00a0\u00a0 (vect os if os != 0 , format(%5.0f) name(offset) ) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\">\u00a0\u00a0 (vect os_design nt if os_design != 0 , format(%5.0f) name(offset.design num.ests) ) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\">\u00a0\u00a0 (zero=c(7{0})) (A=58, S=28, T=8, D=13) using data.txt, replace<\/span><br \/>\n<span style=\"color: #339966\"> * Prepare three sets of starting values for 3 chains<\/span><br \/>\n<span style=\"color: #0000ff\"> matrix RE = J(28,8,0)<\/span><br \/>\n<span style=\"color: #0000ff\"> forvalues i=1\/28 {<\/span><br \/>\n<span style=\"color: #0000ff\">\u00a0\u00a0 matrix RE[`i&#8217;,1] = .<\/span><br \/>\n<span style=\"color: #0000ff\"> }<\/span><br \/>\n<span style=\"color: #0000ff\"> wbslist (matrix RE , format(%5.0f) )\u00a0<\/span><span style=\"color: #0000ff\">\u00a0( mu=c(28{-1}) ) <\/span><span style=\"color: #0000ff\">( tau=0.2) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\">\u00a0\u00a0\u00a0 using init1.txt, replace<\/span><br \/>\n<span style=\"color: #0000ff\"> wbslist (matrix RE , format(%5.0f) ) <\/span><span style=\"color: #0000ff\">( mu=c(28{-2}) ) <\/span><span style=\"color: #0000ff\">( tau=1) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\">\u00a0\u00a0\u00a0 using init2.txt, replace<\/span><br \/>\n<span style=\"color: #0000ff\"> wbslist (matrix RE , format(%5.0f) ) <\/span><span style=\"color: #0000ff\">( mu=c(28{-1.5}) ) <\/span><span style=\"color: #0000ff\">( tau=0.5) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\">\u00a0\u00a0\u00a0 using init3.txt, replace<\/span><br \/>\n<span style=\"color: #339966\"> * Write the model<\/span><br \/>\n<span style=\"color: #0000ff\"> wbsmodel thrombo_bayes.do model.txt<\/span><br \/>\n<span style=\"color: #339966\"> \/*<\/span><br \/>\n<span style=\"color: #339966\"> model {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 for(i in 1:S) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0 eff.study[i, b[offset[i]], b[offset[i]]] &lt;- 0<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0 for(k in (offset[i] + 1):(offset[i + 1]-1)) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 eff.study[i,t[k],b[k]] &lt;- eff.des[d[k],t[k]] + RE[i,t[k]] &#8211; RE[i,b[k]]<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\"> # Random effects for heterogeneity<\/span><br \/>\n<span style=\"color: #339966\"> for(i in 1:S) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 RE[i,1] &lt;- 0<\/span><br \/>\n<span style=\"color: #339966\"> RE[i,2:T] ~ dmnorm(zero[], Prec[,])<\/span><br \/>\n<span style=\"color: #339966\"> }<\/span><br \/>\n<span style=\"color: #339966\"> # Prec is the inverse of the structured heterogeneity matrix<\/span><br \/>\n<span style=\"color: #339966\"> for(i in 1:(T-1)) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 for(j in 1:(T-1)){<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0 Prec[i,j] &lt;- 2*(equals(i,j)-1\/T)\/(tau*tau)<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\"> }<\/span><br \/>\n<span style=\"color: #339966\"> for(i in 1:A) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 logit(p[i]) &lt;- mu[study[i]] + eff.study[study[i],t[i],b[i]]<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 r[i] ~ dbin(p[i],n[i])<\/span><br \/>\n<span style=\"color: #339966\"> }<\/span><br \/>\n<span style=\"color: #339966\"> # Priors<\/span><br \/>\n<span style=\"color: #339966\"> for(i in 1:S) {<\/span><br \/>\n<span style=\"color: #339966\"> mu[i] ~ dnorm(0,0.01)<\/span><br \/>\n<span style=\"color: #339966\"> }<\/span><br \/>\n<span style=\"color: #339966\"> tau ~ dunif(0,2)<\/span><br \/>\n<span style=\"color: #339966\"> for(i in 1:D) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 for(k in (offset.design[i] + 1):(offset.design[i] + num.ests[i])) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0 eff.des[i,t[k]] ~ dnorm(0,0.01)<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\"> }<\/span><br \/>\n<span style=\"color: #339966\"> }<\/span><br \/>\n<span style=\"color: #339966\"> *\/<\/span><br \/>\n<span style=\"color: #339966\"> * Prepare the script<\/span><br \/>\n<span style=\"color: #0000ff\"> wbsscript using script.txt , replace openbugs \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\">\u00a0\u00a0 model(model.txt) data(data.txt) init(init1.txt+init2.txt+init3.txt) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\">\u00a0\u00a0 set(tau eff.des RE mu) burn(30000) update(150000) thin(20) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\">\u00a0\u00a0 log(openlog.txt) coda(thromb)<\/span><br \/>\n<span style=\"color: #339966\"> * Run the analysis<\/span><br \/>\n<span style=\"color: #0000ff\"> wbsrun using script.txt , openbugs<\/span><br \/>\n<span style=\"color: #339966\"> * check the log file<\/span><br \/>\n<span style=\"color: #0000ff\"> type openlog.txt<\/span><br \/>\n<span style=\"color: #339966\"> * read results and store<\/span><br \/>\n<span style=\"color: #0000ff\"> wbscoda using thromb , openbugs clear chains(1 2 3)<\/span><br \/>\n<span style=\"color: #0000ff\"> save thrombmcmc123.dta, replace<\/span><br \/>\n<span style=\"color: #339966\"> * calculate the interaction terms<\/span><br \/>\n<span style=\"color: #0000ff\"> gen w1 = eff_des_3_3 &#8211; eff_des_2_3 \/\/ wAC3<\/span><br \/>\n<span style=\"color: #0000ff\"> gen w2 = eff_des_4_4 &#8211; eff_des_1_4 \/\/ wAD4<\/span><br \/>\n<span style=\"color: #0000ff\"> gen w3 = eff_des_9_6 &#8211; eff_des_5_6 + eff_des_1_2 \/\/ wAF9<\/span><br \/>\n<span style=\"color: #0000ff\"> gen w4 = eff_des_10_7 &#8211; eff_des_6_7 + eff_des_1_2 \/\/ wAG10<\/span><br \/>\n<span style=\"color: #0000ff\"> gen w5 = eff_des_12_7 &#8211; eff_des_6_7 + eff_des_2_3 \/\/ wAG12<\/span><br \/>\n<span style=\"color: #0000ff\"> gen w6 = eff_des_7_8 &#8211; eff_des_2_8 \/\/ wAH7<\/span><br \/>\n<span style=\"color: #0000ff\"> gen w7 = eff_des_11_8 &#8211; eff_des_2_8 + eff_des_1_2 \/\/ wAH11<\/span><br \/>\n<span style=\"color: #0000ff\"> gen w8 = eff_des_13_8 &#8211; eff_des_2_8 + eff_des_2_3 \/\/ wAH13<\/span><br \/>\n<span style=\"color: #0000ff\"> gen dAE = eff_des_8_5 + eff_des_1_2<\/span><br \/>\n<span style=\"color: #339966\"> * various convergence checks<\/span><br \/>\n<span style=\"color: #0000ff\"> mcmctrace w1 w3 w5 w7 , gopt( xline(7500) xline(15000) yscale(range(-4 6)) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\">\u00a0\u00a0 ylabel(-4(2)6) xscale(range(0 22500)) xlabel(0(5000)20000) )<\/span><br \/>\n<span style=\"color: #0000ff\"> mcmcstats_v2 w* , newey(200)<\/span><br \/>\n<span style=\"color: #0000ff\"> gen w7_1 = w7 if chain == 1<\/span><br \/>\n<span style=\"color: #0000ff\"> gen w7_2 = w7 if chain == 2<\/span><br \/>\n<span style=\"color: #0000ff\"> gen w7_3 = w7 if chain == 3<\/span><br \/>\n<span style=\"color: #0000ff\"> mcmcac w7_1 w7_2 w7_3 , gopt(yscale(range(0 0.5)) <\/span><span style=\"color: #0000ff\">ylabel(0(0.2)0.4) ) acopt(lag(50))<\/span><\/p>\n<p>Here we have 3 chains each with a burnin of 30,000 and a run length of 150,000 which makes 540,000 iterations. On my laptop, OpenBUGS took about 1s for 1000 updates so that the entire run took about 9 minutes. Here are the results for the interaction terms based on the combined chains. The results are very similar to those given in the paper and the only interaction that is clearly non-zero is w7<\/p>\n<pre>----------------------------------------------------------------------------\r\nParameter\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 n\u00a0\u00a0\u00a0\u00a0 mean\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sd\u00a0\u00a0\u00a0\u00a0 sem\u00a0\u00a0 median\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 95% CrI\r\n----------------------------------------------------------------------------\r\nw1\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 22500\u00a0\u00a0 -0.165\u00a0\u00a0 0.366\u00a0\u00a0 0.0111\u00a0\u00a0 -0.103 ( -1.038,\u00a0\u00a0 0.452 )\r\nw2\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 22500\u00a0\u00a0  0.479\u00a0\u00a0 0.808\u00a0\u00a0 0.0085\u00a0\u00a0  0.470 ( -1.101,\u00a0\u00a0 2.092 )\r\nw3\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 22500\u00a0\u00a0 -0.193\u00a0\u00a0 0.504\u00a0\u00a0 0.0103\u00a0\u00a0 -0.158 ( -1.300,\u00a0\u00a0 0.775 )\r\nw4\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 22500\u00a0\u00a0  0.387\u00a0\u00a0 0.791\u00a0\u00a0 0.0091\u00a0\u00a0  0.374 ( -1.136,\u00a0\u00a0 1.992 )\r\nw5\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 22500\u00a0\u00a0  0.034\u00a0\u00a0 0.762\u00a0\u00a0 0.0107\u00a0\u00a0  0.034 ( -1.490,\u00a0\u00a0 1.545 )\r\nw6\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 22500\u00a0\u00a0 -0.049\u00a0\u00a0 0.468\u00a0\u00a0 0.0095\u00a0\u00a0 -0.050 ( -0.991,\u00a0\u00a0 0.896 )\r\nw7\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 22500\u00a0\u00a0  1.263\u00a0\u00a0 0.634\u00a0\u00a0 0.0138\u00a0\u00a0  1.247 (\u00a0\u00a00.049,\u00a0\u00a0 2.561 )\r\nw8\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 22500\u00a0\u00a0 -0.321\u00a0\u00a0 0.505\u00a0\u00a0 0.0064\u00a0\u00a0 -0.319 ( -1.330,\u00a0\u00a0 0.674 )\r\n----------------------------------------------------------------------------<\/pre>\n<p>To inspect the mixing I looked at some trace plots. As usual they are not\u00a0particularly informative. The vertical lines\u00a0separate the three chains.<\/p>\n<p><a href=\"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/files\/2015\/06\/nw_trace1-e1435326096430.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-731\" src=\"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/files\/2015\/06\/nw_trace1-e1435326096430.png\" alt=\"nw_trace1\" width=\"600\" height=\"439\" \/><\/a><\/p>\n<p>So next I checked the Brooks-Gelman-Rubin plots. Here is the plot for w7.<\/p>\n<p><a href=\"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/files\/2015\/06\/nw_bgr1-e1435326248655.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-732\" src=\"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/files\/2015\/06\/nw_bgr1-e1435326248655.png\" alt=\"nw_bgr1\" width=\"600\" height=\"439\" \/><\/a><\/p>\n<p>This plot compares the within chain variability to the variability of the pooled chains, R being the ratio of the two. Ideally R should be 1.0. Perhaps the first 1,000 thinned iterations have not quite settled, which would argue for a slightly longer burnin or better starting values.<\/p>\n<p>To check this I ran\u00a0a version of the Geweke test as implemented in <strong>mcmcgeweke<\/strong>. This compares w7 as calculated from the first 10% of each chain with the value from the final 50%. Not only is there\u00a0 evidence of drift, but the three estimates from the second halves of the chains are still subject to quite a lot of sampling error.<\/p>\n<table>\n<tbody>\n<tr>\n<td width=\"98\"><\/td>\n<td width=\"98\">First 10%<\/td>\n<td width=\"98\"><\/td>\n<td width=\"98\">Last 50%<\/td>\n<td width=\"98\"><\/td>\n<td width=\"98\"><\/td>\n<\/tr>\n<tr>\n<td width=\"98\"><\/td>\n<td width=\"98\">Mean<\/td>\n<td width=\"98\">St Error<\/td>\n<td width=\"98\">Mean<\/td>\n<td width=\"98\">St Error<\/td>\n<td width=\"98\">p-value<\/td>\n<\/tr>\n<tr>\n<td width=\"98\">Chain 1<\/td>\n<td width=\"98\">1.342<\/td>\n<td width=\"98\">0.051<\/td>\n<td width=\"98\">1.249<\/td>\n<td width=\"98\">0.014<\/td>\n<td width=\"98\">0.080<\/td>\n<\/tr>\n<tr>\n<td width=\"98\">Chain 2<\/td>\n<td width=\"98\">1.149<\/td>\n<td width=\"98\">0.028<\/td>\n<td width=\"98\">1.267<\/td>\n<td width=\"98\">0.014<\/td>\n<td width=\"98\">0.0001<\/td>\n<\/tr>\n<tr>\n<td width=\"98\">Chain 3<\/td>\n<td width=\"98\">1.159<\/td>\n<td width=\"98\">0.037<\/td>\n<td width=\"98\">1.322<\/td>\n<td width=\"98\">0.022<\/td>\n<td width=\"98\">0.0002<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The reason that such a long chain is required is the strong autocorrelation. For me the autocorrelation plot is key. Remember that the stored values have already been thinned by 20, yet when we look at the autocorrelations for the three chains\u00a0using <strong>mcmcac<\/strong> there is still noticeable correlation up to a lag of about 30 (that is, about 600 of the original iterations).<\/p>\n<p><a href=\"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/files\/2015\/06\/nw_ac1-e1435326368608.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-734\" src=\"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/files\/2015\/06\/nw_ac1-e1435326368608.png\" alt=\"nw_ac1\" width=\"600\" height=\"439\" \/><\/a><br \/>\nThere are convergence issues that remain with the OpenBUGS analysis but it is time to try the same model in <strong>Stan<\/strong>. I\u2019ll start by presenting a basic Stata program that performs the analysis and then I\u2019ll discuss the changes in the code that are needed when we switch from OpenBUGS to Stan.<\/p>\n<p>Here is the Stata program<\/p>\n<p><span style=\"color: #0000ff\">use &#8220;thrombolytic.dta&#8221;, clear<\/span><br \/>\n<span style=\"color: #339966\"> * Number of treatments in each study<\/span><br \/>\n<span style=\"color: #0000ff\"> sort study<\/span><br \/>\n<span style=\"color: #0000ff\"> by study: egen nt = count(trt&gt;0)<\/span><br \/>\n<span style=\"color: #339966\"> * offsets &#8211; row numbers for start of each study or design<\/span><br \/>\n<span style=\"color: #0000ff\"> sort design study trt<\/span><br \/>\n<span style=\"color: #0000ff\"> gen os = _n*(study != study[_n-1])<\/span><br \/>\n<span style=\"color: #0000ff\"> gen os_design = _n*(design != design[_n-1])<\/span><br \/>\n<span style=\"color: #0000ff\"> by design: egen b = min(trt)<\/span><br \/>\n<span style=\"color: #0000ff\"> replace os = 59 in 58<\/span><br \/>\n<span style=\"color: #339966\"> *&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<\/span><br \/>\n<span style=\"color: #339966\"> * Write the data file: jags &amp; Stan use the same format<\/span><br \/>\n<span style=\"color: #339966\"> *&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<\/span><br \/>\n<span style=\"color: #0000ff\"> wbslist_v2 (vect study design trt b r n, format(%5.0f) name(study d t b r n) ) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\"> (vect os if os != 0 , format(%5.0f) name(offset) ) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\"> (vect os_design nt if os_design != 0 , format(%5.0f) name(offset_design num_ests) ) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\"> (zero &lt;- c(7{0.0})) (A &lt;-58 _n S &lt;- 28 _n T &lt;- 8 _n D &lt;- 13) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\"> using thromData.txt, replace jags<\/span><br \/>\n<span style=\"color: #339966\"> *&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/span><br \/>\n<span style=\"color: #339966\"> * Write the model file<\/span><br \/>\n<span style=\"color: #339966\"> *&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/span><br \/>\n<span style=\"color: #0000ff\"> wbsmodel thrombo_stan.do thromModel.stan<\/span><br \/>\n<span style=\"color: #339966\"> \/*<\/span><br \/>\n<span style=\"color: #339966\"> data {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 int A;<\/span><span style=\"color: #339966\">\u00a0\u00a0\u00a0int S;<\/span><span style=\"color: #339966\">\u00a0\u00a0 int T;<\/span><span style=\"color: #339966\">\u00a0\u00a0 int D;<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 int study[A];<\/span><span style=\"color: #339966\">\u00a0\u00a0 int d[A];\u00a0\u00a0\u00a0 <\/span><span style=\"color: #339966\">int t[A];<\/span><span style=\"color: #339966\">\u00a0\u00a0 int b[A];<\/span><span style=\"color: #339966\">\u00a0\u00a0 int r[A];<\/span><span style=\"color: #339966\">\u00a0\u00a0 int n[A];<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 int offset[29];<\/span><span style=\"color: #339966\">\u00a0\u00a0 int offset_design[13];<\/span><span style=\"color: #339966\">\u00a0\u00a0 int num_ests[13];<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 vector[7] zero;<\/span><br \/>\n<span style=\"color: #339966\"> }<\/span><br \/>\n<span style=\"color: #339966\"> parameters {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 real&lt;lower=0.0,upper=2.0&gt; tau;<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 real eff_des[A,A];<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 vector[7] RE[S];<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 real mu[S];<\/span><br \/>\n<span style=\"color: #339966\"> }<\/span><br \/>\n<span style=\"color: #339966\"> transformed parameters {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 matrix[7,7] Prec;<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 real eff_study[S,A,A];<\/span><br \/>\n<span style=\"color: #339966\"> # Prec is the inverse of the structured heterogeneity matrix<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 for(i in 1:7) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0 Prec[i,i] &lt;- 1.75\/(tau*tau);<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0 for(j in 1:7){<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if( i != j ) Prec[i,j] &lt;- -0.25\/(tau*tau);<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 for(i in 1:S) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0 eff_study[i, b[offset[i]], b[offset[i]]] &lt;- 0;<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0 for(k in (offset[i] + 1):(offset[i + 1]-1)) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if( t[k] == 1 ) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if( b[k] == 1 ) eff_study[i,t[k],b[k]] &lt;- eff_des[d[k],t[k]];<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else eff_study[i,t[k],b[k]] &lt;- eff_des[d[k],t[k]] &#8211; RE[i][b[k]-1];<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if( b[k] == 1 ) eff_study[i,t[k],b[k]] &lt;- eff_des[d[k],t[k]] + RE[i][t[k]-1];<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else eff_study[i,t[k],b[k]] &lt;- eff_des[d[k],t[k]] + RE[i][t[k]-1] &#8211; RE[i][b[k]-1];<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 \u00a0}<\/span><br \/>\n<span style=\"color: #339966\">\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\"> }<\/span><br \/>\n<span style=\"color: #339966\"> model {<\/span><br \/>\n<span style=\"color: #339966\"> # Random effects for heterogeneity<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 for(i in 1:S) {\u00a0 <\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0 RE[i] ~ multi_normal_prec(zero, Prec);<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 for(i in 1:A) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0 r[i] ~ binomial_logit(n[i],mu[study[i]] + eff_study[study[i],t[i],b[i]]);<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0}<\/span><br \/>\n<span style=\"color: #339966\"> # Priors<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 for(i in 1:S) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0 mu[i] ~ normal(0.0,10.0);<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 tau ~ uniform(0.0,2.0);<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 for(i in 1:D) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0 for(k in (offset_design[i] + 1):(offset_design[i] + num_ests[i])) {<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 eff_des[i,t[k]] ~ normal(0.0,10.0);<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 \u00a0\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\">\u00a0\u00a0 }<\/span><br \/>\n<span style=\"color: #339966\"> }<\/span><br \/>\n<span style=\"color: #339966\"> *\/<\/span><br \/>\n<span style=\"color: #339966\"> *&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/span><br \/>\n<span style=\"color: #339966\"> * Prepare a Stan batch file<\/span><br \/>\n<span style=\"color: #339966\"> *&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/span><br \/>\n<span style=\"color: #0000ff\"> wbsscript_v3 using throm.bat , replace \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\"> model(thromModel.stan) data(thromData.txt) \/\/\/<\/span><br \/>\n<span style=\"color: #0000ff\"> updates(3000) burnin(500) coda(outthromprec) stan<\/span><br \/>\n<span style=\"color: #339966\"> *&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/span><br \/>\n<span style=\"color: #339966\"> * Run the batch file<\/span><br \/>\n<span style=\"color: #339966\"> *&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/span><br \/>\n<span style=\"color: #0000ff\"> wbsrun_v3 using throm.bat , stan<\/span><br \/>\n<span style=\"color: #0000ff\"> type log.txt<\/span><br \/>\n<span style=\"color: #339966\"> *&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/span><br \/>\n<span style=\"color: #339966\"> * read the results into Stata<\/span><br \/>\n<span style=\"color: #339966\"> *&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<\/span><br \/>\n<span style=\"color: #0000ff\"> wbscoda_v3 using outthromprec.csv , stan clear<\/span><\/p>\n<p>The Stata code for preparing the data file is almost unchanged. Stan uses the same data file format as JAGS, so we merely set the jags option to <strong>wbslist_v2<\/strong>. Note though that when we do not use a keyword, wbslist_v2 writes our text\u00a0directly to the file and in the JAGS\/Stan format each item must be placed on a newline, so _n replaces the comma of OpenBUGS as our separator.<\/p>\n<p>We do not need initial values as Stan is designed to set them internally.<\/p>\n<p>After specifying the model we create a script file with <strong>wbsscript_v3<\/strong> much as\u00a0with OpenBUGS\u00a0except that we set the stan option. Remember that the file that is created is actually a batch file and not a script file because Stan works by compiling the code in the model file and turning it into an executable program that\u00a0is run via the Windows operating system.<\/p>\n<p>The results are written to a comma delimited file that could be read by Excel. However, the file contains a header of summary information about the run so we need to use <strong>wbscoda_v3<\/strong> to extract the simulations and to read them into Stata.<\/p>\n<p>This leaves us with the Stan\u00a0model file. Of course there are many ways of writing any piece of computer code and my experience of Stan is rather limited so my code may not be the most efficient, but at least it works.<\/p>\n<p>The first block defines the data and sets up space for the information that will be read from the data file. Remember that Stan does not see the data until after the program has been compiled so it needs to\u00a0be told\u00a0the sizes of the variables. The next block defines the parameters, i.e. everything for which you give a prior. Stan will choose random starting values for these parameters. Next come the transformed parameters. These are\u00a0quantities that can be calculated from the basic parameters. For instance, the precision matrix, Prec, can be calculated from tau. Stan will\u00a0obtain the starting values for the transformed parameters by deriving them from the starting values for the basic parameters.<\/p>\n<p>When the elements of Prec are calculated from tau, the OpenBUGS code used the equals() function, while in Stan I code the test explicitly using \u201c== \u201c<\/p>\n<p>You will notice some other differences in the code. In OpenBUGS we had a matrix of parameters RE in which the first column was fixed at zero and the other columns were estimated.\u00a0Use of\u00a0fixed and estimated values in the same structure is not\u00a0allowed in Stan so\u00a0I formed a parameter matrix RE with one less column and treated references to column 1 as a special case in the subsequent code. In fact I have not defined RE to be a matrix at all, but rather I have created a set of vectors corresponding to the different columns. This is somewhat more natural since each vector(column) is drawn separately\u00a0from a multivariate normal distribution.<\/p>\n<p>Finally, notice that the distributions have different names in Stan and there are many variations on each distribution. So a multivariate normal, multi_normal(), is used if you know the mean and covariance matrix and multi_normal_prec() is used if you know the mean and precision matrix. binomial() is used when we know n and p, but binomial_logit() is used when we know n and logit(p).<\/p>\n<p>The Stan syntax takes a little getting used to if you are a long-standing BUGS user, but in truth it is closer to a standard programming language and much more flexible than WinBUGS or OpenBUGS.<\/p>\n<p>Anyway the code runs, but don\u2019t\u00a0start it if you are in a hurry. It is incredibly slow! 3000 updates and a 500 burnin took about 1.5 hours.<\/p>\n<p>Although\u00a0Stan is very slow, the estimates that it produces are of very high quality. The 3,000 updates have a\u00a0similar sem to that given by 450,000 OpenBUGS updates.<\/p>\n<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br \/>\nParameter\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 n\u00a0\u00a0\u00a0\u00a0 mean\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 sd\u00a0\u00a0 \u00a0sem\u00a0\u00a0 median\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 95% CrI<br \/>\n&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br \/>\nw7\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 3000\u00a0\u00a0 1.249\u00a0\u00a0 0.646\u00a0\u00a0 0.0141\u00a0\u00a0 1.239 ( -0.048,\u00a0\u00a0 2.515 )<br \/>\n&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<\/p>\n<p>What is more there is no indication of early drift<\/p>\n<p><a href=\"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/files\/2015\/06\/nw_trace2-e1435326627946.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-736\" src=\"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/files\/2015\/06\/nw_trace2-e1435326627946.png\" alt=\"nw_trace2\" width=\"600\" height=\"439\" \/><\/a><\/p>\n<p>The visual impression of the trace plot is confirmed by the Geweke analysis, which shows a\u00a0mean (se) of 1.269 (0.0245) in the first 10% and 1.234(0.0172) in the final 50% with a p-value 0.242.<\/p>\n<p>Most importantly,\u00a0the autocorrelation is negligible, so we have the equivalent of a random sample.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-737\" src=\"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/files\/2015\/06\/nw_ac2-e1435326668714.png\" alt=\"nw_ac2\" width=\"600\" height=\"439\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>I hit one other problem. Stan wrote all of the parameters to the output file and\u00a0there are so many that neither Excel nor Stata could cope. So to obtain the estimate of w7 I had to open part of the output\u00a0file in Excel and then manually copy and paste the relevant columns into Stata.<\/p>\n<p>This particular model creates estimates for every treatment comparison in every study. Hence the huge output file. I suspect that it would be possible to reparameterize the model with far fewer active parameters, which might greatly improve the performance of Stan. One of the difficulties that Stan had in this example\u00a0is that the code that I wrote is based on a structure and parameterization that was intended for OpenBUGS.<\/p>\n<p>For me, there is no clear winner even though Stan was\u00a0much slower. I have been using WinBUGS for years and I know more or less how to write efficient WinBUGS code.\u00a0Perhaps I need to put the same investment into Stan before I\u00a0will be\u00a0in a position to judge how good it is.<\/p>\n<p>If you want to download any of the programs referred to in this posting they are available from my webpage at <a href=\"https:\/\/www2.le.ac.uk\/Members\/trj\">https:\/\/www2.le.ac.uk\/Members\/trj<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A rather long posting this week for which I apologise. I would have split this\u00a0posting over two weeks but I am about to go on my summer holiday and I wanted\u00a0to avoid a long gap between the two halves. I have spent\u00a0the last few\u00a0weeks discussing how Stan can be called from Stata and now the [&hellip;]<\/p>\n","protected":false},"author":134,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[69,24,48,56],"class_list":["post-723","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-autocorrelation","tag-network-meta-analysis","tag-openbugs","tag-stan"],"_links":{"self":[{"href":"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/wp-json\/wp\/v2\/posts\/723","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/wp-json\/wp\/v2\/users\/134"}],"replies":[{"embeddable":true,"href":"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/wp-json\/wp\/v2\/comments?post=723"}],"version-history":[{"count":20,"href":"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/wp-json\/wp\/v2\/posts\/723\/revisions"}],"predecessor-version":[{"id":751,"href":"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/wp-json\/wp\/v2\/posts\/723\/revisions\/751"}],"wp:attachment":[{"href":"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/wp-json\/wp\/v2\/media?parent=723"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/wp-json\/wp\/v2\/categories?post=723"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/staffblogs.le.ac.uk\/bayeswithstata\/wp-json\/wp\/v2\/tags?post=723"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}