




已阅读5页,还剩10页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
在SAS中我们比较习惯使用DATA步来解决数据处理工作,但是当我们需要处理的是两个以上有关联的数据文件或需要处理的数据观测记录达到百万级别时,DATA步显然不能满足我们的要求。若使用hash散列表(哈希表),把关键字映射到散列表中,通过散列表直接获取需要访问数据的存储地址,可以快速的进行查找、添加等操作。 SAS提供了hash和hiter两种方法处理哈希表,hash提供了查找、修改、添加、删除等方法,hiter提供了用于定位和遍历等方法。1.1 Hash的定义及使用在使用之前需要定义哈希表,如下:Daclare hash myhash;myhash=_new_ hash(); 或者:Declare hash myhash();例如:Daclare hash my_hash;my_hash =_new_ hash();定义了一个名字为my_hash的哈希表。初始化哈希表:declare hash variable_name(argument_tag-1 : value-1);或者:variable_name = _new_ hash(argument_tag-1: value-1);例如:declare hash h(hashexp:4,dataset: work.sales, ordered: yes);定义了一个名字为h的哈希表,并且把work.sales的数据映射到哈希表上;hashexp:4表示哈希表的大小定为2的4次方,ordered: yes表示在哈希表中根据关键字升序排序。语句解读:使用第一种方法定义哈希表时需要注意myhash是定义的表名,其余部分为固定格式。初始化时可选填的项有:Hashexp:n 指定哈希表的大小为,但并不表示观测数。默认为8。Dataset:dataset_name指定需要映射到哈希表的数据集。Ordered:option指定输出到数据集或读取数据时是否排序,option选项如下:Ascending和yes表示根据key升序;Descending表示根据key值降序;no为不做任何操作。此外各选项均可只用首字母代替。duplicate: optionoption选项如下:replace表示遇到相同key时,仅保留最后一条观测;error表示遇到相同的key时,在日志窗口报错multidata: optionoption选项如下:yes表示允许重复的key在哈希表中出现,no则不允许,默认情况为不允许。在定义一个新的哈希表后需要指定哈希表的关键字段等,如下:语句功能DEFINEKEY定义关键字段;DEFINEDATA定义值;DEFINEDONE定义完成;CALL MISSING避免提示变量未初始化哈希表中可以实现较多的操作,语句格式如下:myhash.option();option可选选项句及功能:语句功能FIND查找相同的键值,存在则返回rc=0;ADD添加键值,若hash表中已存在,则不添加;CHECK查找健值,若存在返回rc=0;REPLACE若哈希表中不存在指定的关健字段,则添加;若存在则替换;REMOVE移去哈希表中指定关键字对应的地址等数据;EQUAL判断两个哈希表是否完全相等;OUTPUT将哈希表输出到数据集;REF若查找关键字成功则无操作,若查找不成功则添加关键字,相当于find与add的结合;SETCUR规定一个关键字,用于起始迭代。通常在对数据排序后使用。SUM计算并返回相同key下指定计数变量的和CLEAR清空hash表,但不删除数据;DELETE删除整个哈希表NUM_ITEMS计算哈希表中观测的条数ITEM_SIZE计算哈希表的大小在哈希表中还有如下操作,与上述操作不同的是,使用下列的操作必须在允许哈希表中出现相同的关键字前提下。HAS_NEXT在允许出现相同关键字情况下,是否存在下一条相同关键字的观测FIND_NEXT在允许出现相同关键字情况下,寻找下一条相同关键字的观测FIND_PREV在允许出现相同关键字情况下,寻找前一条相同关键字的观测REMOVEDUP在允许相同关键字出现的情况下,在哈希表中移去当前关键字等数据REPLACEDUP在允许出现相同关键字情况下,使用新的数据代替当前关键字对应的数据等SUMDUP在允许出现相同关键字情况下,计算并返回当前关键字下的指定计数的变量和由于哈希表的定义及操作的语法及使用语句较多,格式较新,下面我们通过一个例子来解释哈希表的定义及简单操作。例5.1定义一个哈希表并对其进行ADD、CHECK、FIND、REMOVE、REPLACE、NUM_ITEMS等操作。程序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=myhash.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 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,data:tomato,data:200);totalitems = myhash.num_items;put totalitems=;myhash.output(dataset:out);run;输出结果为:表1程序5.1输出前后数据集hash_sample数据集out数据集fruitamountfruitamountapple100apple300orange200tomato200tomato300orange200cherry400cherry500cherry500peach500程序解读:程序5.1中把数据集映射到哈希表,并在哈希表中做添加、修改等简单操作,最后输出哈希表。rc为接收返回值,程序中若操作成功则返回0,失败则返回非0。length fruit$ 10;length amount 8;在定义哈希表前,先定义需要映射到哈希表的变量的类型及长度,且必须与数据集中的类型匹配。declare hash myhash(dataset:work.hash_sample ,duplicate: r);定义一个名为myhash的哈希表,并把work.hash_sample的数据集映射到哈希表上;duplicate: r表示相同关键字时数据会不断代替,其结果是哈希表中只有相同关键字的最后一观测的地址,如上例中“cherry 400”将被忽略。rc=myhash.defineKey(fruit);定义关键字段为fruit。rc=myhash.defineData(fruit,amount); 定义数据为fruit和amount,需要注意的是,这里若只定义amount变量,则哈希表中不存在fruit变量,而只是存在其对应的地址,当以需要引用哈希表输出的时候将忽略fruit变量。 rc=myhash.defineDone();表示定义完成。call missing(fruit,amount);当未找到匹配值时,返回空值给指定变量。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: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);移去关键字为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 = myhash.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,multidata: 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();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数据集keysdatakeysdata210021003200240023003200240015003700 程序解读:程序5.2中在允许相同关键字出现的情况下映射到哈希表执行简单操作并输出到数据集。在详细解读程序之前我们需要注意哈希表中向前及往后读取与数据集中的前后相反且可以把表中相同关键字的记录看成循环队列。哈希表的实际存储为二叉树结构,我们不必掌握其顺序,但是我们必须掌握数据读取的先后顺序,为了掌握哈希表“指针”的移动情况,在打印前使用了“”区分每次打印时“指针”的位置。declare hash h(dataset:hash_keys,multidata: y);multidata:y表示允许哈希表中出现相同的关键字记录。rc = h.find();由于关键字段为keys,且最大为3最小为1,我们可以在控制循环的同时对keys赋值,再使用keys在哈希表中查找。此语句为rc = h.find(key:keys);的省略方式。h.has_next(result: r);查找是否存在相同关键字的下一记录,存在则返回非0。rc = h.find_next();查找下一相同关键字的观测,并且“指针”指向该观测。为了更好的理解每个操作在哈希表的运行,我们使用keys=2的数据,按顺序标号,每次操作完后打印“指针”所指的数据记录。 100 300 400 图 1:keys=2时顺序观测记录data的值表3:keys=2时的输出整理keys=2data=100keys=2data=400keys=2data=100keys=2data=400keys=2data=300keys=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(result: r);时,r返回的是0,即哈希表不会把第一条记录当做的下一记录,否则循环则不会停止。跳出do while循环后h.removedup();移去指针所指向的记录,也就是记录,所以我们在输出数据集的时候没有记录。指针的移动可以过程为。通过上例,我们可以发现,在存在相同关键字时,使用has_next语句查找是否存在下一记录控制循环,使用find_next和find_prev移动指针遍历数据。当你需要访问或修改的是相同记录下的某一无数据特征的记录时,此方法非常管用。1.2 Hiter的定义及使用Hiter通常意译为哈希迭代器,通过哈希迭代器遍历哈希表中的关键字和数据。在例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的迭代器,其对应的哈希表为myhash。myiter的操作将在myhash哈希表中进行。遍历哈希表的语句格式如下:variable_name.option();option的选项及功能如下:语句功能FIRST允许出现相同关键字时,在哈希表中取相同关键字观测的第一个观测;LAST允许出现相同关键字时,在哈希表中取相同关键字观测的第二个观测;NEXT允许出现相同关键字时,在相关关键字观测的前提下取当前观测的后一观测;PREV允许出现相同关键字时,在相关关键字观测的前提下取当前观测的前一观测;在不允许关键字重复出现的情况下,由于不需要了解迭代器对哈希表的读取方式,我们只需要根据自己的情况选用FIRST和NEXT、LAST和PREV组合就可以遍历哈希表中的记录。在唯一关键字的哈希表中,我们通常对其排序输出。例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(keys, 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程序解读:在上述程序中选择使用ordered:no不排序,选择last与prev组合遍历哈希表。Last首先查找是否存在多条相同关键字的记录,若不存在则prev查找失败跳出循环;若存在则指向第二条,如keys=3时,第一次打印的是data=200,prev语句查找前已记录成功继续循环,第二次打印的是data=300。可以发现在允许相同关键字出现的情况下哈希迭代器next语句和prev语句读取数据的顺序与find_next和find_prev是一致的。若把multidata: y改成multidata: n且加上duplicate: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(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程序解读:此程序使用了sum函数,对出现相同的关键字进行计数,而不是求和。这此定义哈希表时并没有直接把数据集映射到哈希表,而是通过引用hash_sum表的记录提取关键字及计数信息存储到哈希表,最后使用哈希迭代器及sum函数计数。declare hash myhash(suminc: c, ordered: y);当需要使用sum或sumdup函数计数时,在哈希表中必须定义用来计数的项,suminc: c定义了计数项变量c。需要注意的是c=1只是在每一次引用数据时添加到哈希表。do while (not done);set hash_sum end=done;rc = myhash.ref();end;通过set语句每次读取hash_sum数据集中的一条观测,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和哈希迭代器遍历哈希表,同时使用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.6 1 5.5 1 5.4 1 5.8 1 5.72 5.9 2 6.0 2 5.2 2 4.3 2 5.93 5.5 3 7.0 3 4.4 3 5.5 3 5.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 done);set data1 end=done;rc=myhash.ref();end;do while(not last);set data2 end=last;rc=myhash.find();if rc=0 and actualstd then do;count+1;myhash.replace();output;end; end;myhash.output(dataset:result2);run;输出结果:表6:程序5.6输出结果整理result1数据集result2数据集idstdactualcountidstdcount15.55.6115.5315.55.8225.8315.55.7335.9125.85.9125.86225.85.9335.971程序解读: 程序中先建立一个空的哈希表,再把data1数据集映射到该哈希表,接着用过引用data2数据集找到对应关键字并判断、计数、输出。结果输出了两个数据集,result1为满足要求的全部记录,而result2为最后哈希表存储的信息。在定义哈希表时并不直接把数据集映射到哈希表,原因是需要映射到哈希表中的data1数据集中没有我们需要存储计数的变量count,此时可以建立一个空的哈希表,里面包含需要输出的变量。输出结果中result1数据集是由output语句输出的,result2数据集是myhash.output(dataset:result2)语句输出的,可以发现,result1数据集包含了哈希表的内容及data2中actual变量的数据,而result2数据集只包含了哈希表定义的变量及最后计数的结果。其结果的不同时由于哈希表中不存在定义变量以外的信息,且默认定义不允许相同的关键字存在。查看数据的结构可以发现data1数据集中的id是唯一的,data2数据集中的id是重复出现的,在此类问题中,较好的处理方式是把id是唯一的数据集映射到哈希表,通过set引用重复出现id的数据集进行数据处理。 例5.5中设计两个数据集的连接,其中有一个是存在唯一关键字的,若需要处理的数据集的关键字都不唯一,则使用如下方法。例5.6连接data1、data2数据集,并求kind下所有id变量 amt的总和。表7:原始数据data1数据集data2数据集kindididamta1150a2240b1230b3330c2c3 程序5.6data data1;input kind$ id$;cards;a 1 a 2 b 1 b 3 c 2 c 3 ;run;data data2;input id$ amt;cards;1 502 402 303 30;run;data result1;length kind$ 8 id$ 8;if _n_=1 then do;declare hash h1(dataset: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(result: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 then do;total+amt;h2.replace();end;else do;total=amt;h2.add();end;end;h2.output(dataset:result2);run;输出结果整理:表8:程序5.6输出结果整理result1数据集result2数据集kindidamtkindtotala150a120a230b80a240c100b150b330c230c240c330程序解读:程序分为两部分,第一部分为连接数据集,输出为result1,第二部分为以kind分组对amt变量求和。第一部分中由于要求连接后的数据集存在变量amt,而映射到哈希表的data1数据集中并不存在,则选择每连接一个相同的关键字就输出到指定的数据集。由于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. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 出租屋管理安全培训课件
- 文库发布:出师表课件
- 出国安全培训制度课件
- 2025年长期供货合同范本-涂料供应合同
- 出口许可证课件
- 冲积扇形成原因课件
- 2025全新升级计算机辅助卓越二手房买卖中介服务合同
- 2025农药买卖合同(除草剂)
- 2025上海市地方标准《融资租赁服务合同规范》编制说明
- 2025合同样本:健身房合作经营合同律师起草专业版
- 2025版食堂承包合同补充协议模板(含财务管理)
- 大学生家教服务合同范本
- 新教科版科学六年级上册全册表格式核心素养目标教案 (一)
- 小学道德与法治教师考试题及答案
- 2025年燃气送气服务人员考试题库及答案
- 2025-2026学年第一学期九年级开学第一课:收心班会课件
- 工程质量管理存在问题及管理措施
- 2025秋湘科版(2024)一年级上册科学教学计划
- 血压基础护理讲解
- 厂房建筑结构设计方案
- Unit1单元复习课件人教版八年级英语上册
评论
0/150
提交评论