Dear Dave,<br><br>You are right. This can be used as a template file for handing growth mixture modeling using ADMB. Thanks for the effort. <br><br>I plan to spend some time adapting the code to handle my empirical questions at hand, and comparing the results to those obtained from Mplus, as well as some benchmarks. I will report to the community once I have something to report. <br>
<br>Many thanks.<br><br>Best,<br>Shige<br><br><div class="gmail_quote">On Sun, Feb 22, 2009 at 4:32 PM, dave fournier <span dir="ltr">&lt;<a href="mailto:otter@otter-rsch.com">otter@otter-rsch.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
Shige,<br>
<br>
I think the &quot;ADMB team&quot; consists mostly of me. So I&#39;ll try and answer<br>
your question about finite mixtures and growth models. Until today I had<br>
very little idea what growth models were, but in writing the simulator I<br>
hope I am getting the idea.<br>
<br>
Actually finite mixtures are handled directly so it is not necessary to<br>
use the random effects package. This is actually an advantage since it<br>
greatly speeds up the calculations.<br>
To illustrate the ideas I built a simulator to create a data set<br>
something like you describe in<br>
 &nbsp;<a href="http://sgsong.blogspot.com/2009/01/finite-mixture-modeling-with-admb.html" target="_blank">http://sgsong.blogspot.com/2009/01/finite-mixture-modeling-with-admb.html</a><br>
<br>
This could be done in R but I used ADMB since it illustrates some of the<br>
techniques which are useful for building the analyzer. since you didn&#39;t<br>
identify the growth curves you used I use the von Bertalanfy curve<br>
<br>
 &nbsp; &nbsp; L_t = Linf * ( 1 - exp(-k*age))<br>
<br>
where L_0=0 is assumed. Of course it is a simple matter to switch to a<br>
different curve There are two curves one with Linf=100 and the other<br>
with Linf=120. For both cases k=0.11 (time measured in years).<br>
<br>
I generated 2000 samples. First the size measured in 2 month intervals<br>
and then at ages 8,11,15,19<br>
<br>
The individuals were generated with a probability of 0.4 of belonging to<br>
group1 (linf=100) and 0.6 of belonging to group 2. After the first<br>
period the individual were changed at random to groups 1 or 2 with a<br>
transition matrix<br>
<br>
 &nbsp; .8 &nbsp;prob stay in group 1<br>
 &nbsp; .2 &nbsp;prob to move from group 2 to group 1<br>
 &nbsp; .7 &nbsp;prob to say in group 2<br>
 &nbsp; .3 &nbsp;prob to move from group 2 to group 1<br>
<br>
&nbsp;The the size data was generator using the appropriate growth curve.<br>
&nbsp;the resulting sizes were then perturbed using &nbsp;multiplicative lognormal<br>
&nbsp;random variables (std dev of .08) which were highly positively<br>
correlated (0.9)<br>
<br>
 &nbsp;The resulting output was analyzed with a finite mixture model where<br>
the 12 initial measuremeasurements are assumed to come from a mixture of<br>
two multivariate log-normal distributions with a correlation matrix of<br>
the form<br>
<br>
 &nbsp; &nbsp; &nbsp; &nbsp; 1 &nbsp; &nbsp; rho rho^2 &nbsp;.... rho^11<br>
 &nbsp; &nbsp; &nbsp; &nbsp; rho &nbsp; &nbsp;1<br>
 &nbsp; &nbsp; &nbsp; &nbsp; rho^2 &nbsp; .......<br>
<br>
&nbsp;etc.<br>
<br>
<br>
 &nbsp;The model was fit and the Hessian evaluated in under a minute.<br>
