SAS中文论坛

标题: 一个有关SAS效率的问题 [打印本页]

作者: shiyiming    时间: 2011-2-26 18:35
标题: 一个有关SAS效率的问题
Dear 版主及各位高手:
今天跑了一个自己写的宏,用了6小时,这还只是我模拟实验的几十分之一,如果按我的程序,估计真的很难毕业了,所以想请教下各位如何提高这段代码的效率?
不胜感激!!



%macro boot;                       /* bootstrap 重抽样后计算估计参数的STD*/
   %do sampnum=1 %to 500;
  data bootsamp_&sampnum;
            do i = 1 to nobs;                 
              x = round(ranuni(0) * nobs);   
              set temp  
                  nobs = nobs                     
                  point = x;              
              output;                     
           end;
         stop;                        
        run;

          proc sort data=bootsamp_&sampnum;
                              by id;
                run;

   data cox;
    merge bootsamp_&sampnum(in=b) a5(in=a);
        by id;
        if b;
  run;
   
        proc phreg data=cox covm covs;
            model t1*status(0)=z1 z2 x1 ;
                ods output parameterestimates=out_&sampnum;
        run;
  
         %if &sampnum>1 %then %do;
    proc datasets;
       append base=out_1
       data=out_&sampnum;
         quit;
         %end;
   %end;
   data para (keep=sampnum variable estimate);
          set out_1;
          if StdErrRatio ne .;
          run;

        proc sort data=para;
           by variable;
    run;

        proc means data=para std;
          var estimate;
          by variable;
          output out=temp2;
        run;
   data temp3;
     set temp2;
         if _STAT_="STD";
         keep Estimate variable;
   run;

%mend;



%macro caculatesd(n1,g,n,censor,label);     /*生成数据并将多次模拟的结果保存下来*/
%do sn=1 %to 100;
        data a1;
            do cluster=1 to &g;
                  z1=rand('BERNOULLI',0.5);
                  z2=rand('normal',2,1);
                  output;
                  end;
                run;

                data a2;
                  set  a1;
                  do i=1 to &n1;
                   output;
                  end;
                run;

                data a3;
                  do id=1 to &n;
                  u=rand('uniform');
                  lu=-log(u);
                  x1=rand('normal',3,1);
                  re=rand('normal',0,0.4);
                  output;
                  end;
                run;

         data a4;
            merge a3 a2;

         run;

         data a5;
           set a4;
                   t1=lu/exp(-2*z1+0.2*z2+0.2*x1+re);
           status=rand('BERNOULLI',&censor);
        run;

       data temp ;set a5 ;keep id;run;

        %boot                                                                  /*调用上一个宏程序*/

  proc transpose data=temp3 out=sd_&sn._&label(drop=_LABEL_);
       id variable;
       var estimate;          
   run;

   %if &sn>1 %then %do;
    proc datasets;
       append base=sd_1_&label
       data=sd_&sn._&label;
         quit;
         %end;
        %end;

        data paper.sd_&label;
           set sd_1_&label;
        run;
%mend;

%caculatesd(n1=10,g=50,n=500,censor=0.3,label=d10_50_30);


可以看到我的%caculatesd宏程序其实只做了100次,按道理来说至少要500次的,但是这个速度实在太可怕了,还望各位大侠出手相助!~
作者: shiyiming    时间: 2011-2-27 13:28
标题: Re: 一个有关SAS效率的问题
没看你code的具体内容,但是在用SAS模拟的时候,确实是很费时间的,有的都是一直运行几天几夜才会有结果。
作者: shiyiming    时间: 2011-3-1 00:42
标题: Re: 一个有关SAS效率的问题
我仔细阅读了你的程序,自己做了些猜测,几点意见仅供参考:
1.我认为你的抽样方法还不是以cluster为单位的(如你以前的问题所提到的)。在程序里,random access那些ID而不是cluster;
2.如果不需要的东西就不要output出来。尤其是那个每次算500遍的phreg。这样会省很多的时间。也建议把一次calculation里的500 bootstrap samples整合到一个大的数据集里。利用proc phreg的by-processing减少phreg的开关次数。
如果得当,对于一般的PC,你的100次calcuations应该可以控制在15分钟之内。
JingJu
作者: shiyiming    时间: 2011-3-1 18:57
标题: Re: 一个有关SAS效率的问题
就像jingju说的那样,如果不想要的data,就扼杀在摇篮中,不要把无用的data产生出来,然后又把人家忽略,这多浪费时间。

