如何在SAS中的proc NLMIXED中使用Do循环而不使用Array语句

时间:2017-01-22 08:19:31

标签: arrays loops sas

当我按照sas代码运行时,它说,优化无法完成。其中一个问题,我猜,我使用的是宽格式数据,这对proc NLMIXED不好,任何人都可以帮我解决下面我可以使用的代码/问题,长格式数据,我必须使用do循环,但是,如何使用长格式数据来完成它。

proc nlmixed   
    data=new method=GAUSS NOAD qpoints=50 tech=newrap maxit=5000
;
  array y{*} y1-y5;
  array Time{*} Time1-Time5;
  parms  b1=0.95 sdn1=0.95 sdC=0.90 fi=0.45;
  bounds sdn1 >= 0, sdC >= 0;
  pi=constant('pi');
  L1=log(pi)-((pi*(y[1]-b1*Time[1] + bD))/(sdn1*sqrt(3)))-log(sdn1)-0.5*log(3)-2*log(1+exp(-((pi*(y[1]-b1*Time[1] + bD))/(sdn1*sqrt(3)))));
  L2=1;
  do j=2 to 5;
    L2=L2*(log(pi)-((pi*(y[j]-b1*Time[j]+y[j-1]*fi+ bD))/(sdn1*sqrt(3*(1-fi*fi))))-log(sdn1)-0.5*log(3*(1-fi*fi))-2*log(1+exp(-((pi*(y[j]-b1*Time[j]+y[j-1]*fi+ bD))/(sdn1*sqrt(3*(1-fi*fi)))))));  
  end;  
  L=L1*L2;dum=1; 
  model dum ~ general(L);
  random bD ~ normal(0,sdC*sdC) subject=ID;
run;

DATA SCREENSHOT

1 个答案:

答案 0 :(得分:1)

我有几点意见。首先,当您有一个似乎给您带来问题的复杂似然函数时,您通常可以通过尝试在数据步骤中构造似然函数来确定困难的来源。您可能尝试取幂导致溢出的值,或者您可能有一个条件,您尝试计算负数的对数或平方根。当您尝试在数据步骤代码中构造(日志)可能性时,错误报告通常会提供更多关于此类问题的信息。请注意,写入数据步骤代码的目的不是为了最大化可能性,而是在给定一组指定参数的情况下评估可能性。

为了将NLMIXED代码转换为数据步骤代码,必须进行一些修改。首先,必须将NLMIXED语句(带选项)转换为DATA语句。 A DATA NULL ;声明通常就足够了。其次,DATA步骤不支持PARMS语句。这可以转换为RETAIN语句,通常会对代码进行一些修改。 (PARMS语句允许参数和值之间的等号.RETAIN语句不允许等号。此外,您可以使用PARMS语句为单个参数指定多个初始条件.RETAIN语句不支持多个值规范对于单个变量。)其他语句经常出现在NLMIXED代码中,这些代码在DATA步骤中不可用。在您的代码中,需要注释掉BOUNDS,MODEL和RANDOM语句。不幸的是,在RANDOM语句中识别出的随机效应必须从模型中消失,或者必须为每个随机效应赋予一些值。

现在,上面提到的DATA步骤代码中不支持的一个语句(应该!)通常也可以在NLMIXED代码中完成。具体来说,BOUNDS语句可能会在NLMIXED执行期间导致各种问题。此外,模型几乎总是可以以不需要BOUNDS语句的方式进行参数化。由于您有两个参数(sdn1和sdC),您希望它们是非负的,您可以根据两个参数(log_sdn1和log_sdC)的对数来编写模型。然后,您可以在PARMS(或RETAIN)语句之后立即构造变量sdn1 = exp(log_sdn1)和sdC = exp(log_sdC),然后在可能性规范中引用sdn1和sdC。当然,您允许sdn1和sdC在BOUNDS语句中等于0。当对log_sdn1和log_sdC取幂时,你只能实现0值的一个(无限接近)近似。

我构建了一个数据集,该数据集由您在上面显示的前两个记录组成,然后对NLMIXED代码进行修改,以将其转换为DATA步骤代码,如上所示。见下文:

data new;
  input id y1-y5;
cards;
1 0.3393279811 2.9297994781 3.3204747713 5.712911709 7.303402636
2 0.6299412759 0.5226832086 2.6025372538 4.6200632561 6.3933354199
;;;

/*proc nlmixed
      data=new method=GAUSS NOAD qpoints=50 tech=newrap maxit=5000;*/
data _null_;
  set new;

  array y{*} y1-y5;
  array Time{*} Time1-Time5;
  do i=1 to 5;
    Time{i} = i;
  end;

  /* Change PARMS statement to RETAIN statement and express sdn1 and sdC differently */
  /*parms b1=0.95 sdn1=0.95 sdC=0.90 fi=0.45;*/
  retain        b1 0.95
          log_sdn1 %sysfunc(log(0.95))
          log_sdC  %sysfunc(log(0.90))
              fi   0.45;
  /*bounds sdn1 >= 0, sdC >= 0;*/
  sdn1 = exp(log_sdn1);
  sdC = exp(log_sdC);
  pi=constant('pi');

  /* Add bD=0 to data step code only so that there is some value specified for the random effect. */
  bD=0;

  L1 = log(pi) -
       ((pi*(y[1]-b1*Time[1] + bD))/(sdn1*sqrt(3))) -
       log(sdn1) - 0.5*log(3) -
       2*log(1 + exp(-((pi *(y[1]-b1*Time[1] + bD))/(sdn1*sqrt(3)))));
  L2=1;
  do j=2 to 5;
    L2=L2*(log(pi) - ((pi*(y[j]-b1*Time[j]+y[j-1]*fi+ bD))/(sdn1*sqrt(3*(1-fi*fi)))) -
           log(sdn1) - 0.5*log(3*(1-fi*fi)) -
           2*log(1+exp(-((pi*(y[j]-b1*Time[j]+y[j-1]*fi+ bD))/(sdn1*sqrt(3*(1-fi*fi))))))
          );
  end;  
  L=L1*L2;
  dum=1; 
  /*model dum ~ general(L);*/
  /*random bD ~ normal(0,sdC*sdC) subject=ID;*/
run;

我会提供几个最后的笔记。我经常使用宽数据集来构建似然函数,其中每个主题有少量观察。从我对你如何构建可能性函数的有限看来,我不认为以长格式重塑数据会使你受益。

上面的代码运行正常。但我只雇用了两个记录。您可能会发现我排除的其他一些记录的似然函数问题。

您的优化问题也可能与使用BOUNDS语句有关。使用重新参数化的模型可能是您的似然函数正确执行所需的全部内容。