<br>
these are the parameter estimates for a typical run.<br>
<br>
# Number of parameters = 10 &nbsp;Objective function value = -84436.9<br>
Maximum gradient component = 0.0208847<br>
# p1coff:<br>
&nbsp;0.379774 0.620226<br>
# p2coff:<br>
&nbsp;0.482844 0.517158<br>
# Linf:<br>
&nbsp;99.2992 119.646<br>
# k:<br>
&nbsp;0.109928 0.110294<br>
# rho:<br>
0.882750993879<br>
# lsigma:<br>
-2.54165198426<br>
<br>
<br>
For each individual the conditional probabilities of belonging in either<br>
of the two groups was calculated after observing the first sizes and<br>
again after observing the second group of sizes. this was used to<br>
estimate the transition probabilities. (Of course this could be done in<br>
the model which would be more efficient.)<br>
~<br>
~ 0.793901 0.206099<br>
&nbsp;0.292103 0.707897<br>
~<br>
which is almost perfect.<br>
<br>
the C++ code for the simulator is<br>
<br>
~<br>
~<br>
#include &lt;admodel.h&gt;<br>
<br>
dvector growth_function(const dvector &amp; age,const dvector&amp; theta)<br>
{<br>
 &nbsp;dvector tmp=theta(1)*(1.0-exp(-theta(2)*age)); // use you own<br>
 &nbsp;return tmp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // growth function here<br>
}<br>
<br>
int main(int argc,char * argv[])<br>
{<br>
 &nbsp;int n=2000;<br>
 &nbsp;int nm=16;<br>
 &nbsp;int iseed=289;<br>
 &nbsp;random_number_generator rng(iseed);<br>
 &nbsp;dvector p1(1,2); &nbsp;// priori probability that a child is in group 1 or 2<br>
 &nbsp;p1(1)=.4; p1(2)=.6;<br>
 &nbsp;dvector p2(1,2);<br>
 &nbsp;dmatrix M(1,2,1,2); &nbsp; // transition probabilities<br>
 &nbsp;M(1,1)=.8; &nbsp;// 1 remains 1<br>
 &nbsp;M(2,1)=.3; &nbsp;// 2 moves to 1<br>
 &nbsp;M(1,2)=.2; &nbsp;// 1 moves to 2<br>
 &nbsp;M(2,2)=.7; &nbsp;// 2 remains 2<br>
 &nbsp;dvector choose(1,n);<br>
 &nbsp;dvector choose1(1,n);<br>
 &nbsp;double sigma=0.08;<br>
 &nbsp;double rho=0.9;<br>
 &nbsp;dmatrix size(1,n,1,nm);<br>
 &nbsp;imatrix group(1,n,1,2);<br>
 &nbsp;dvector age(1,nm);<br>
 &nbsp;dvector eta(1,nm);<br>
 &nbsp;dvector eps(1,nm);<br>
 &nbsp;age.fill_seqadd(.2,.2);<br>
 &nbsp;age(13)=8;<br>
 &nbsp;age(14)=11;<br>
 &nbsp;age(15)=15;<br>
 &nbsp;age(16)=19;<br>
 &nbsp;dmatrix theta(1,2,1,2); &nbsp;//parameters for growth curves<br>
 &nbsp;theta(1,1)=100;<br>
 &nbsp;theta(2,1)=120;<br>
 &nbsp;theta(1,2)=.11;<br>
 &nbsp;theta(2,2)=.11;<br>
<br>
 &nbsp;choose.fill_randu(rng); &nbsp;// use to pick group that each child belongs to<br>
 &nbsp;choose1.fill_randu(rng); &nbsp;// use to pick group that each child belongs to<br>
 &nbsp;int i;<br>
 &nbsp;for (i=1;i&lt;=n;i++) &nbsp; // loop over children<br>
 &nbsp;{<br>
 &nbsp; &nbsp;if (choose(i)&lt;p1(1))<br>
 &nbsp; &nbsp;{<br>
 &nbsp; &nbsp; &nbsp;group(i,1)=1; &nbsp;//child in group1<br>
 &nbsp; &nbsp;}<br>
 &nbsp; &nbsp;else<br>
 &nbsp; &nbsp;{<br>
 &nbsp; &nbsp; &nbsp;group(i,1)=2; // child in group2<br>
 &nbsp; &nbsp;}<br>
 &nbsp; &nbsp;if (group(i,1)==1) &nbsp;// use probability that group 1 remains in group1<br>
 &nbsp; &nbsp; &nbsp;if (choose1(i)&lt;M(1,1))<br>
 &nbsp; &nbsp; &nbsp; &nbsp;group(i,2)=1; &nbsp; &nbsp;// remained in group1<br>
 &nbsp; &nbsp; &nbsp;else<br>
 &nbsp; &nbsp; &nbsp; &nbsp;group(i,2)=2; // moved to group2<br>
 &nbsp; &nbsp;else<br>
 &nbsp; &nbsp; &nbsp;if (choose1(i)&lt;M(2,1)) // use probability that group 2 changes to<br>
group1<br>
 &nbsp; &nbsp; &nbsp; &nbsp;group(i,2)=1; &nbsp; &nbsp;// changed to group1<br>
 &nbsp; &nbsp; &nbsp;else<br>
 &nbsp; &nbsp; &nbsp; &nbsp;group(i,2)=2; // remained in group2<br>
 &nbsp;}<br>
<br>
 &nbsp;for (i=1;i&lt;=n;i++) &nbsp; // loop over children and get size data<br>
 &nbsp;{<br>
 &nbsp; &nbsp;size(i)(1,12)=growth_function(age(1,12),theta(group(i,1)));<br>
 &nbsp; &nbsp;size(i)(13,16)=growth_function(age(13,16),theta(group(i,2)));<br>
 &nbsp;}<br>
 &nbsp;double rho2=rho*rho;<br>
 &nbsp;for (i=1;i&lt;=n;i++) &nbsp; // loop over children and &nbsp;add noise<br>
 &nbsp;{<br>
 &nbsp; &nbsp;eta.fill_randn(rng);<br>
 &nbsp; &nbsp;eps(1)=eta(1);<br>
 &nbsp; &nbsp;int j;<br>
 &nbsp; &nbsp;for (j=2;j&lt;=4;j++) &nbsp; // loop over children and &nbsp;add noise<br>
 &nbsp; &nbsp;{<br>
 &nbsp; &nbsp; &nbsp;eps(j)=rho*eps(j-1)+sqrt(1.0-rho2)*eta(j);<br>
 &nbsp; &nbsp;}<br>
 &nbsp; &nbsp;eps(5)=eta(1);<br>
 &nbsp; &nbsp;for (j=6;j&lt;=16;j++) &nbsp; // loop over children and &nbsp;add noise<br>
 &nbsp; &nbsp;{<br>
 &nbsp; &nbsp; &nbsp;eps(j)=rho*eps(j-1)+sqrt(1.0-rho2)*eta(j);<br>
 &nbsp; &nbsp;}<br>
 &nbsp; &nbsp;size(i)=elem_prod(size(i),exp(sigma*eps)); &nbsp;// lognormal error<br>
 &nbsp;}<br>
<br>
 &nbsp;ofstream ofs(&quot;growth.dat&quot;);<br>
 &nbsp;ofs &lt;&lt; &quot;# nobs&quot; &lt;&lt; endl &lt;&lt; n &lt;&lt; endl ;<br>
 &nbsp;ofs &lt;&lt; &quot;# nmeasure&quot; &lt;&lt; endl &lt;&lt; nm &lt;&lt; endl ;<br>
 &nbsp;ofs &lt;&lt; &quot;# ages&quot; &lt;&lt; endl &lt;&lt; setprecision(3) &lt;&lt; setw(7) &lt;&lt; age &lt;&lt; endl ;<br>
 &nbsp;ofs &lt;&lt; &quot;# observations&quot; &lt;&lt; endl &lt;&lt; setprecision(3) &lt;&lt; setw(7) &lt;&lt; size<br>
&lt;&lt; endl ;<br>
 &nbsp;ivector icount1(1,2);<br>
 &nbsp;icount1.initialize();<br>
 &nbsp;ivector icount2(1,2);<br>
 &nbsp;icount2.initialize();<br>
 &nbsp;for (i=1;i&lt;=n;i++) &nbsp; // loop over children<br>
 &nbsp;{<br>
 &nbsp; &nbsp;icount1(group(i,1))++;<br>
 &nbsp; &nbsp;icount2(group(i,2))++;<br>
 &nbsp;}<br>
 &nbsp;cout &lt;&lt; &quot;proportions in groups &quot; &lt;&lt; icount1/sum(icount1) &lt;&lt; endl;<br>
 &nbsp;cout &lt;&lt; &quot;proportions in groups &quot; &lt;&lt; icount2/sum(icount2) &lt;&lt; endl;<br>
}<br>
<br>
<br>
while the TPL code for the analyzer is<br>
<br>
DATA_SECTION<br>
 &nbsp;init_int n<br>
 &nbsp;init_int nm<br>
 &nbsp;init_vector ages(1,nm)<br>
 &nbsp;init_matrix sizes(1,n,1,nm)<br>
 &nbsp;matrix q0(1,n,1,2)<br>
 &nbsp;matrix q1(1,n,1,2)<br>
 &nbsp;number lmin<br>
 &nbsp;number lmax<br>
