楼主: Imasasor
8732 31

怎么利用hash或sql将不同观测按要求重新组合? [推广有奖]

11
maidenhan 发表于 2012-11-6 14:31:38
bobguy 发表于 2012-11-6 12:14
I think the key is to figure out how many duplicates one needs to make for each and every observatio ...
你的思路和我最初的思路一样,可惜这个思路有漏洞的。用下面这个样例跑一下,您就会发现这个思路的问题。

data test;
input subjn dt Rx $ x;
cards;
2 3 A 21
2 7 C 22
2 7 B 23
2 12 D 24
2 12 B 25
;run;

12
sculhb_1027 发表于 2012-11-6 16:43:57
不错,好好学习一下

13
pobel 在职认证  发表于 2012-11-6 19:29:17

data test;
input subjn dt Rx $ x;
cards;
1 1 A 11
1 2 B 12
1 3 C 13
2 3 A 21
2 7 C 22
2 7 B 23
2 12 D 24
3 1 B 31
3 1 C 32
3 5 A 33
3 8 t 34
3 8 p 35
3 11 D 36
3 11 E 37
;;;;

data test1(keep=subjn dt rx x n);
   set test end=last;
   by subjn dt;
   length obs $100 code $1000;
   retain obs code;
   n=_n_;
   output test1;
   if first.dt then obs=catx(",",_n_);
   else obs=catx(",",obs,_n_);

   if _n_=1 then code="data all; ";

   if first.subjn then do;
        code=trim(code)||" subjn="||strip(subjn)||"; caseid=0; ";
                dtnum=0; caseid=0; i=0;
         end;
   if last.dt then do;
                  dtnum+1;
          code=trim(code)|| " do obs"||strip(dtnum)||"="||strip(obs)||";";
                end;
   if last.subjn then do;
              code=trim(code)||"caseid+1; output;";
                do i=1 to dtnum;
                   code=trim(code)||" end;";
            end;
        end;
   if last then do;
       code=trim(code)||" run;";
       call execute(code);
        end;
run;

data all1;
   set all;
   keep caseid n;
   array temp(*) obs:;
   do i=1 to dim(temp);
      n=temp(i);
          if ^missing(n) then output;
        end;
run;

proc sort data=all1;
   by n;
run;

data wanted;
   merge test1 all1;
   by n;
   drop n;
run;

proc sort data=wanted;
   by subjn caseid;
run;

已有 1 人评分论坛币 学术水平 热心指数 信用等级 收起 理由
数据分析师3K + 60 + 5 + 5 + 5 鼓励积极发帖讨论

总评分: 论坛币 + 60  学术水平 + 5  热心指数 + 5  信用等级 + 5   查看全部评分

和谐拯救危机

