在SAS中我们比较习惯使用data步来解决数据处理工作,但是当我们需要处理的是两个以上有关联的数据文件或需要处理的数据观测记录达到百万级别时,data步显然不能满足我们的要求,而且我们用data步进行merge拼接的时候还要对数据集进行排序。
此外,我们也可以使用sql进行多表连接。sql相比data步来说不需要对数据集进行排序,不用名字一样,并且条件不限制在等号,没有data步那么繁琐。我们还可以使用hash散列表(哈希表),把关键字(key)映射到散列表中,通过散列表直接获取需要访问数据的存储地址,可以快速地进行查找、添加等操作。
SAS提供了hash和hiter两种方法处理哈希表,hash提供了查找、修改、添加、删除等方法,hiter提供了用于定位和遍历等方法(为了便于理解,key相当于merge时by的变量)。
hash的定义及使用
首先我们要将数据集‘ss’实例化,可以采用以下两种定义方式:
定义1:declare hash variable_name(tag: value, ... tag-n: value-n);
定义2:variable_name = _new_ hash(tag: value, ... tag: value-n);
图一
如图一所示:
将数据集‘ss’实例化为2个哈希对象:‘hh’,‘tt’;
ordered指定主键的排序,‘a’表示ascending;multidata判断同一主键是否有多条记录,‘Y’表示允许,一般默认情况为‘N’;
suminc指定一个数值变量在data步中用来汇总键的步长,‘j’相当于数组中的‘i’;
keysum指定一个变量用来汇总查询键的次数;
hiter是遍历‘tt’(相当于data步中进行了去重处理);
(‘if _n_=1 then do’是因为在使用hash对象前需要对其进行定义和声明,但是这一步只需要完成一次,所以对第一行数据单独进行定义和声明,不加也可以,运行速度会比较慢)。
其次,在定义一个哈希对象后需要指定哈希对象的关键字段等,如下:
Definekey 定义关键字段
Definedata 定义值
Definedone 定义完成
Call missing 避免提示变量未初始化
图二
如图二所示:
‘hh’中定义主键为‘sex’,主键对应的值为‘sex’,‘name’;
‘tt’中定义主键为‘sex’,主键对应的值为‘sex’;同时声明主键和值的变量名、数据类型、长度(可以使用call missing()进行显示处理)。
/*如果需要使用全部值,可通过h.definedata(all:'yes')来进行全部的定义*/
哈希表中可选选项语句及功能
图三
如图三所示:
find 根据指定主键查找hash对象中对应的值,若查找成功则返回rc=0并更新该变量的值,若无则返回上次查找结果;
has_next指遍历指定主键过程中查找是否有前/后值,并指定一个变量在result标签中接收返回的值,若成功则返回rc=0;
put可以在log中查看hash的迭代过程;remove移除指定的主键及其对应的值;find_next指遍历指定主键过程中查找是否有前/后值,若成功则返回rc=0,若无则返回上次查询结果。
不同主键
多个数据集用哈希表进行合并的时候,如果key是同一个变量,那么任意放N-1个数据集放到哈希表中,直接用以下语句即可实现:
如果key不是同一个变量,那么就要单独指定key,rc为接收返回值,程序中若操作成功则返回0,失败则返回非0。
小结
总的来说,hash对象(哈希表)是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
在SAS中使用哈希表十分简单,你并不需要知道SAS内部是怎么实现的,只需要知道哈希表是存储在内存中的,查找是根据key值直接获得存储的地址的精确匹配。加上使用哈希表合并数据集时不用排序的优点,在实际应用中可以极大地提高程序运行效率,尤其是数据集较大的时候。但是由于哈希表是放到内存中的,因此对内存有一定要求!