sashash简介与实例_第1页
sashash简介与实例_第2页
sashash简介与实例_第3页
sashash简介与实例_第4页
sashash简介与实例_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、在SAS中我们比较习惯使用DAT“来解决数据处理工作,但是当我们需要处理的是两个以上有关联的数据文件或需要处理的数据观测记录达到百万级别时,DATA显然不能满足我们的要求。若使用hash散列表(哈希表),把关键字映射到散列表中,通过散列表直接获取需要访问数据的存储地址,可以快速的进行查找、添加等操作。SAS 提供了 hash 和 hiter 两种方法处理哈希表, hash 提供了查找、修改、添加、删除等方法, hiter 提供了用于定位和遍历等方法。1.1 Hash 的定义及使用在使用之前需要定义哈希表,如下:Daclare hash myhash;myhash=_new_ hash();或者

2、: Declare hash myhash();例如:Daclare hash my_hash;my_hash =_new_ hash(); 定义了一个名字为 my_hash的哈希表。初始化哈希表:declarehashvariable_name(argument_tag-1:value-1<, .argument_tag-n: value-n>);或者:variable_name= _new_hash(argument_tag-1:value-1<, .argument_tag-n: value-n>);例如: declare hash h(hashexp : 4,d

3、ataset: 'work.sales', ordered: 'yes');定义了一个名字为h的哈希表,并且把 work.sales 的数据映射到哈希表上;hashexp: 4表示哈希表的大小定为 2的4次方,ordered: 'yes'表示在哈希表中根据关键字升序排序。语句解读:使用第一种方法定义哈希表时需要注意myhash是定义的表名,其余部分为固定格式初始化时可选填的项有:Hashexp:n指定哈希表的大小为2n,但并不表示观测数。默认为8。Dataset:'dataset_name'指定需要映射到哈希表的数据集。Order

4、ed: ' option '指定输出到数据集或读取数据时是否排序,option 选项如下:Ascending 和 yes 表示根据 key 升序;Descending 表示根据key值降序;no为不做任何操作。此外 各选项均可只用首字母代替。duplicate:' option ' option 选项如下:replace 表示遇至U相同 key 时,仅保留最后一条观测;error表示遇到相同的key时,在日志窗口报错multidata:' option '' option ' 选项如下: yes 表示允许重复的key在哈希表中出现

5、,no则不允许,默认情况为不允许。在定义一个新的哈希表后需要指定哈希表的关键字段等,如下:语句功能DEFINEKEY定义关键字段;DEFINEDATA 定义值;DEFINEDONE 定义完成;CALL MISSING避免提示变量未初始化哈希表中可以实现较多的操作,语句格式如下:myhash.' option '();option可选选项句及功能:语句功能FIND查找相同的键值,存在则返回rc=0;ADD添加键值,若hash表中已存在,则不添加;CHECK查找健值,若存在返回 rc=0;REPLACE若哈希表中不存在指定的关健字段,则添加;若存在则替换;REMOVE移去哈希表中指

6、定关键字对应的地址等数据;EQUAL判断两个哈希表是否完全相等;OUTPUT将哈希表输出到数据集;REF若查找关键字成功则无操作,若查找不成功则添加关键字,相当于find与add的结合;SETCUR规定一个关键字,用于起始迭代。通常在对数据排序后使用。SUM计算并返回相同key下指定计数变量的和CLEAR清空hash表,但不删除数据;DELETE删除整个哈希表NUM_ITEMS计算哈希表中观测的条数ITEM_SIZE计算哈希表的大小在哈希表中还有如下操作, 与上述操作不同的是,使用下列的操作必须在允许 哈希表中出现相同的关键字前提下。HAS_NEXT在允许出现相同关键字情况下,是否存在下一条相

7、同关键字的观测FIND_NEXT在允许出现相同关键字情况下,寻找下一条相同关键字的观测FIND_PREV在允许出现相同关键字情况下,寻找前一条相同关键字的观测REMOVEDUP 在允许相同关键字出现的情况下,在哈希表中移去当前关键字等数据REPLACEDUP在允许出现相同关键字情况下,使用新的数据代替当前关键字对应的数据等SUMDUP在允许出现相同关键字情况下,计算并返回当前关键字下的指定计数的变量和由于哈希表的定义及操作的语法及使用语句较多,格式较新,下面我们通过一个例子来解释哈希表的定义及简单操作。例5.1定义一个哈希表并对其进行 ADD CHECK FIND、REMOVEREPLACEN