14
Imasasor 发表于 2012-11-6 20:01:15
感谢各位高手的答案,有空一个一个好好学习一下,至于悬赏币,只是一个形式,就给第一位同学了。
我也贴上我后来写的程序,有点长,但一步步都做了注释,供需要的人围观
  1. data test;
  2. input subjn dt Rx $ x;
  3. cards;
  4. 1 1 A 11
  5. 1 2 B 12
  6. 1 3 C 13
  7. 2 3 A 21
  8. 2 7 C 22
  9. 2 7 B 23
  10. 2 12 D 24
  11. 3 1 B 31
  12. 3 1 C 32
  13. 3 5 A 33
  14. 3 8 B 34
  15. 3 11 B 35
  16. 3 11 D 36
  17. 3 11 E 37
  18. ;
  19. run;

  20. /*可能可以有很多方法来做这个问题,sql查询如果学得好貌似应该可以解决这个问题,无奈本人不太熟悉sql*/
  21. /*只能用最擅长的base一点一点解决,可能不是最好的方法,但最后能解决问题*/
  22. /*基本处理思想,把每个subjn一个一个拿出来做,做好后不断append final数据集中
  23. 对于每个subjn,用sas的point=n语句不断跳转并输出,n由每个subjn和dt的数据结构决定*/

  24. %macro dat(source=,total=);

  25. %do h=1 %to &total;
  26. data a;
  27. set &source;
  28. where subjn=&h;
  29. run;
  30. proc sql noprint;
  31. select count(*) into:x from a;
  32. quit;  /*将subjn=&h的人拿出生成a*/

  33. %if &x^=0 %then %do; /*如果a数据集观测不为空的话*/
  34. proc sql noprint;
  35. create table c as select subjn,dt,count(dt) as count from a
  36. group by subjn,dt;
  37. quit;
  38. data d;
  39. merge a c;
  40. by subjn dt;
  41. run; /*生成的d中,每个dt都对应一个count,为该dt出现的次数*/


  42. data f;
  43. set d;
  44. n=_n_;
  45. if first.dt then output;
  46. by dt;
  47. run;
  48. /*生成的f中,两个需要用来作point指针的变量,一个为count,一个为n*/
  49. data g;
  50. set f;
  51. keep subjn dt count n;
  52. n=n-1;
  53. run;


  54. proc sql noprint;
  55. select count(*) into:num from g;
  56. quit;
  57. proc sql noprint;
  58. select n into:n1-:n%left(&num) from g;
  59. select count into:count1-:count%left(&num) from g;
  60. quit; /*分别将n和count赋给多个宏变量,用于随后生成多个point=n的指针*/

  61. %macro r;
  62. data o;
  63. %do i=1 %to #
  64. a&i=&&n&i;
  65. %end;
  66. run;
  67. %mend;

  68. %r  /*o中的几个变量,为point=n第一个循环时的观测位置减去1*/


  69. %macro sb;
  70. data p;
  71. set o;
  72. %do b=1 %to #
  73. do point&b=1 to &&count&b;
  74. %end;
  75. %do c=1 %to #
  76. c&c=a&c+point&c;
  77. %end;
  78. output;
  79. %do d=1 %to #
  80. end;
  81. %end;
  82. keep c1-c%left(&num);
  83. run;
  84. %mend;
  85. %sb  /*关键一步,生成的所有观测实际为point=n的所有指针*/

  86. %macro cat;
  87. data q;
  88. set p;
  89. informat d $40.;
  90. d=catx(",",%do j=1 %to %eval(&num-1); C&j,%end; c%left(&num));
  91. run;
  92. %mend;
  93. %cat  /*将所有指针用逗号连起来*/

  94. proc sql noprint;
  95. select count(*) into:num2 from q;
  96. quit;
  97. proc sql noprint;
  98. select d into:e1-:e%left(&num2) from q;
  99. quit; /*将所有的d赋给多个宏变量,即point=n中用到的宏变量*/

  100. %macro last;
  101. data last;
  102. %do k=1 %to &num2;
  103. do n=&&e&k;
  104. set d point=n;
  105. output;
  106. end;
  107. %end;
  108. drop count;
  109. stop;
  110. run;
  111. %mend;
  112. %last /*最后一步,将point=n按照前面生成的宏变最不断变换位置,并输出*/

  113. %if &h=1 %then %do;
  114. data final;
  115. set last;
  116. if _n_=1 then stop;
  117. run;
  118. %end; /*先建立一个空的数据集*/

  119. proc append base=final data=last force;
  120. run; /*不断添加*/

  121. %end;
  122. %end;

  123. %mend dat;



  124. /*两个宏参数source代表源数据集,total为总共的病人数,如上例为3人,稍大于总人数没有关系
  125. 最后结果保存在work的final中*/
  126. %dat(source=work.test,total=4)
复制代码
已有 2 人评分学术水平 热心指数 信用等级 收起 理由
数据分析师3K + 5 鼓励积极发帖讨论
tobewithU + 1 + 1 + 1 观点有启发

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

欢迎加入亚太地区第一R&Python数据挖掘群: 251548215;

15
davil2000 发表于 2012-11-6 20:33:14
maidenhan 发表于 2012-11-5 19:41
对不起楼主,我的思路有问题,2*3的时候ok,2*2的时候结论是错的,容我晚上在好好想想~~
学习了 谢谢
R是万能的,SAS是不可战胜的!

16
davil2000 发表于 2012-11-6 21:21:09
yuerqieqie 发表于 2012-11-6 04:16
感觉group的逻辑很难。
强悍
R是万能的,SAS是不可战胜的!