&nbsp;LOC_CALCS<br>
 &nbsp;ages.fill_seqadd(.2,.2);<br>
 &nbsp;ages(13)=8;<br>
 &nbsp;ages(14)=11;<br>
 &nbsp;ages(15)=15;<br>
 &nbsp;ages(16)=19;<br>
 &nbsp;lmin=min(column(sizes,nm));<br>
 &nbsp;lmax=max(column(sizes,nm));<br>
PARAMETER_SECTION<br>
 &nbsp;init_bounded_vector p1coff(1,2,.001,1.1)<br>
 &nbsp;init_bounded_vector p2coff(1,2,.001,1.1)<br>
 &nbsp;vector p1(1,2)<br>
 &nbsp;vector p2(1,2)<br>
 &nbsp;number psum1<br>
 &nbsp;number psum2<br>
 &nbsp;init_bounded_vector Linf(1,2,0.9*lmin,1.1*lmax,2)<br>
 &nbsp;init_bounded_vector k(1,2,.01,.3)<br>
 &nbsp;init_bounded_number rho(-.1,.95,3)<br>
 &nbsp;init_bounded_number lsigma(-5.0,5.0)<br>
 &nbsp;number sigma<br>
 &nbsp;matrix cor1(1,12,1,12)<br>
 &nbsp;matrix cor2(1,4,1,4)<br>
 &nbsp;matrix is1(1,12,1,12)<br>
 &nbsp;matrix is2(1,4,1,4)<br>
 &nbsp;matrix ic1(1,12,1,12)<br>
 &nbsp;matrix ic2(1,4,1,4)<br>
 &nbsp;matrix pred_size(1,2,1,nm)<br>
 &nbsp;number lds1<br>
 &nbsp;number lds2<br>
 &nbsp;objective_function_value f<br>
