首页 sashash简介与实例

sashash简介与实例

举报
开通vip

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

sashash简介与实例
在SAS中我们比较习惯使用DATA步来解决数据处理工作,但是当我们需要处理的是两个以上有关联的数据文件或需要处理的数据观测 记录 混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载 达到百万级别时,DATA步显然不能满足我们的要求。若使用hash散列 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf (哈希表),把关键字映射到散列表中,通过散列表直接获取需要访问数据的存储地址,可以快速的进行查找、添加等操作。hash提供了查找、修改、添加、删SAS提供了hash和hiter两种方法处理哈希表,除等方法,hiter提供了用于定位和遍历等方法。1.1Hash的定义及使用在使用之前需要定义哈希表,如下:Daclarehashmyhash;myhash=_new_hash();或者:Declarehashmyhash();例如:定义了一个名字为my_hash的哈希value-1<,...argument_tag-n:Daclarehashmy_hash;my_hash=_new_hash();表。初始化哈希表:declarehashvariable.name(argument_tag-1value-n>);或者:variable.name=_new_hash(argument_tag-1:value-1<,...argument_tag-n:value-n>);例如:declarehashh(hashexp:4,dataset:'work.sales',ordered:'yes');定义了一个名字为h的哈希表,并且把work.sales的数据映射到哈希表上;hashexp:4表示哈希表的大小定为2的4次方,ordered:'yes'表示在哈希表中根据关键字升序排序。语句解读:使用第一种方法定义哈希表时需要注意myhash是定义的表名,其余部分为固定格式。初始化时可选填的项有:Hashexp:n指定哈希表的大小为2n,但并不表示观测数。默认为Dataset:'dataset_name'指定需要映射到哈希表的数据集Ordered:'optionduplicate:'optionmultidata:'option指定输出到数据集或读取数据时是否排序,option选项如下:Ascending和yes表示根据key升序;Descending表示根据key值降序;no为不做任何操作。此外各选项均可只用首字母代替。option选项如下:replace表示遇到相同key时,仅保留最后一条观测;error表示遇到相同的key时,在日志窗口报错'option'选项如下:yes表示允许重复的key在哈希表中出现,no则不允许,默认情况为不允许。在定义一个新的哈希表后需要指定哈希表的关键字段等,如下:语句DEFINEKEYDEFINEDATADEFINEDONECALLMISSING功能定义关键字段;定义值;定义完成;避免提示变量未初始化哈希表中可以实现较多的操作,语句格式如下: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计算哈希表中观测的条数ITEMSIZE计算哈希表的大小在哈希表中还有如下操作,与上述操作不同的是,使用下列的操作必须在允许哈希表中出现相同的关键字前提下HAS_NEXT在允许出现相同关键字情况下,是否存在下一条相同关键字的观测FIND_NEXT在允许出现相同关键字情况下,寻找下一条相同关键字的观测FIND_PREV在允许出现相同关键字情况下,寻找前一条相同关键字的观测REMOVEDUP在允许相同关键字出现的情况下,在哈希表中移去当前关键字等数据REPLACEDUP在允许出现相同关键字情况下,使用新的数据代替当前关键字对应的数据等SUMDUP在允许出现相同关键字情况下,计算并返回当前关键字下的指定计数的变量和由于哈希表的定义及操作的语法及使用语句较多,格式较新,下面我们通过一个例子来解释哈希表的定义及简单操作。[例5.1]定义一个哈希表并对其进行ADDCHECKFINDREMOV駅EPLACENUM_ITEMS等操作。[程序5.1]datahash_sample;inputfruit$amount;cards;apple100orange200tomato300cherry400cherry500Jrun;data_null_;lengthfruit$10;lengthamount8;if_N_=1thendo;declarehashmyhash(dataset:'work.hash_sample'‘duplicate:"r");rc=myhash.defineKey('fruit');rc=myhash.defineData('fruit','amount');rc=myhash.defineDone();callmissing(fruit,amount);end;rc=myhash.add(key:'peach',data:'peach',data:500);rc=myhash.find(key:'peach');ifrc=0thenputfruit=amount=;rc=myhash.check(key:'orange');ifrc=0thenput'theorangeisexist';rc=myhash.remove(key:'tomato');ifrc=0thenput'tomatoisnotexist';rc=myhash.replace(key:'apple',data:'apple',data:300);ifrc=0thendo;rc=myhash.find(key:'apple');ifrc=0thenputfruit=amount=;end;rc=myhash.ref(key:'tomato',data:'tomato',data:200);totalitems=myhash.num_items;puttotalitems=;myhash.output(dataset:'out');run;输出结果为:表1程序5.1输出前后数据集hashsample数据集out数据集fruitamountfruitamountapple100apple300orange200tomato200tomato300oranger200「cherry400cherry500cherry500peach500程序解读:程序5.1中把数据集映射到哈希表,并在哈希表中做添加、修改等简单操作,最后输出哈希表。rc为接收返回值,程序中若操作成功则返回0,失败则返回非0。lengthfruit$10;lengthamount8;在定义哈希表前,先定义需要映射到哈希表的变量的类型及长度,且必须与数据集中的类型匹配。declarehashmyhash(dataset:'work.hash_sample'‘duplicate:"r");定义一个名为myhash的哈希表,并把work.hash_sample的数据集映射到哈希表上;duplicate:"r"表示相同关键字时数据会不断代替,其结果是哈希表中只有相同关键字的最后一观测的地址,如上例中“cherry400”将被忽略。rc=myhash.defineKey('fruit');定义关键字段为fruit。rc=myhash.defineData('fruit','amount');定义数据为fruit和amount,需要注意的是,这里若只定义amount变量,则哈希表中不存在fruit变量,而只是存在其对应的地址,当以需要引用哈希表输出的时候将忽略fruit变量。rc=myhash.defineDone();表示定义完成。callmissing(fruit,amount);当未找到匹配值时,返回空值给指定变量。myhash.add(key:'peach',data:'peach',data:500);在哈希表中增加一关键字为peach的记录,若已经存在则忽略。由于定义时数据项为fruit和amount,则增加记录时必须对应全部罗列出来。且amount为数值型,则500无单引号。rc=myhash.find(key:'peach');ifrc=0thenputfruit=amount=;查找关键字为peach的记录,若存在返回0,使用ifthen打印查看详细信息。rc=myhash.check(key:'orange');ifrc=0thenput'theorangeisexist';查找关键字为orange的记录,使用ifthen打印指定字符。你或许会疑惑为什么不直接打印orange的详细信息?其实这就是check和find的区别,可以理解为指针的形式,find不仅找到而且指针指向find的记录,而check只是查看有没有,并不移动指针,所以如果把ifthen指定的打印字符换成输出信息,则输出的仍为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.2]datahash_keys;inputkeysdata;cards;210032002300240015003600run;data_null_;lengthkeysdata8;if_N_=1thendo;declarehashh(dataset:'hash_keys',multidata:'y');h.definekey('keys');h.definedata('keys','data');h.definedone();callmissing(keys,data);end;dokeys=1to3;rc=h.find();put@keys=data=;h.has_next(result:r);dowhile(rne0);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数据集整理hashkeys数据集hashout数据集keysdatakeysdata21002I10032002[40023003P20024001:5003700程序解读:程序5.2中在允许相同关键字出现的情况下映射到哈希表执行简单操作并输出到数据集。在详细解读程序之前我们需要注意哈希表中向前及往后读取与数据集中的前后相反且可以把表中相同关键字的记录看成循环队列。哈希表的实际存储为二叉树结构,我们不必掌握其顺序,但是我们必须掌握数据读取的先后顺序,为了掌握哈希表“指针”的移动情况,在打印前使用了“@区分每次打印时“指针”的位置。declarehashh(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的数据,按顺序标号,每次操作完后打印“指针”所指的数据记录。图1:keys=2时顺序观测记录data的值表3:keys=2时的输出整理@keys=2data=100①@@keys=2data=400③@@@keys=2data=100①@@@@keys=2data=400③「@@keys=2data=300②@@@keys=2data=400③1@@@@keys=2data=300②当keys=2时,h.find指向①记录并打印;接下来h.has_next查看是否存在下一记录,成功返回0,而在哈希表中①的下一记录并不是②,而是③,此时指针并没有移动到③;进入dowhile第一次循环后h.find_next把指针移动到③并打印;h.find_prev语句把指针往前移,但这里并不是把③移动到②,而是移动到①,打印;第二句hfind_next再次把指针移动到③;最后h.has_next查找是否存在下一记录,此时②为③的记录,存在则继续循环。在执行到第二次循环的h.has_next前时,指针指向的是②,当读到h.has_next(result:r);时,r返回的是0,即哈希表不会把第一条记录①当做②的下一记录,否则循环则不会停止。跳出dowhile循环后h.removedup();移去指针所指向的记录,也就是记录②,所以我们在输出数据集的时候没有记录②。指针的移动可以过程为①f③f①f③f②f③f②。通过上例,我们可以发现,在存在相同关键字时,使用has_next语句查找是否存在下一记录控制循环,使用find_next和find_prev移动指针遍历数据。当你需要访问或修改的是相同记录下的某一无数据特征的记录时,此方法非常管用。1.2Hiter的定义及使用Hiter通常意译为哈希迭代器,通过哈希迭代器遍历哈希表中的关键字和数据。在例5.2中的遍历仅限于在相同关键字下遍历,而在哈希迭代器中没有此项要求。在使用之前需要定义哈希表,如下:Declarehitervariable.name(hash_object_name);或者:Declarehitervariable.name;variable.name=_new_hiter(hash_object_name);例如:declarehitermyiter('myhash');定义了一个名字为myiter的迭代器,其对应的哈希表为myhash。myiter的操作将在myhash哈希表中进行遍历哈希表的语句格式如下:variable.name.'option'();option的选项及功能如下:语句功能FIRST允许出现相同关键字时,在哈希表中取相同关键字观测的第一个观测;LAST允许出现相同关键字时,在哈希表中取相同关键字观测的第二个观测;NEXT允许出现相同关键字时,在相关关键字观测的前提下取当前观测的后一观测;PREV允许出现相同关键字时,在相关关键字观测的前提下取当前观测的前一观测;在不允许关键字重复出现的情况下,由于不需要了解迭代器对哈希表的读取方式,我们只需要根据自己的情况选用FIRST和NEXTLAST和PRE\组合就可以遍历哈希表中的记录。在唯一关键字的哈希表中,我们通常对其排序输出。[例5.3]使用哈希迭代器遍历例5.2的数据,并输出到数据集。[程序5.3]datahiter_keys;lengthkeysdata8;if_N_=1thendo;declarehashh(dataset:'hash_keys',multidata:'y',ordered:'no');declarehitermy_hiter('h');h.definekey('keys');h.definedata('keys','data');h.definedone();callmissing(keys,data);end;rc=my_hiter.last();dowhile(rc=0);putkeys=data=;output;rc=my_hiter.prev();end;rc=h.clear();run;输出结果为:表4:程序5.3输出结果整理hashkeys数据集hiterkeys数据集keysdatakeysdata31004300540032002:2003300:15003100430011003200150011005P400「33002200程序解读:在上述程序中选择使用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.4]datahash_sum;inputkeys@@;cards;153436415run;datahash_count;lengthckeys8;if_n_=1thendo;declarehashmyhash(suminc:"c",ordered:"y");declarehiteriter("myhash");myhash.defineKey('keys');myhash.defineDone();c=1;end;dowhile(notdone);sethash_sumend=done;rc=myhash.ref();end;rc=iter.first();dowhile(rc=0);rc=myhash.sum(sum:c);output;rc=iter.next();end;stop;run;输出结果:表5:程序5.4输出结果ckeys31232425:16程序解读:此程序使用了sum函数,对出现相同的关键字进行计数,而不是求和。这此定义哈希表时并没有直接把数据集映射到哈希表,而是通过引用hash_sum表的记录提取关键字及计数信息存储到哈希表,最后使用哈希迭代器及sumS数计数。declarehashmyhash(suminc:"c",ordered:"y");当需要使用sum或sumdu函数计数时,在哈希表中必须定义用来计数的项,suminc:"c"定义了计数项变量c。需要注意的是c=1只是在每一次引用数据时添加到哈希表。dowhile(notdone);sethash_sumend=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();dowhile(rc=0);rc=myhash.sum(sum:c);output;rc=iter.next();end;使用dowhile和哈希迭代器遍历哈希表,同时使用myhash.sum函数对哈希表中每个关键字的c逐一计数并output到hash_count数据集。1.4哈希表及迭代器的的应用[例5.5]在实际应用哈希表时常遇到两个关联数据集处理问题。若一个表(data1)中每个id的 标准 excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载 值std,另一个表(data2)中为每个id的实际值,使用hash输出data2中比标准值大的观测及个数。[程序5.5]datadata1;inputidstd@@;cards;5.525.835.9Jrun;datadata2;inputidactual@@;cards;5.615.515.415.815.75.926.025.224.325.95.537.034.435.535.4run;dataresultl;if_n_=1thendo;declarehashmyhash(ordered:'y');myhash.definekey('id');myhash.definedata('id','std','count');myhash.definedone();callmissing(std,counfactual);count=0;end;dowhile(notdone);setdata1end=done;rc=myhash.ref();end;dowhile(notlast);setdata2end=last;rc=myhash.find();ifrc=0andactual>stdthendo;count+1;myhash.replace();output;end;end;myhash.output(dataset:'result2');run;输出结果:表6:程序5.6输出结果整理result1数据集result2数据集idstdactualcountidstdcount15.55.6115.5315.55.8225.8315.5r5.73「35.9125.85.9125.86225.8P5.93「35.971程序解读:程序中先建立一个空的哈希表,再把data1数据集映射到该哈希表,接着用过引用data2数据集找到对应关键字并判断、计数、输出。结果输出了两个数据集,result1为满足要求的全部记录,而result2为最后哈希表存储的信息。在定义哈希表时并不直接把数据集映射到哈希表,原因是需要映射到哈希表中的data1数据集中没有我们需要存储计数的变量count,此时可以建立一个空的哈希表,里面包含需要输出的变量。输出结果中result1数据集是由output语句输出的,result2数据集是myhash.output(dataset:'result2')语句输出的,可以发现,resultl数据集包含了哈希表的内容及data2中actual变量的数据,而result2数据集只包含了哈希表定义的变量及最后计数的结果。其结果的不同时由于哈希表中不存在定义变量以外的信息,且默认定义不允许相同的关键字存在。查看数据的结构可以发现datal数据集中的id是唯一的,data2数据集中的id是重复出现的,在此类问题中,较好的处理方式是把id是唯一的数据集映射到哈希表,通过set引用重复出现id的数据集进行数据处理。例5.5中设计两个数据集的连接,其中有一个是存在唯一关键字的,若需要处理的数据集的关键字都不唯一,则使用如下方法。[例5.6]连接datal、data2数据集,并求kind下所有id变量amt的总和。表7:原始数据data1数据集data2数据集kindididamta11150a22P40b1230b3330c2c3[程序5.6]datadata1;inputkind$id$;cards;TOC\o"1-5"\h\za1a2b1b3c2c3Jrun;datadata2;inputid$amt;cards;TOC\o"1-5"\h\z50403030Jrun;dataresult1;lengthkind$8id$8;if_n_=1thendo;declarehashh1(dataset:'data1',ordered:'y',multidata:'y');h1.definekey('id');h1.definedata('id','kind');hl.definedone();callmissing(id,kind);end;dowhile(notlastl);setdata2end=last1;h1.find();output;h1.has_next(result:r);dowhile(rne0);h1.find_next();output;h1.has_next(result:r);end;end;run;data_null_;lengthkind$8id$8;if_n_=1thendo;declarehashh2(ordered:'y');h2.definekey('kind');h2.definedata('id','kind','total');h2.definedone();callmissing(id,kind,total);end;dowhile(notdone);setresult1end=done;ifh2.find()=0thendo;total+amt;h2.replace();end;elsedo;total=amt;h2.add();end;end;h2.output(dataset:'result2');run;输出结果整理:表&程序5.6输出结果整理result1数据集result2数据集kindidamtkindtotala150a120a230b80a2p40ncP100b150b330c230c240c330程序解读:程序分为两部分,第一部分为连接数据集,输出为resultl,第二部分为以kind分组对amt变量求和。第一部分中由于要求连接后的数据集存在变量amt,而映射到哈希表的datal数据集中并不存在,则选择每连接一个相同的关键字就输出到指定的数据集。由于setdata2语句相当于遍历data2数据集,则每读取data2中的一条记录,则与哈希表连接查找相同的关键字并使用output输出,输出后继续查找是否存在下一个相同的关键字,若存在则输出,直到查找完毕,不存在则退出循环读取data2的下一条记录。这里不使用h1.output()语句是因为我们需要的是每次查找成功的记录且包含amt变量的数据集,而此处哈希表中仅存在data2的数据。第二部分为以kind为关键字段对所有id下的amt求和,由于此处只需要求和的结果而不是像第一部分需要的是每次连接的结果,选择使用h2.output语句输出哈希表的内容。接下来我们只需定义一个不允许相同关键字出现的哈希表,每读取resultl中的一条记录,查找哈希表中是否存在相同关键字,若存在相同关键字更新求和变量,若不存在则赋值到求和变量更加到哈希表即可,最后输出哈希表。此处需要注意的是h2.definedata('id','kind','total');中并没有定义我们需要求总和的amt变量,由于我们引用resultl数据集求和,而amt变量已经存在于resultl数据集,则不必映射到哈希表。若我们把amt变量引入哈希表则会导致求和时把相同关键字下最后读入哈希表的记录重算[例5.7]使用哈希迭代器遍历两个数据集并计算频数[程序5.7]datatest1;inputd1d2;cards;5910141519202425293034Jrun;datatest2;inputd@@;cards;5951032262841619262428273230132030Jrun;data_null_;lengthd18count8;if_n_=1thendo;declarehashh1(ordered:'y');hl.definekey('dl');hl.definedata('d1','d2','count');hl.definedone();callmissing(count,d1,d2,d);count=0;declarehiteriter1('h1');end;if_n_=1thendo;declarehashh2(dataset:'test2',multidata:'y');h2.definekey('d');h2.definedata('d');h2.definedone();callmissing(d);declarehiteriter2('h2');end;dowhile(notlast1);settest1end=last1;rc0=h1.ref();end;rc1=iter1.first();dowhile(rc仁0);count=0;h1.replace();rc2=iter2.first();dowhile(rc2=0);ifd1<=d<=d2thendo;count+1;h1.replace();end;rc2=iter2.next();end;rc1=iter1.next();end;h1.output(dataset:'result2');run;输出结果整理:表9:程序5.7输出结果result2数据集整理d1d2count593:101421519220242:2529530344本例主要使用哈希迭代器遍历test1数据集和test2数据集,查找满足条件d1<=d<=d2的观测并计数。在细节方面需要注意遍历的先后顺序,外层循环遍历的是保存有分组情况test1数据集,内层循环遍历的是需要被分组计数的test2数据集。需要注意控制两次遍历的循环条件,为了使内外循环条件不造成混乱使用rc1控制外层循环,rc2控制内层循环。外层循环读取到hl哈希表的每一条记录时,把count计数变量清零并使用iter2迭代器都扫描一次test2数据集,计数满足条件的观测。
本文档为【sashash简介与实例】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: ¥15.0 已有0 人下载
最新资料
资料动态
专题动态
个人认证用户
guoliang
暂无简介~
格式:doc
大小:44KB
软件:Word
页数:15
分类:
上传时间:2021-11-19
浏览量:20