注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

数据挖掘

学习数据挖掘

 
 
 

日志

 
 

SAS hash 对象  

2013-05-26 22:17:06|  分类: SAS |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
原文连接: http://blog.163.com/qiaozhanwen@126/blog/static/12955392520121010102028497/ 
1,基本原理
       散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
      
     在数据装载时,根据F(key)=内存地址将表存到内存中指定的地址; 

     
 key  value 内存地址(举例)
 张三  87  A1=F(张三)=18
 李四  98  A2=F( 李四)=20
 王五  69 A3= F(王五)=36
 阮六  83  A4= F(阮六)=48
    
 当要查找这个表中的数据时只要给定KEY值根据A=F(key)可以快速的得到的该key对应的内存地址直接进行取数,不用扫描整个表。

2.SAS中定义的HASH对象:

         Hash对象的最基本的要点有三个:

         (1)要放入内存中的表

         (2)用来通过hash函数建立与内存对应存储地址的KEY值(可以是数值、字符或者两者的混合,最好是表的主键否则只有第一条记录有效,因为key值相同通过F(key)只会指向一个地址)。

        (3)要调入内存中与key值一起构成数组的变量.

3.在SAS中分别通过以下步骤来完成上述三个要点:

SAS hash 对象 - 小坏 - Do  What
 
   Call missing(key,variable_1)避免log里出现数据未初始化的提醒。

3.   SAS中使用已经定义好的Hash表的方法有以下7种:
 
1)ADD 方法:增加指定的数据到hash中,数据中必须包括已经存在的hash的key值。

          rc=object.ADD(<KEY: keyvalue-1,..., KEY: keyvalue-n, DATA: datavalue-1,..., DATA: datavalue-n>);

         rc:指定add方法是否成功,成功返回0,失败返回非0。下同

          object:hash名。下同

          KEY: keyvalue :指定增加的关键值,必须与已定义的hash中一致

          DATA: datavalue:指定增加的数据,必须与hash中一致

2)CHECK 方法:检查具体的key的取值是否已经存储在hash中

           rc=object.CHECK(<KEY: keyvalue-1,..., KEY: keyvalue-n>);

            例:rc = h.check(key: 'Joyce')

3)FIND 方法:查找给定key值的内存位置把对应的数据取出,以供接下来进行操作。

          rc=object.FIND(<KEY: keyvalue-1,..., KEY: keyvalue-n>);

          rc=h.find(key:'var1')

4)DELETE 方法:删除已经定义的hash

           rc=object.DELETE( );

5)OUTPUT 方法:创造一个或多个数据集(数据包含在hash中)

           rc=object.OUTPUT(DATASET: 'dataset-1' <..., DATASET: 'dataset-n'>);

            DATASET: 'dataset' 指定输出的数据集名称

6)REMOVE 方法:移除hash中key的某个特定值(针对观测值/行)

            rc=object.REMOVE(<KEY: keyvalue-1,..., KEY: keyvalue-n>);

7)REPLACE 方法:替换hash中key的某个特定值后边所带的变量值(针对观测值/行)

            rc=object.REPLACE(<KEY: keyvalue-1,..., KEY: keyvalue-n, DATA: datavalue-1,..., DATA: datavalue-n>);

8)Hash Iterator 方法

         1)FIRST 方法:返回hash索引的第一个值

         2)LAST 方法:返回hash索引的最后一个值

         3)NEXT 方法:返回hash索引下一个值

         4)PREV 方法:返回hash索引前一个值
9) h.num_items 返回唯一的key值数

4.hash的使用实例

(1)通过hash可以实现表与表的高效关联

(2)可以对hash表中的数据进行控制设计巧妙的算法。下边是在网上搜集的一些具体的例子:

eg1.通过hash对数据集进行排序,并输出排序后的数据集


data test;
do i =1 to 10;
key=5+rannor(10)*3;
value=3+rannor(10)*2;
output;/*在循环中,保证每一条记录的输出*/
end;
run;

----做成hash表