另外transpose之类的在数据多的时候就不要用的,尽量用data步来搞定。
作者: shiyiming    时间: 2011-3-1 20:03
标题: Re: 一个有关SAS效率的问题
to jingju11
呵呵,谢谢你的细心~~这个的确没有用cluster的bootstrap,因为模拟实验两个都要做的,所以只是放了最原始的bootstrap的程序~
另外至于 phreg里面的output 确实是有用的,可以看到每一次output的data我都存下了,最后用了append, 把他们合并成一个数据集,以方便最后算mean之类的,其实觉得append是个很不高效的做法,不过也没想出其他办法来
作者: shiyiming    时间: 2011-3-1 20:07
标题: Re: 一个有关SAS效率的问题
哦,对了,这个程序其实是在100次里套了500次的bootstrap。。。。所以再×500,似乎也到了好几个小时了。。。。
作者: shiyiming    时间: 2011-3-1 22:27
标题: Re: 一个有关SAS效率的问题
如果再乘上100,岂不是比你原来的程序更慢?我怎么会害你,给你个更馊的主意呢?
你或许还没有理解我所说的output。如sxlion所言,你最后只是需要一个小小的数据集,为什么一定要把大篇大篇的结果listing出来呢?
另外,或许你没有抄完全,你的程序是无法运行的。不过即使这样,我也运行了一遍,如果100次caculations(你的100×500次phreg),的确大概15分钟。也就是说,如果是最后的500次,大概90分钟之内。
我还有一个观点或许不对,希望指正:
%boot为什么要做成macro,让它无聊地编译几百次呢?我总有一个观点,%macro nested %macro是个挺不高效的写法。尤其在此处,连个macro parameter都不需要的宏

[quote:3iu8g9ps]其实觉得append是个很不高效的做法[/quote:3iu8g9ps]
append的效率我也搞不清楚。不过我想,其本质是是否需要反反复复的使用这个过程。
京剧
作者: shiyiming    时间: 2011-3-1 23:43
标题: Re: 一个有关SAS效率的问题
to jingju
恩,你说的非常对,我其实也没想过用%boot, 但是由于我想反复保存后面的phreg所出来的结果,所以只能用到out_&i的方式,如果要有&i 就必须把它包进宏里面。
我最先试过 data bootsamp;
   do sampnum = 1 to 1000;            
    do i = 1 to nobs;                 
      x = round(ranuni(0) * nobs);   
      set original   
          nobs = nobs                  
          point = x;              
      output;                     
   end;