8、UM_ITEM等操作。程序 5.1data hash_sample;input fruit$ amount;cards;apple 100orange 200tomato 300cherry 400cherry 500;run;data _null_;length fruit$ 10;length amount 8;if _N_=1 then do;declare hash myhash(dataset:'work.hash_sample' ,duplicate: "r");rc=myhash.defineKey('fruit');rc=my

9、hash.defineData('fruit','amount');rc=myhash.defineDone();call missing(fruit,amount);end;rc=myhash.add(key:'peach',data:'peach',data:500);rc=myhash.find(key:'peach');if rc=0 then put fruit= amount=;rc=myhash.check(key:'orange');if rc=0 then put 'the

10、 orange is exist'rc=myhash.remove(key:'tomato');if rc=0 then put 'tomato is not exist'rc=myhash.replace(key:'apple',data:'apple',data:300);if rc=0 then do;rc=myhash.find(key:'apple');if rc=0 then put fruit= amount=;end;rc=myhash.ref(key:'tomato',da

11、ta:'tomato',data:200);totalitems = myhash.num_items;put totalitems=;myhash.output(dataset:'out');run;输出结果为:表1程序5.1输出前后数据集hash_sample 数据集out数据集fruitamountfruitamountapple100apple300orange200tomato200tomato300orange200cherry400cherry500cherry500peach500程序解读:程序5.1中把数据集映射到哈希表,并在哈希表中做添加、修

12、改等简单操作,最后输出哈希表。rc为接收返回值,程序中若操作成功则返回0,失败则返回非0length fruit$ 10;length amount 8;在定义哈希表前,先定义需要映射到哈希表的变量的类型及长度,且必须与数据集中的类型匹配。declare hash myhash(dataset:'work.hash_sample' duplicate: "r");定义一个名为myhash的哈希表,并把work.hash_sample的数据集映射到哈 希表上;duplicate: "r"表示相同关键字时数据会不断代替,其结果是哈希表中只有相

13、同关键字的最后一观测的地址,如上例中“ cherry 400 ”将被忽略。rc=myhash.defineKey('fruit');定义关键字段为 fruit 。rc=myhash.defineData('fruit','amount');定义数据为 fruit 和 amount,需要注意的是,这里若只定义 amount变量,则哈希表中不存在fruit变量,而只 是存在其对应的地址,当以需要引用哈希表输出的时候将忽略fruit变量。rc=myhash.defineDone();表示定义完成。call missing(fruit,amount);当

