楼主: yellowriver
2017 1

[原创博文] 请高手解释高手编的macro~ [推广有奖]

  • 0关注
  • 4粉丝

VIP

博士生

38%

还不是VIP/贵宾

-

威望
0
论坛币
10028 个
通用积分
22.7632
学术水平
21 点
热心指数
26 点
信用等级
19 点
经验
3133 点
帖子
164
精华
0
在线时间
170 小时
注册时间
2007-11-4
最后登录
2019-5-18

50论坛币
前天我发帖悬赏了一个SAS macro的编写,有个牛人迅速编出,其他各路牛人纷纷赞同,学术奖章纷至沓来,我也设此为最佳答案,可是Q4,Q5这两个macro编写对于macro新手的我还是不太理解,能否请其他高手翻译一下这位高手的编程思路?

数据表如下:
  1. data StudentScore;
  2. input StudentID $ Year Score;
  3. datalines;
  4. A 91 400
  5. A 92 398
  6. A 92 399
  7. B 91 430
  8. B 92 432
  9. B 93 444
  10. B 94 446
  11. C 91 455
  12. C 92 423
  13. C 93 411
  14. C 94 415
  15. C 95 427
  16. C 95 418
  17. ;
  18. run;
复制代码
Q4. Complete the following macro.

%macroprocessyear(Inputds=StudentScore, Year=91,Outputds=Year_out);

%mend;

Year _out should have the following variables:
Year- Year specified in the input.
StudentHighScore- “StudentID “of the student with thehighest score for that year.
YearAvg- Average for the input year.

高手回复:
  1. %macro processyear(Inputds,Year,Outputds);
  2.         proc sql;
  3.                 create table &Outputds as
  4.                         select
  5.                                 Year
  6.                                 ,StudentID
  7.                                 ,Score
  8.                                 ,Avg(Score) as YearAvg
  9.                         from &Inputds
  10.                         where year=&year
  11.                         group by
  12.                                 Year
  13.                         order by
  14.                               Score desc
  15.                 ;
  16.         quit;

  17.        data &Outputds;
  18.                 set &Outputds;
  19.                 by descending Score;
  20.                 if _N_=1;
  21.                 rename StudentID=StudentHighScore;
  22.                 drop Score;
  23.         run;
  24. %mend processyear;
  25. %processyear(StudentScore,95,Year_Out);
复制代码
Q5. Write a SAS macro to create individual student files foreach student/year combination.

高手回复:
  1. %MACRO split;
  2.         proc sort data=StudentScore;by StudentId year;run;quit;
  3.         data t1;
  4.                 set StudentScore;
  5.                 by StudentId year;
  6.                 Grp=compress(StudentID||'_'||year);
  7.                 if first.year;
  8.                 keep StudentID year Grp;
  9.         run;
  10.        proc sql;
  11.                 select Grp into:output separated by '|' from t1;
  12.         quit;
  13.         %let cnt=%eval(%sysfunc(count(&output,|))+1);
  14.         %put &output &cnt;
  15.         
  16.         data
  17.                 %do i=1 %to &cnt;
  18.                         %scan(&output,&i,|)
  19.                 %end;
  20.         ;
  21.                 set StudentScore;
  22.                 %do i=1 %to &cnt;
  23.                       %if &i>=2 %then %do;else%end;
  24.                        if StudentID="%scan(%scan(&output,&i,|),1,_)" and year=%scan(%scan(&output,&i,|),2,_) then output %scan(&output,&i,|);
  25.                 %end;

  26.         ;
  27.       run;

  28. %MEND split;
  29. %SPLIT;
复制代码

关键词:Macro acr CRO Mac combination following 数据表
沙发
pobel 在职认证  发表于 2010-11-5 07:35:24 |只看作者 |坛友微信交流群
我来试试:

%macro processyear(Inputds,Year,Outputds);

   proc sql;
      create table &Outputds as          /*创建数据集,名为&outputds*/
        select                                        /*选择变量年份、编号、分数、平均分数*/
            Year
            ,StudentID
            ,Score
            ,Avg(Score) as YearAvg
        from &Inputds                         /*指定输入数据集&inputds*/
        where year=&year                 /*只选择年份为&year的数据*/
        group by   
                 Year                               /*按照年份分组*/
        order by
               Score desc                     /*将结果数据集按分数的降序排列*/
                ;
quit;

data &Outputds;
    set &Outputds;
    by descending Score;                                    /*按分数降序读入数据*/
    if _N_=1;                                                        /*选择第一条记录,即分数最高的记录*/
    rename StudentID=StudentHighScore;        /*更改变量名*/  
    drop Score;
run;

%mend processyear;

%processyear(StudentScore,95,Year_Out);  


%MACRO split;
    proc sort data=StudentScore;by StudentId year;run;quit;       /*将数据集按编号、年份排序*/
    data t1;
         set StudentScore;
         by StudentId year;                                  /*按编号、年份顺序依次读入数据*/
         Grp=compress(StudentID||'_'||year);     /*生成Grp变量,值为编号与年份组合,如A_91*/
         if first.year;                                             /*选择每个编号+年份组合的第一条记录,目的是对每个编号和年份组合只记录一次*/
         keep StudentID year Grp;                     /*保存需要的变量*/
    run;

    proc sql;
        select Grp into:output separated by '|' from t1;       /*将所有编号+年份的组合保存在宏变量output中,并以字符'|'分隔*/
    quit;

    %let cnt=%eval(%sysfunc(count(&output,|))+1);    /*数出编号+年份组合的个数,保存在宏变量cnt中*/

   %put &output &cnt;                                                    /*在log中输出宏变量output和cnt的值*/

    data
       %do i=1 %to &cnt;
         %scan(&output,&i,|)
       %end;
        ;                          /*在Data语句中列出所有的编号+年份组合。data A_91 A_92 B_91 ...;*/               
       set StudentScore;

    /*以下Do循环将每个编号和年份的数据输出到对应的数据集中。*/

       %do i=1 %to &cnt;
         %if &i>=2 %then %do;else%end;
         if StudentID="%scan(%scan(&output,&i,|),1,_)" and year=%scan(%scan(&output,&i,|),2,_) then output %scan(&output,&i,|);
      %end;
    ;
    run;
%MEND split;
%SPLIT;
已有 2 人评分学术水平 热心指数 信用等级 收起 理由
hopewell + 1 + 1 + 1 我很赞同
soporaeternus + 1 + 1 + 1 我很赞同

总评分: 学术水平 + 2  热心指数 + 2  信用等级 + 2   查看全部评分

和谐拯救危机

使用道具

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-4-30 19:21