17
jingju11 发表于 2012-11-7 01:10:44
I know one of codes above is quite good. but I am not able to figure out how the group was defined so far. I had to use a macro to simulate the loop I need, which makes the code strange. Anyway, i think it does work. JingJu
  1. proc sort data = test out =test0; by subjn dt;
  2. run;
  3. data test1;
  4.         set test0 end =Eof; by subjn dt;
  5.         array s[2] _temporary_;
  6.         obs = _n_;
  7.         if first.subjn         then do; d1 =0;                                        end;
  8.         if first.dt                 then do; d2 =0; d1 ++1; end;
  9.         d2 ++1;
  10.         if last.subjn then s[1] = max(d1, s[1]);
  11.         if last.dt                 then s[2] = max(d2, s[2]);
  12.         if Eof then do;
  13.                 call symputx('maxS', s[1]);
  14.                 call symputx('maxD', s[2]);
  15.         end;
  16. run;%put &maxS &maxD;
  17. data test2;
  18.         array s[&maxS]; array t2[&maxS,&maxD] _temporary_; array t3[&maxS] _temporary_;
  19.         set test1; by subjn dt;
  20.         t2[d1, d2]         = obs        ;
  21.         t3[d1]                         = d2        ;
  22.         if last.subjn then do;
  23.                 %macro loops;options nomprint;%local ends;
  24.                         %do i =1 %to &maxS;        %let ends = &ends %str(end;);
  25.                                 do i&i =1 to max(1, t3[&i]); s[&i] = t2[&i,i&i];
  26.                         %end;
  27.                         output; &ends
  28.                 %mend loops;
  29.                 %loops;
  30.                 call missing(of t2[*]); call missing(of t3[*]);
  31.         end;
  32.         keep s1-s&maxS;
  33. run;
  34. data testOUT;
  35.         set test2;array s[&maxS];
  36.         do i =1 to dim(s);
  37.                 obs0 =s[i]; if missing(s[i]) then leave;
  38.                 do p =1 to nobs;
  39.                         set test1 point =p nobs =nobs;
  40.                         if obs0 =obs then output;
  41.                 end;
  42.         end;
  43.         keep subjn dt Rx x;
  44. run;
复制代码
已有 2 人评分论坛币 学术水平 热心指数 信用等级 收起 理由
数据分析师3K + 60 + 5 + 5 + 5 热心帮助其他会员
hopewell + 1 + 1 + 1 我很赞同

总评分: 论坛币 + 60  学术水平 + 6  热心指数 + 6  信用等级 + 6   查看全部评分

18
Imasasor 发表于 2012-11-7 10:32:05
jingju11 发表于 2012-11-7 01:10
I know one of codes above is quite good. but I am not able to figure out how the group was defined s ...
人间遍地是高手
欢迎加入亚太地区第一R&Python数据挖掘群: 251548215;

19
bobguy 发表于 2012-11-7 11:41:30
maidenhan 发表于 2012-11-6 14:31
你的思路和我最初的思路一样,可惜这个思路有漏洞的。用下面这个样例跑一下,您就会发现这个思路的问题。 ...
Yes, I think I overlook the original request. The combination needs to be considered in here. I still see a lot of solution proposed is so complicated. Here is a solution using 'by logic' to deal with each subjn block.  Within each subjn a combination will produced exactly for dt blocks. To simplify the problem I left only relevant variables and remove any dt block with only one obs in there.

The trick part here is the number of dt blocks in each subjn in unknown before hand. I use the different sub branch to handle it. The problem calls different sub-output-routine according to the number of dt blocks in a subjn block. I only write for cases of 2, 3 dt blocks in a subjn block. It is easily to expand it.


   

data test;
input subjn dt   x ;
cards;
1 7   22  
1 7   23   
1 12  24  
1 12  25
2 7   22  
2 7   23  
2 12  24  
2 12  25  
2 12  26  
2 14  24  
2 14  25  
;
run;

data test2;
  do n=1 by 1 until (last.subjn);
     set test end=end;
         by subjn dt;
         array d[4] subjn dt order  x ;
         array ss[100, 4] _temporary_;
         array s[5] s1-s5;
         array e[5] e1-e5;
         if first.subjn then do;
       order=0;
           idx=0;
         end;
         order+1;
         if first.dt then do;
      idx+1;
          s[idx]=order;
         end;
         if last.dt then do;
          e[idx]=order;
         end;

     l2=dim(d);
     do i=1 to l2;
        ss[order,i]=d;
         end;
  end;

  group=0;


  if idx=2 then link out2;
  else if idx=3 then link out3;
  *else if idx=4 then link out4;
  *else if idx=5 then link out5;
return;