end;
stop;                        
run;
这样的方式直接做bootstrap,但是去做proc phreg的时候就出现问题了。即使我用了 by sampnum; 按照每个sample来估计模型,但是最后却不能用 ods 将所有的结果都保存下来,这个我也很苦恼。。。。所以没有办法才做套了一个%boot
不知道您有没有好的办法?
作者: shiyiming    时间: 2011-3-2 00:27
标题: Re: 一个有关SAS效率的问题
proc phreg data=cox covm covs;
[color=#BF0000:1mgyl193]by sampNum; [/color:1mgyl193]   [color=#0000FF:1mgyl193]***<------by-processing;[/color:1mgyl193]
model t1*status(0)=z1 z2 x1 ;
ods output parameterestimates=PhregOut;
run;
何必担心。如果加上by,那么每次的结果就自动append到输出数据phregOut里了。也就是说给出的phregout应是:
sampNum parameter estimate
1              z1             ***
1              z2            ***
1              x1             ***

2              z1             ***
2              z2            ***
2             x1             ***
.....
然后
proc means data =PhregOut nway;
class parameter;
output out =MeansOut std =std;
run;
很自然的,你的每一次boot其实就是给出3个记录的data set而已。
最后再用append吧每一次caculation的数据连接起来。
作者: shiyiming    时间: 2011-3-2 18:41
标题: Re: 一个有关SAS效率的问题
append的效率很高。
作者: shiyiming    时间: 2011-3-2 18:54
标题: Re: 一个有关SAS效率的问题
to jingju;

恩,我再试试这样的方法,之前试过发现最后ods 出来的是把第一个sample的结果append了很多次。。。不知道是不是哪里出现了问题

另外,SAS的快慢是不是与计算机的配置也有很大关系?
这是我昨天11点开始跑的一段程序,到现在(第二天晚上7点)了还没有跑完。。。我想就算把bootstrap那里改了改善会那么显著吗?不知道哪里还需调整

libname paper " D:\simulation2        ";
%macro boot;
   %do sampnum=1 %to 500;
  data bootsamp_&sampnum;
            do i = 1 to nobs;                 
              x = round(ranuni(0) * nobs);   
              set temp  
                  nobs = nobs                     
                  point = x;              
              output;                     
           end;
         stop;                        
        run;

          proc sort data=bootsamp_&sampnum;
         by id;
                run;

   data cox;
    merge bootsamp_&sampnum(in=b) a5(in=a);
        by id;
        if b;
  run;
   

        proc phreg data=cox covm covs;
            model t1*status(0)=z1 z2 x1 x2;
                ods output parameterestimates=out_&sampnum;
        run;
  
         %if &sampnum>1 %then %do;
    proc datasets;
       append base=out_1
       data=out_&sampnum;
         quit;
         %end;
   %end;
   data para (keep=sampnum parameter estimate);
          set out_1;
          if StdErrRatio ne .;
          run;

        proc sort data=para;
           by parameter;
    run;

        proc means data=para std;
          var estimate;
          by parameter;
          output out=temp2;
        run;
   data temp3;
     set temp2;
         if _STAT_="STD";
         keep Estimate parameter;
   run;

%mend;


%macro nonbootsurvival(n1,g,n,censor,var,label);
%do sn=1 %to 500;
        data a1;
            do cluster=1 to &g;
                  z1=rand('BERNOULLI',0.5);
                  z2=rand('normal',2,1);
                  output;
                  end;
                run;

                data a2;
                  set  a1;
                  do i=1 to &n1;
                   output;
                  end;
                run;

                data a3;
                  do id=1 to &n;
                  u=rand('uniform');
                  lu=-log(u);
                  x1=rand('normal',3,1);
                  x2=rand('BERNOULLI',0.5);
                  re=rand('normal',0,&var);
                  output;
                  end;
                run;

         data a4;
            merge a3 a2;

         run;

         data a5;
           set a4;
                   t1=lu/exp(-2*z1+0.2*z2+0.2*x1+0.2*x2+re);
           status=rand('BERNOULLI',&censor);
        run;
   
                **cluster survival analysis;

        proc phreg data=a5 covm covs;
            model t1*status(0)=z1 z2 x1 x2;
            id cluster;
                ods output parameterestimates=robustout;
        run;
  
        data robustout_&sn;
          set robustout;
          if StdErrRatio ne .;
        run;

    %if &sn>1 %then %do;
    proc datasets;
       append base=robustout_1
       data=robustout_&sn;
         quit;
        %end;
   
        **frailty model;
         ods output ParameterEstimates=est;
   proc nlmixed data=a5 noad;
       bounds gamma > 0;
       linp  = b1*(z1)+b2*(z2)+b3*(x1)+b4*(x2)+ z;
       alpha = exp(-linp);
       G_t   = exp(-(alpha*t1)**gamma);
       g     = gamma*alpha*((alpha*t1)**(gamma-1))*G_t;
       ll = (status=1)*log(g) + (status=0)*log(G_t);
       model t1 ~ general(ll);
       random z ~ normal(0,exp(2*logsig)) subject=id;  
   run;
     ods output close;

    data frailtout_&sn;
           set est;
          if parameter="logsig" then do;
      var=exp(2*estimate);
          tao=estimate/(2+estimate);
          end;
        run;

          %if &sn>1 %then %do;
    proc datasets;
       append base=frailtout_1
       data=frailtout_&sn;
         quit;
        %end;
          
                **original COX;

        proc phreg data=a5 covm covs;
            model t1*status(0)=z1 z2 x1 x2;
                ods output parameterestimates=coxout;
        run;
  
        data coxout_&sn;
          set coxout;
          if StdErrRatio ne .;
        run;

    %if &sn>1 %then %do;
    proc datasets;
       append base=coxout_1
       data=coxout_&sn;
         quit;
        %end;

        **bootstrap claculate sd;
  data temp ;set a5 ;keep id;run;

        %boot

  proc transpose data=temp3 out=sd_&sn._&label(drop=_LABEL_);
       id parameter;
       var estimate;          
   run;

   %if &sn>1 %then %do;
    proc datasets;
       append base=sd_1_&label
       data=sd_&sn._&label;
         quit;
         %end;
        %end;

        data paper.sd_&label;
           set sd_1_&label;
        run;

  data robustci ;
  set robustout_1;
  IC_UP=estimate+1.96*StdErr;
  IC_low=estimate-1.96*StdErr;
  if parameter="z1" then true=-2;
  else if parameter="z2" then true=0.2;
  else if parameter="x1" then true=0.2;
  else if parameter="x2" then true=0.2;
  run;

  data paper.robust_&label;
    set robustci;
        if true>=IC_low and true<=IC_UP then cover=1;
        else cover=0;
    if ProbChiSq<0.05 then coverp=1;
        else coverp=0;
  run;

  data coxci ;
  set coxout_1;
  IC_UP=estimate+1.96*StdErr;
  IC_low=estimate-1.96*StdErr;
  if parameter="z1" then true=-2;
  else if parameter="z2" then true=0.2;
  else if parameter="x1" then true=0.2;
  else if parameter="x2" then true=0.2;
  run;

  data paper.cox_&label;
    set coxci;
        if true>=IC_low and true<=IC_UP then cover=1;
        else cover=0;
        if ProbChiSq<0.05 then coverp=1;
        else coverp=0;
  run;

  data frailtyci ;
  set frailtout_1;
  if parameter="b1" then true=2;
  else if parameter="b2" then true=-0.2;
  else if parameter="b3" then true=-0.2;
  else if parameter="b4" then true=-0.2;
  run;
  
  data paper.frailty_&label;
    set frailtyci;
        if true>=Lower and true<=upper then cover=1;
        else cover=0;
        if Probt<0.05 then coverp=1;
        else coverp=0;
  run;

%mend;

%nonbootsurvival(n1=10,g=50,n=500,censor=0.3,var=0.8,label=10_50_30_8);
作者: shiyiming    时间: 2011-3-2 18:57
标题: Re: 一个有关SAS效率的问题
to sxlion
哦///难道主要问题还是宏套宏?
在计算机上能有啥改进的余地不?比如把C盘剩余空间留大一点之类的,,,(我只是瞎猜测)
作者: shiyiming    时间: 2011-3-3 00:34
标题: Re: 一个有关SAS效率的问题
To jingju
忽略我上面的程序吧,我试了下,把%boot去掉了,果然快了很多!
作者: shiyiming    时间: 2011-3-3 01:22
标题: Re: 一个有关SAS效率的问题
我有过这样的经验,简单说来是:如果用宏循环和数据步循环都可实现的情况,用数据步循环将更有效。
举个例子:
%macro one;
data one;
set rawdata;
%do i=1 %to 100;
select(var_&i);
%do j=1 %to 1000;
when(&&value_&j) ....;*此处省略具体操作;
%end;
otherwise;
end;
%end;
%mend;

%macro two;
data one;
set rawdata;
array v(100)  var_1-var_100;
drop i;
do i=1 to 100;
select(v(i));
%do j=1 %to 1000;
when(&&value_&j) ....;
%end;
otherwise;
end;
end;
%mend;


即使rawdata仅有不到100条数据,第一个宏编译的时间就要几倍于第二个,有时第一个宏干脆无法运行。如果用option Mprint, 我们会发现,第一个宏将生成一个大于100*1000行的程序,而第二个仅有约1000行。
作者: shiyiming    时间: 2011-3-3 09:08
标题: Re: 一个有关SAS效率的问题
to caicaisas
最好是把%do sampnum=1 %to 500;%end这个宏循环改装到data步里。为proc phreg的by-processing创造条件。
如果这样的话,之后的proc append就是不必要的。
作者: shiyiming    时间: 2011-3-3 13:00
标题: Re: 一个有关SAS效率的问题
to sun59338
是这样。
作者: shiyiming    时间: 2011-3-3 19:00
标题: Re: 一个有关SAS效率的问题
我想问题的时候,最不希望用到宏。

不过有时为了省点代码时间和半自动化才用宏,但是也只挑一段地方。

用宏,也只用最简单的,最好不要用到什么条件,循环之类的宏,尽量少。

还有宏嵌套之类的,少碰啊,套来套去,debug困难,把自己套死了都不知道怎么死的。




欢迎光临 SAS中文论坛 (http://mysas.net/forum/) Powered by Discuz! X3.2