14、未找到匹配值时,返回空值给指定变量。myhash.add(key:'peach',data:'peach',data:500);在哈希表中增加一关键字为peach的记录,若已经存在则忽略。由于定义时数据项为fruit 和amount,则增加记录时必须对应全部罗列出来。且amount为数值型,则500无单引号。rc=myhash.find(key:'peach');if rc=0 then put fruit= amount=;查找关键字为peach的记录,若存在返回0,使用if then打印查看详细信息。rc=myhash.check(key:&

15、#39;orange'); if rc=0 then put 'the orange is exist'查找关键字为 orange 的记录,使用 if then 打印指定字符。你或许会疑惑为什么不直接打印 orange 的详细信息?其实这就是check 和 find 的区别,可以理解为指针的形式, find 不仅找到而且指针指向 find 的记录, 而 check 只是查看有没有,并不移动指针,所以如果把if then 指定的打印字符换成输出信息,则输出的仍为 peach 的信息。rc=myhash.remove(key:'tomato'); 移去关键字

16、为 tomato 的记录信息。rc=myhash.replace(key:'apple',data:'apple',data:300);替换关键字为apple的记录信息。由于replace和check 一样不会使指针移动,则可以先使用 find再打印查看是否替换成功。rc=myhash.ref(key:'tomato',data:'tomato',data:200);若查找关键字tomato成功则无操作,若查找不成功则添加关键字等信息,相当于find与add的结合。需要注意的是ref 同样不移动指针。totalitems = my

17、hash.num_items; 计算哈希表中观测的数量并赋值给totalitems 。myhash.output(dataset:'out'); 把哈希表的信息输出到 out 数据集。 例 5.2 在允许关键字重复出现情形下进行简单操作。 程序 5.2data hash_keys;input keys data;cards;2 1003 2002 3002 4001 5003 600;run;data _null_;length keys data 8;if _N_ = 1 then do;declare hash h(dataset:'hash_keys',m

18、ultidata: 'y');h.definekey('keys');h.definedata('keys', 'data');h.definedone();call missing (keys, data);end;do keys=1 to 3;rc = h.find();put '' keys= data=;h.has_next(result: r);do while(r ne 0);rc = h.find_next();put '' keys= data=;rc = h.find_prev()

19、;put '' keys= data=;rc = h.find_next();put '' keys= data=;h.has_next(result: r);end;h.removedup();end;h.output(dataset:'hash_out');run;输出结果:表2程序5.2数据集整理hash_keys数据集hash_out数据集keysdatakeysdata21002100320024002300320024001500700程序解读:程序5.2中在允许相同关键字出现的情况下映射到哈希表执行简单操作并输 出到数据集。在详细解

20、读程序之前我们需要注意哈希表中向前及往后读取与数据 集中的前后相反且可以把表中相同关键字的记录看成循环队列。哈希表的实际存 储为二叉树结构,我们不必掌握其顺序,但是我们必须掌握数据读取的先后顺序, 为了掌握哈希表“指针”的移动情况,在打印前使用了 “ 区分每次打印时“指针”的位置。declare hash h(dataset:'hash_keys',multidata: 'y');multidata: 'y' 表示允许哈希表中出现相同的关键字记录。rc = h.find();由于关键字段为keys ,且最大为3最小为1,我们可以在控制循 环的同时

21、对keys赋值,再使用keys在哈希表中查找。此语句为rc = h.find(key:keys);的省略方式。h.has_next(result:r);查找是否存在相同关键字的下一记录,存在则返回非00rc = h.find_next();查找下一相同关键字的观测,并且“指针”指向该观测。为了更好的理解每个操作在哈希表的运行,我们使用keys=2的数据,按顺序标号,每次操作完后打印“指针”所指的数据记录。图1 : keys=2时顺序观测记录data的值keys=2data=100keys=2data=400keys=2data=100keys=2data=400keys=2data=300ke

22、ys=2data=400keys=2data=300当keys=2时,h.find指向记录并打印; 接下来h.has_next查看是否存在下一 记录,成功返回0,而在哈希表中的下一记录并不是,而是,此时指针并没 有移动到;进入do while第一次循环后h.find_next把指针移动到并打印; h.find_prev语句把指针往前移,但这里并不是把移动到,而是移动到,打 印;第二句h.find_next再次把指针移动到;最后h.has_next查找是否存在下一 记录,此时为的记录,存在则继续循环。在执行到第二次循环的h.has_next前时,指针指向的是,当读到 h.has_next(res

23、ult: r); 时,r返回的是0,即哈 希表不会把第一条记录当做的下一记录,否则循环则不会停止。跳出do while循环后h.removedup();移去指针所指向的记录,也就是记录,所以我们在输出 数据集的时候没有记录。指针的移动可以过程为""""""。通过上例,我们可以发现,在存在相同关键字时,使用has_next语句查找是否存在下一记录控制循环,使用 find_next和find_prev移动指针遍历数据。当你需 要访问或修改的是相同记录下的某一无数据特征的记录时,此方法非常管用。1.2 Hiter的定义及使用Hiter通常意

24、译为哈希迭代器,通过哈希迭代器遍历哈希表中的关键字和数据。在例5.2中的遍历仅限于在相同关键字下遍历,而在哈希迭代器中没有此项 要求。在使用之前需要定义哈希表,如下:Declare hiter variable_name(hash_object_name);或者:Declare hiter variable_name;variable_name = _new_ hiter(hash_object_name);例如:declare hiter myiter ('myhash');定义了一个名字为 myiter 的迭代器,其对应的哈希表为 myhasho myiter的操作将在 m

25、yhash哈希表中进行。遍历哈希表的语句格式如下:variable_name. ' option '();option的选项及功能如下:语句功能FIRST允许出现相同关键字时,在哈希表中取相同关键字观测的第一个观测;LAST允许出现相同关键字时,在哈希表中取相同关键字观测的第二个观测;NEXT允许出现相同关键字时,在相关关键字观测的前提卜取当前观测的后一观测;PREV允许出现相同关键字时,在相关关键字观测的前提卜取当前观测的前一观测;在不允许关键字重复出现的情况下,由于不需要了解迭代器对哈希表的读取方式,我们只需要根据自己的情况选用FIRST和NEXT LAST和PREVm合就

26、可以遍历哈希表中的记录。在唯一关键字的哈希表中,我们通常对其排序输出。 例 5.3 使用哈希迭代器遍历例 5.2 的数据,并输出到数据集。 程序 5.3data hiter_keys;length keys data 8;if _N_ = 1 then do;declare hash h(dataset:'hash_keys',multidata:'y',ordered:'no');declare hiter my_hiter('h');h.definekey('keys');h.definedata('k

27、eys', 'data');h.definedone();call missing (keys, data);end;rc=my_hiter.last();do while(rc = 0);put keys= data=;output;rc=my_hiter.prev();end;rc=h.clear();run;输出结果为:表4:程序5.3输出结果整理hash_keys数据集hiter_keys 数据集keysdatakeysdata3100430054003200220033001500310043001100320015001100540033002200程序解读

28、:在上述程序中选择使用 ordered:no'不排序,选择last与prev组合遍历哈希表。Last首先查找是否存在多条相同关键字的记录,若不存在则prev查找失败跳出循环;若存在则指向第二条,如 keys=3时,第一次打印的是data=200 , prev语 句查找前已记录成功继续循环,第二次打印的是data=300。可以发现在允许相同关键字出现的情况下哈希迭代器next语句和prev语句读取数据的顺序与 find_next 和find_prev 是一致的。若把 multidata: 'y' 改成 multidata: 'n' 且加 上duplicat

29、e : replace时,哈希表中不再出现重复记录且对与每个关键字仅存最后一条记录。1.3 综合应用 例 5.4 使用哈希表计数。 程序 5.4data hash_sum;input keys;cards;1 1 5 3 43 6 4 1 5;run;data hash_count;length c keys 8;if _n_ = 1 then do;declare hash myhash(suminc: "c", ordered: "y");declare hiter iter("myhash");myhash.defineKey(

30、'keys');myhash.defineDone();c = 1;end;do while (not done);set hash_sum end=done;rc = myhash.ref();end;rc = iter.first();do while(rc = 0);rc = myhash.sum(sum: c);output;rc = iter.next();end;stop;run;输出结果:表5:程序5.4输出结果ckeys3123242516程序解读:此程序使用了 sumg数,对出现相同的关键字进行计数,而不是求和。这此定义哈希表时并没有直接把数据集映射到哈希表,

31、而是通过引用hash_sum表的记录提取关键字及计数信息存储到哈希表,最后使用哈希迭代器及sumS数计数。declare hash myhash(suminc: "c", ordered: "y");当需要使用 sunlgsumdup函数计数时,在哈希表中必须定义用来计数的项,suminc: "c" 定义了计数项变量c 。需要注意的是c=1 只是在每一次引用数据时添加到哈希表。do while (not done);set hash_sum end=done;rc = myhash.ref();end;通过set语句每次读取hash_

32、sun#据集中的一条观测,end=last指定当读到最 后一条记录是done=0并控制do循环。在每读取一条观测时, myhash.ref()语句自 动把数据集中的 keys 当做关键字查找哈希表中是否存在相同关键字的数据,若存在则不操作,若不存在则添加。而不管是否存在相同的关键字,c=1都会伴随着查找写入哈希表。虽然哈希表中仅有5个关键字,但c=1可以不断写入,最后通过对c求和即可完成。rc = iter.first();do while(rc = 0);rc = myhash.sum(sum: c);output;rc = iter.next();end;使用do while和哈希迭代器遍

33、历哈希表,同时使用myhash.sum函数对哈希表中每个关键字的c逐一计数并output到hash_count数据集。1.4 哈希表及迭代器的的应用 例 5.5 在实际应用哈希表时常遇到两个关联数据集处理问题。若一个表(data1) 中每个 id 的标准值 std ,另一个表(data2) 中为每个 id 的实际值,使用hash 输出 data2 中比标准值大的观测及个数。 程序 5.5data data1;input id std ;cards;1 5.5 2 5.8 3 5.9;run;data data2;input id actual;cards;1 5.61 5.51 5.4 15.

34、8 15.72 5.92 6.02 5.2 24.3 25.93 5.53 7.03 4.4 35.5 35.4;run;data result1;if _n_=1 then do;declare hash myhash(ordered:'y');myhash.definekey('id');myhash.definedata('id','std','count');myhash.definedone();call missing(std,count,actual);count=0;end;do while(not

35、 done);set datal end=done;rc=myhash.ref();end;do while(not last);set data2 end=last;rc=myhash.find();if rc=0 and actual>std then do;count+1;myhash.replace();output;end;end;myhash.output(dataset:'result2');run;输出结果:表6:程序5.6输出结果整理result1 数据集result2 数据集idstdactualcountidstdcount15.55.6115.53

36、15.55.8225.8315.55.7335.9125.85.9125.86225.85.9335.971程序解读:程序中先建立一个空的哈希表,再把datal数据集映射到该哈希表,接着用过引用data2数据集找到对应关键字并判断、计数、输出。结果输出了两个数据 集,resultl为满足要求的全部记录,而 result2为最后哈希表存储的信息。在定义哈希表时并不直接把数据集映射到哈希表,原因是需要映射到哈希表中的datal数据集中没有我们需要存储计数的变量count ,此时可以建立一个空的哈希表,里面包含需要输出的变量。输出结果中 resultl数据集是由output语句输 出的,result

37、2 数据集是 myhash.output(dataset:'result2') 语句输出的,可以 发现,resultl数据集包含了哈希表的内容及data2中actual变量的数据,而result2数据集只包含了哈希表定义的变量及最后计数的结果。其结果的不同时由于哈希表中不存在定义变量以外的信息,且默认定义不允许相同的关键字存在。 查看数据的结构可以发现datal数据集中的id是唯一的,data2数据集中的id是重复出现的,在此类问题中,较好的处理方式是把 id是唯一的数据集映射到哈希表,通过set引用重复出现id的数据集进行数据处理例5.5中设计两个数据集的连接,其中有一个是存

38、在唯一关键字的,amt的总和。处理的数据集的关键字都不唯一,则使用如下方法。例5.6连接data1、data2数据集,并求kind下所有id变量表7:原始数据data1数据集data2数据集kindididamta1150a2240b1230b3330c2c3程序5.6 data datal;input kind$ id$;cards;run;data data2;input id$ amt;cards;150240230330;run;data result1;length kind$ 8 id$ 8;if _n_=1 then do;declare hash h1(dataset:'

39、;data1',ordered:'y', multidata: 'y');h1.definekey('id');h1.definedata('id','kind');h1.definedone();call missing(id,kind);end;do while(not last1);set data2 end=last1;h1.find();output;h1.has_next(result:r);do while(r ne 0);h1.find_next();output;h1.has_next(r

40、esult:r);end;end;run;data _null_;length kind$ 8 id$ 8;if _n_=1 then do;declare hash h2(ordered:'y');h2.definekey('kind');h2.definedata('id','kind','total');h2.definedone();call missing(id,kind,total);end;do while(not done);set result1 end=done;if h2.find()=0 t

41、hen do;total+amt;h2.replace();end;else do;total=amt;h2.add();end;end;h2.output(dataset:'result2');run;输出结果整理:表8:程序5.6输出结果整理resultl 数据集result2 数据集kindidamtkindtotala150a120a230b80a240c100b150b330c230c240c330程序解读:程序分为两部分, 第一部分为连接数据集, 输出为 result1 , 第二部分为以 kind分组对 amt 变量求和。第一部分中由于要求连接后的数据集存在变量am

42、t,而映射到哈希表的datal数据集中并不存在,则选择每连接一个相同的关键字就输出到指定的数据集。由于 set data2 语句相当于遍历data2 数据集,则每读取data2 中的一条记录,则与哈希表连接查找相同的关键字并使用 output 输出, 输出后继续查找是否存在下一个相同的关键字, 若存在则输出, 直到查找完毕, 不存在则退出循环读取data2的下一条记录。 这里不使用 h1.output() 语句是因为我们需要的是每次查找成功的记录且包含 amt 变量的数据集,而此处哈希表中仅存在data2 的数据。第二部分为以 kind 为关键字段对所有 id 下的 amt 求和,由于此处只需要求和的结果而不是像第一部分需要的是每次连接的结果,选择使用 h2.output 语句输出哈希表的内容。接下来我们只需定义一个不允许相同关键字出现的哈希表,每读取 result1 中的一条记录,查找哈希表中是否存在相同关键字,若存在相同关键字更新求和变量,若不存在则赋值到求和变量更加到哈希表即可,最后输出哈希表。 此处需要注

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论