SAS中文论坛

标题: 求助:两个数据集的搜寻比较 [打印本页]

作者: shiyiming    时间: 2009-2-12 17:05
标题: 求助:两个数据集的搜寻比较
[code:19hiegbp]data a;
input num1 num2 add $20.;
cards;
0 5 北京
6 10 上海
11 15 广州
16 21 深圳
22 29 杭州
30 36 成都
37 41 贵阳
42 52 昆明
53 58 海口
59 100 其他
;
run;
data b;
input id $ num;
cards;
001 8
002 15
003 43
004 97
;
run;[/code:19hiegbp]
当b中的num介于a中的num1和num2之间时,b中生成变量city=add,如下:
id  num  city
001 8    上海
002 15   广州
003 43   昆明
004 97   其他

这个该如何实现?实际a和b的量都比较大,a有几十万行,b有几万行
作者: shiyiming    时间: 2009-2-12 19:34
标题: Re: 求助:两个数据集的搜寻比较
这种特别情况下可以避免笛卡尔乘积。
作者: shiyiming    时间: 2009-2-13 09:04
标题: Re: 求助:两个数据集的搜寻比较
对于a,b都比较小时比较容易实现。
应该有效率高的办法...期待高手
作者: shiyiming    时间: 2009-2-13 11:02
标题: Re: 求助:两个数据集的搜寻比较
[code:1jw9xm80]data a;
input num1 num2 add $20. ;
call symput('maxA',_n_);
cards;
0 5 bj
6 10 sh
11 15 gz
16 21 sz
22 29 hz
30 36 cd
37 41 gy
42 52 km
53 58 hk
59 100 qt
;
run;

proc sort ;
  by num1 num2;
run;

data b;
input id $ num;
cards;
001 8
002 15
003 43
004 97
;
run;

proc sort ;
  by num;
run;

data ahuige(drop=num1 num2);
  set b;
  retain num1 num2 add;
  do while (not (num1<=num<=num2) and (point+1<=&maxA)) ;
    point+1;
    set  a point=point;
  end;
run;[/code:1jw9xm80]
如果A的数据的区间能保证是包含所有B所有的可能值那么代码就还可以更简化。MAXA这个宏变量也可以不要了。不包括排序的话,复杂度是约等于A+B的条数。而不是A×B
作者: shiyiming    时间: 2009-2-13 11:23
标题: Re: 求助:两个数据集的搜寻比较
<!-- s:D --><img src="{SMILIES_PATH}/icon_biggrin.gif" alt=":D" title="Very Happy" /><!-- s:D --> 效率很高,非常感谢ahuige!!

实际中A区间包含所有B中的num值。
作者: shiyiming    时间: 2009-2-13 13:12
标题: Re: 求助:两个数据集的搜寻比较
楼主需要严格明示一下限制条件:数据a中num1,num2满足num1&lt;num2,且排好序后每条观察值的num2小于下一条观察值的num1。

这个复杂度等于sum(&lt;A), &lt;A为小于A的某个数,这个数取决于B中相应的观察值num在A中的观察值的num1和num2之间对应的条数。


ps:随便优化下ahuige的代码(哈哈,ahuige别拿钢鞭打我  <!-- s:D --><img src="{SMILIES_PATH}/icon_biggrin.gif" alt=":D" title="Very Happy" /><!-- s:D --> )。

data a;
input num1 num2 add $20. ;
cards;
0 5 bj
6 10 sh
11 15 gz
16 21 sz
22 29 hz
30 36 cd
37 41 gy
42 52 km
53 58 hk
59 100 qt
30 100 sxlion         
;
run;

proc sort ;
  by num1 num2;
run;

data b;
input id $ num;
cards;
001 8
002 15
003 43
004 97
;
run;

proc sort ;
  by num;
run;

data ahuige(drop=num1 num2);
  set b;
  retain num1 num2 add;
  do while (not (num1&lt;=num&lt;=num2) and (point+1&lt;=maxA)) ;
    point+1;
    set  a point=point nobs=maxA;
  end;
run;