PROCEDURE_SECTION<br>
 &nbsp;get_correlation();<br>
 &nbsp;get_proportions();<br>
 &nbsp;get_predicted_sizes();<br>
 &nbsp;get_likelihood();<br>
<br>
FUNCTION get_correlation<br>
 &nbsp;f+=square(rho);<br>
<br>
 &nbsp;sigma=exp(lsigma);<br>
 &nbsp;dvariable vinv=1.0/(sigma*sigma);<br>
 &nbsp;int i,j;<br>
 &nbsp;for (i=1;i&lt;=12;i++)<br>
 &nbsp; &nbsp;for (j=1;j&lt;=12;j++)<br>
 &nbsp; &nbsp; &nbsp;cor1(i,j)=pow(rho,fabs(i-j));<br>
<br>
 &nbsp;for (i=1;i&lt;=4;i++)<br>
 &nbsp; &nbsp;for (j=1;j&lt;=4;j++)<br>
 &nbsp; &nbsp; &nbsp;cor2(i,j)=pow(rho,fabs(i-j));<br>
<br>
 &nbsp;ic1=inv(cor1);<br>
 &nbsp;ic2=inv(cor2);<br>
<br>
 &nbsp;is1=ic1*vinv;<br>
 &nbsp;is2=ic2*vinv;<br>
<br>
 &nbsp;lds1=ln_det(is1);<br>
 &nbsp;lds2=ln_det(is2);<br>
<br>
FUNCTION get_proportions<br>
 &nbsp; psum1=sum(p1coff);<br>
 &nbsp; p1=p1coff/psum1;<br>
 &nbsp; f+=100.*square(log(psum1));<br>
<br>
<br>
 &nbsp; psum2=sum(p2coff);<br>
 &nbsp; p2=p2coff/psum2;<br>
 &nbsp; f+=100.*square(log(psum2));<br>
<br>
FUNCTION get_predicted_sizes<br>
 &nbsp; &nbsp; lmax=max(column(sizes,nm));<br>
 &nbsp; pred_size(1)=log(Linf(1)*(1.0-exp(-k(1)*ages)));<br>
 &nbsp; pred_size(2)=log(Linf(2)*(1.0-exp(-k(2)*ages)));<br>