out3:
  do i=s1 to e1;
     do j=s2 to e2;
            do k=s3 to e3;
                  group+1;
                  do l=1 to l2;
            d[l]=ss[i,l];
              end;
                  output;
                  do l=1 to l2;
            d[l]=ss[j,l];
              end;
                  output;
                  do l=1 to l2;
            d[l]=ss[k,l];
              end;
                  output;
        end;
        end;
end;
return;


out2:
  do i=s1 to e1;
     do j=s2 to e2;
                  group+1;
                  do l=1 to l2;
            d[l]=ss[i,l];
              end;
                  output;
                  do l=1 to l2;
            d[l]=ss[j,l];
              end;
                  output;
        end;
end;
return;

drop s1  s2  s3  s4  s5  e1  e2  e3  e4  e5  idx  l2 i j k l;

run;

proc print;run;

   
已有 4 人评分论坛币 学术水平 热心指数 信用等级 收起 理由
数据分析师3K + 60 + 5 + 5 + 5 热心帮助其他会员
hopewell + 1 + 1 + 1 我很赞同
tobewithU + 1 + 1 + 1 牛人啊啊
Imasasor + 1 + 1 + 1 违法信息

总评分: 论坛币 + 60  学术水平 + 8  热心指数 + 8  信用等级 + 8   查看全部评分

20
zhangzachary 发表于 2012-12-25 13:30:52
好贴啊,人大SAS版的高手都齐了,就缺hopewell大大没放程序啦~~
我自己也来帖一个,用上面bobguy的dataset:
  1. data test;
  2. input subjn dt   x ;
  3. cards;
  4. 1 7   22  
  5. 1 7   23   
  6. 1 12  24  
  7. 1 12  25
  8. 2 7   22  
  9. 2 7   23  
  10. 2 12  24  
  11. 2 12  25  
  12. 2 12  26  
  13. 2 14  24  
  14. 2 14  25  
  15. ;
  16. run;

  17. proc sql noprint;
  18.   select distinct subjn into:subj separated by '|'
  19.     from test;
  20. quit;

  21. data ff;
  22.   if 0 then set test;
  23. run;

  24. %macro ff;
  25.   %let k=1;
  26.   %let id=%scan(&subj.,&k.,'|');
  27.   %do %until(&id.= );
  28.       proc sql noprint;
  29.             select distinct dt into:dt separated by '|'
  30.                   from test
  31.                     where subjn=&id.;
  32.           quit;
  33.           %let j=1;
  34.           %let dtj=%scan(&dt.,&j.,'|');
  35.        %let dtj1=%scan(&dt.,%eval(&j.+1),'|');
  36.            proc sql noprint;
  37.              create table ffj as
  38.                    select subjn, dt as dt0, x as x0
  39.                      from test
  40.                            where subjn=&id. and dt=&dtj.;
  41.            quit;
  42.           %do %until(&dtj.= );
  43.                %let dtj1=%scan(&dt.,%eval(&j.+1),'|');
  44.                    proc sql noprint;
  45.                      create table ffj as
  46.                            select a.*, b.dt as dt&j., b.x as x&j.
  47.                              from ffj as a,
  48.                                       (select * from test where subjn=&id. and dt=&dtj1.) as b
  49.                                    where a.subjn=b.subjn;
  50.                    quit;

  51.                    %let j=%eval(&j.+1);
  52.                    %let dtj=%scan(&dt.,&j.,'|');
  53.           %end;

  54.           data ffk;
  55.             set ffj;
  56.             %do i=0 %to %eval(&j.-1);
  57.                     dt=dt&i.;
  58.                         x=x&i.;
  59.                         output;
  60.                 %end;
  61.           run;

  62.           data ff;
  63.                   set ff ffk;
  64.           run;

  65.      %let k=%eval(&k.+1);
  66.      %let id=%scan(&subj.,&k.,'|');
  67.   %end;

  68.   proc sort data=ff out=final(keep=subjn dt x) nodup;
  69.     by subjn;
  70.         where nmiss(subjn,dt,x)=0;
  71.   run;
  72. %mend ff;
  73. %ff;
复制代码
写了个简单点的,有warning和error,木有考虑其他情况,不过final还是给出了所需要的结果,嘿嘿~
也请各位高手指点warning和error的问题,有待改进!
寒冰凤凰 My blog: http://blog.sina.com.cn/u/1058955485

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

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2025-12-31 22:30