proc print;
run;
作者: shiyiming    时间: 2009-2-13 13:23
标题: Re: 求助:两个数据集的搜寻比较
多谢sxlion提醒,是应当严谨 <!-- s:D --><img src="{SMILIES_PATH}/icon_biggrin.gif" alt=":D" title="Very Happy" /><!-- s:D -->
最近没怎么样用SAS,都有点生疏了... <!-- s:shock: --><img src="{SMILIES_PATH}/icon_eek.gif" alt=":shock:" title="Shocked" /><!-- s:shock: -->
作者: shiyiming    时间: 2009-2-13 13:25
标题: Re: 求助:两个数据集的搜寻比较
这么多数据啊,借我玩玩啦,好像有更好的代码。
作者: shiyiming    时间: 2009-2-13 13:32
标题: Re: 求助:两个数据集的搜寻比较
<!-- s:( --><img src="{SMILIES_PATH}/icon_sad.gif" alt=":(" title="Sad" /><!-- s:( --> 不大方便.....不过这个程序的效率已经蛮高的了,呵呵
作者: shiyiming    时间: 2009-2-13 14:20
标题: Re: 求助:两个数据集的搜寻比较
如果不排序:
data ab(keep=id num add);
    set b;
        do i=1 to n;
        set a point=i nobs=n;
        if num1=&lt;num=&lt; num2 then  return;
        end;

如果前面的排好序:
data ab (keep=id num add);
    set b;
        point+1;
        do i=point to n;
        set a point=i nobs=n;
        if num1=&lt;num=&lt; num2 then  do ;
                                                 output ;
                                         if add=lag(add) then point=point-1;
                                                 return;
                                    end;
     end;
run;

如果不计排序时间的话,代码2效率高。

ps:如果有空的话会在blog中写得具体一些。
作者: Qiong    时间: 2009-2-13 16:09
标题: Re: 求助:两个数据集的搜寻比较
可不可以用proc format来实现呢?
作者: shiyiming    时间: 2009-2-13 16:33
标题: Re: 求助:两个数据集的搜寻比较
考虑过,但不知道SAS支持不支持几万条的FORMAT。而且每次用几万个条目的FORMAT来PUT的花费也不知道效率如何。
所以没这样写。
作者: shiyiming    时间: 2009-2-13 16:51
标题: Re: 求助:两个数据集的搜寻比较
根据imeon说的,要是没有意会错的话,format应该是可以的。

<!-- m --><a class="postlink" href="http://sasor.feoh.net/viewtopic.php?f=1&amp;t=629&amp;start=0&amp;st=0&amp;sk=t&amp;sd=a">http://sasor.feoh.net/viewtopic.php?f=1 ... &amp;sk=t&amp;sd=a</a><!-- m -->

哪位搞个format的代码出来欣赏下。 <!-- s:) --><img src="{SMILIES_PATH}/icon_smile.gif" alt=":)" title="Smile" /><!-- s:) -->
作者: shiyiming    时间: 2009-2-13 17:53
标题: Re: 求助:两个数据集的搜寻比较
之前也考虑过format,想来想去没弄出来,又觉得效率可能不高,所以...... <!-- s:shock: --><img src="{SMILIES_PATH}/icon_eek.gif" alt=":shock:" title="Shocked" /><!-- s:shock: -->
作者: shiyiming    时间: 2009-2-13 22:29
标题: Re: 求助:两个数据集的搜寻比较
不会
作者: shiyiming    时间: 2009-2-14 20:20
标题: Re: 求助:两个数据集的搜寻比较
对于数据集比较大的format也比较大,不过还是很不错,佩服....
<!-- s:lol: --><img src="{SMILIES_PATH}/icon_lol.gif" alt=":lol:" title="Laughing" /><!-- s:lol: --> 小弟在此谢过各位...... <!-- s:D --><img src="{SMILIES_PATH}/icon_biggrin.gif" alt=":D" title="Very Happy" /><!-- s:D -->
作者: shiyiming    时间: 2009-2-14 20:36
标题: Re: 求助:两个数据集的搜寻比较
给出测试结果好吗?
算上排序,比较下总的运行时间,还有给出你的硬件配置。各种方法(好像有4种解决的代码了)都有了,需要一点比较的结果。