<br>
FUNCTION get_likelihood<br>
 &nbsp;int i;<br>
 &nbsp;dvar_matrix res(1,2,1,nm);<br>
 &nbsp;for (i=1;i&lt;=n;i++)<br>
 &nbsp;{<br>
 &nbsp; &nbsp;res(1)=log(sizes(i))-pred_size(1);<br>
 &nbsp; &nbsp;res(2)=log(sizes(i))-pred_size(2);<br>
 &nbsp; &nbsp;dvar_vector res1a=res(1)(1,12);<br>
 &nbsp; &nbsp;dvar_vector res1b=(res(1)(13,16)).shift(1);<br>
 &nbsp; &nbsp;dvar_vector res2a=res(2)(1,12);<br>
 &nbsp; &nbsp;dvar_vector res2b=(res(2)(13,16)).shift(1);<br>
 &nbsp; &nbsp;dvariable l1a=exp(-0.5*res1a*(is1*res1a));<br>
 &nbsp; &nbsp;dvariable l1b=exp(-0.5*res1b*(is2*res1b));<br>
 &nbsp; &nbsp;dvariable l2a=exp(-0.5*res2a*(is1*res2a));<br>
 &nbsp; &nbsp;dvariable l2b=exp(-0.5*res2b*(is2*res2b));<br>
 &nbsp; &nbsp;f-=log(1.e-10+(p1(1)*l1a+p1(2)*l2a));<br>
 &nbsp; &nbsp;f-=log(1.e-10+(p2(1)*l1b+p2(2)*l2b));<br>
 &nbsp; &nbsp;f-=0.5*(lds1+lds2);<br>
<br>
 &nbsp; &nbsp; &nbsp;q0(i,1)=value(p1(1))*value(l1a);<br>
 &nbsp; &nbsp; &nbsp;q0(i,2)=value(p1(2))*value(l2a);<br>
 &nbsp; &nbsp; &nbsp;q0(i)/=sum(q0(i));<br>
 &nbsp; &nbsp; &nbsp;q1(i,1)=value(p2(1))*value(l1b);<br>
 &nbsp; &nbsp; &nbsp;q1(i,2)=value(p2(2))*value(l2b);<br>
 &nbsp; &nbsp; &nbsp;q1(i)/=sum(q1(i));<br>
 &nbsp;}<br>
REPORT_SECTION<br>
&nbsp;report &lt;&lt; setprecision(4) &lt;&lt; setw(8) &lt;&lt; inv(is1) &lt;&lt; endl;<br>
&nbsp;report &lt;&lt; setprecision(4) &lt;&lt; setw(8) &lt;&lt; inv(is2) &lt;&lt; endl;<br>
<br>
&nbsp;report &lt;&lt; setprecision(4) &lt;&lt; setw(8) &lt;&lt; cor1 &lt;&lt; endl;<br>
&nbsp;report &lt;&lt; setprecision(4) &lt;&lt; setw(8) &lt;&lt; cor2 &lt;&lt; endl;<br>
<br>
&nbsp;report &lt;&lt; colsum(q0)/n &lt;&lt; endl;<br>
&nbsp;report &lt;&lt; colsum(q1)/n &lt;&lt; endl;<br>
<br>
&nbsp;report &lt;&lt; n &lt;&lt; endl;<br>
&nbsp;report &lt;&lt; q0 &lt;&lt; endl;<br>
&nbsp;report &lt;&lt; q1 &lt;&lt; endl;<br>
<br>
<br>
I hope this illustrates how ADMB might be applied to growth models.<br>
<br>
 &nbsp; Dave<br>
<br>
<br>
<br>
<br>
<br>
--<br>
David A. Fournier<br>
P.O. Box 2040,<br>
Sidney, B.C. V8l 3S3<br>
Canada<br>
Phone/FAX 250-655-3364<br>
<a href="http://otter-rsch.com" target="_blank">http://otter-rsch.com</a><br>
_______________________________________________<br>
Users mailing list<br>
<a href="mailto:Users@admb-project.org">Users@admb-project.org</a><br>
<a href="http://lists.admb-project.org/mailman/listinfo/users" target="_blank">http://lists.admb-project.org/mailman/listinfo/users</a><br>
</blockquote></div><br>