data _null_;
if _n_=0 then set test;/*初始化要进行hash的数据集的数据结构*/
if _n_=1 then do;/*定义hash表的三个要素,在内存中生成hash表*/
declare hash h(dataset:'test',ordered:'ascending');/*在这里实现在内存中按key值进行排序*/
h.definekey('key');
h.definedata(all:'yes');
h.definedone();
end;
rc=h.output(dataset:'test_order');/*调用output方法在内存中排好序的hash表输出*/
run;
proc print data=test_order;
run;
eg2.把哈希表中指定的观测输出或者做处理 

data work.test;
input key value;
datalines;
1 2
1 3
2 4
2 5
3 6
3 7
;
run;
data test_2;
if _n_=0 then set test;
if _n_=1 then do;
declare hash h(dataset:'work.test');
declare hiter iter('h');/*针对两个关键词以及以上*/
h.definekey('key');
h.definedata(all:'yes');
h.definedone();
end;
rc=iter.first();/*返回0代表成功,好变态的返回策略,哈哈*/
do while(rc=0);
if key=2 then output;
rc=iter.next();
end;
drop rc;
run;
proc print data=test_2;/*结果发现 只取一个key值的记录*/
run;

eg3.主表调用hash表的数据(这个例子是从网上转载的,hash应用较为的经典案例,值得反复揣摩品味)

要求:A表是每日基金净值表,其中name是基金名称;date是收盘日期;value是当日净值。B表是各客户持有各基金的起始日期与终止日期,
其中name是基金名称,sdate是起始日期,edate是终止日期。真实环境中:A表不大,只有几千条记录;B表巨大,会有一亿条记录。
   
目标表C含有各客户持有各基金起始日期的净值;终止日期的净值;期间净值累计值。即在保留B表所有字段的基础上衍生计算三个字段:svalue(起始日期的净值);evalue(终止日期的净值);tvalue(期间净值累计值)。

data value;
input name$ data value;
informat data yymmdd8;
format data data9;
cards;
A 20070101 1
A 20070102 2
A 20070103 3
A 20070104 4
A 20070105 5
A 20070106 6
A 20070107 7
B 20070101 8
B 20070102 9
;
run;
data original;
input name$ sdata edata;
informat sdata edata yymmdd10;
format sdata edata yymmdd10;
datalines;
A 20070102 20070106
A 20070101 20070104
B 20070101 20070102
;
run;
data cum_value;
if _n_=0 then set value;
if _n_=1 then do;
declare hash h(dataset:'value');
h.definekey('name','data');
h.definedata('value');
h.definedone();
end;
set original;
rc=h.find(key:name,key:sdata);/*把具体的key值传给find方法找到对应的内存地址将hash表中对应的数据取出*/
s_value=value;
rc=h.find(key:name,key:edata);/*把具体的key值传给find方法找到对应的内存地址将hash表中对应的数据取出*/
end_value=value;
sum_value=0;
do i=sdata to edata;
sum_value+value;
end;
keep name sdata edata s_value end_value sum_value;
run;
proc print data=cum_value;
run;


eg4.调用hash表自身数据进行计算
   A客户有三条记录,每条记录的金额均小于200,;B客户有5条记录,每条记录的金额均大于150,但小于400。
 条件:如果某个客户的总金额(该客户所有记录的金额加和)<600,则将该客户的所有记录删除。如上例中,A客户总金额<600,则删除A客户。

data test;
input id $ amount;
datalines;
A 189
B 160
B 188
B 165
A 145
A 199
B 198
B 345
;
run;
data wanted;
if 0 then set test;
if _n_=1 then do;
declare hash h();
h.definekey('id');
h.definedata('id','total'); /*定义一个空total变量*/
h.definedone();
end;
do until(last);
set test end=last;
if h.find()=0 then do;
total+amount;
h.replace();
end;
else do;
total=amount;
h.add();
end;
end;
do until(last1);
set test end=last1;
if h.find()=0 and total>=600 then output;
end;
stop;
run;


  评论这张
 
阅读(475)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017