ps:如果方便,请贴出来看看,谢谢!
作者: shiyiming    时间: 2009-2-14 20:54
标题: Re: 求助:两个数据集的搜寻比较
OK,等下附上
作者: shiyiming    时间: 2009-2-14 22:28
标题: Re: 求助:两个数据集的搜寻比较
这个ahuige原版,sxlion改进的:

489
490  proc sort data=a;
491    by num1 num2;
492  run;

NOTE: There were 365462 observations read from the data set WORK.A.
NOTE: The data set WORK.A has 365462 observations and 3 variables.
NOTE: PROCEDURE SORT used:
      real time           8.65 seconds
      cpu time            0.79 seconds


493  proc sort data=b;
494    by num;
495  run;

NOTE: There were 111157 observations read from the data set WORK.B.
NOTE: The data set WORK.B has 111157 observations and 2 variables.
NOTE: PROCEDURE SORT used:
      real time           0.21 seconds
      cpu time            0.21 seconds


496
497  data ahuige(drop=num1 num2);
498    set b;
499    retain num1 num2 add;
500    do while (^(num1&lt;=num&lt;=num2) and (point+1&lt;=maxA)) ;
501      point+1;
502      set a point=point nobs=maxA;
503    end;
504    if num^=.;
505  run;

NOTE: There were 111157 observations read from the data set WORK.B.
NOTE: The data set WORK.AHUIGE has 111054 observations and 3 variables.
NOTE: DATA statement used:
      real time           1.78 seconds
      cpu time            0.32 seconds

这个是徐福贵兄的,生成的formats 28.5M

538  data xxx/view=xxx;
539     fmtname = 'tianwild';
540     do until(eof);
541        set a(keep=num1 num2 add rename=(num1=start num2=end add=label)) end=eof;

542        output;
543     end;
544     hlo = 'o';
545     label = '';
546     output;
547     stop;

NOTE: DATA STEP view saved on file WORK.XXX.
NOTE: A stored DATA STEP view cannot run under a different operating system.
NOTE: DATA statement used:
      real time           0.00 seconds
      cpu time            0.00 seconds


548  proc format cntlin=xxx;
NOTE: Format TIANWILD has been output.

NOTE: View WORK.XXX.VIEW used:
      real time           5.07 seconds
      cpu time            0.14 seconds

NOTE: There were 365462 observations read from the data set WORK.A.
NOTE: There were 365463 observations read from the data set WORK.XXX.
NOTE: PROCEDURE FORMAT used:
      real time           5.09 seconds
      cpu time            2.21 seconds


549  data c;
550     set b;
551     city = put(num, tianwild.);
552     if city ne '';
553  run;

NOTE: There were 111157 observations read from the data set WORK.B.
NOTE: The data set WORK.C has 111054 observations and 3 variables.
NOTE: DATA statement used:
      real time           0.71 seconds
      cpu time            0.71 seconds

[quote=&quot;sxlion&quot;:1us8krd3]如果不排序:
...
如果前面的排好序:
...
如果不计排序时间的话,代码2效率高。
[/quote:1us8krd3]
其余这两个的效率不太高,跑了8分钟左右我中止了,没跑完。

第一个
real time:8.65+0.21+1.78=10.64 seconds  
CPU time:0.79+0.21+0.32=1.32 seconds

第二个
real time:0.00+5.09+0.71=5.80 seconds         
CPU time:0.00+2.21+0.71=2.92 seconds


备注:硬件配置 AMD TL-56(1.8G)+2G
作者: shiyiming    时间: 2009-2-14 22:57
标题: Re: 求助:两个数据集的搜寻比较
数据说明一切。

ps:我的那个改进只是代码看上去简洁一点,对速率没有任何帮助。
作者: shiyiming    时间: 2009-2-15 20:33
标题: Re: 求助:两个数据集的搜寻比较
我觉得还是在do循环巧妙使用。
作者: shiyiming    时间: 2009-2-17 17:15
标题: Re: 求助:两个数据集的搜寻比较
还要加上对data步的了解,显然针对这个问题,我代码中的无用循环太多了,消耗了不少资源。
作者: shiyiming    时间: 2009-2-17 17:20
标题: Re: 求助:两个数据集的搜寻比较
严重同意sxlion的观点,以前在看文档时没在意那些东西,现在才发现.....有空还得回去再翻翻那些文档




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