SAS哈希合并 - 小数据集作为哈希对象
我使用的是在http://www.sascommunity.org/mwiki/images/2/22/Hashmerge.sas发现%HASHMERGE
宏和下面的示例数据集的:SAS哈希合并 - 小数据集作为哈希对象
data working;
length IID TYPE $12;
input IID $ TYPE $;
datalines;
B 0
B 0
A 1
A 1
A 1
C 2
D 3
;
run;
data master;
length IID FIRST_NAME MIDDLE_NAME LAST_NAME SUFFIX_NAME $12;
input IID $ FIRST_NAME $ MIDDLE_NAME $ LAST_NAME $ SUFFIX_NAME;
datalines;
X John James Smith Sr
Z Sarah Marie Jones .
Y Tim William Miller Jr
C Nancy Lynn Brown .
B Carol Elizabeth Collins .
A Wayne Mark Rooney .
;
run;
在working
数据集,我试图附加_NAME
变量从master
数据集使用此散列合并。输出看起来很好,是所需的输出。但是,在我的真实场景中,的master
数据集太大,无法放入散列对象,并且该宏一直将其作为散列对象。我最终想要将这两个数据集翻到working
数据集为哈希对象的位置,但是当我翻转代码时,我无法获得所需的输出。下面是产生所需的输出和需求调整了宏观调控的一部分,但我不能确定如何设置此:
data OUTPUT;
if 0 then set MASTER (keep=IID FIRST_NAME MIDDLE_NAME LAST_NAME SUFFIX_NAME)
WORKING (keep=IID);
declare hash h_merge(dataset:"MASTER"); /* I want WORKING to be the hash object since it's smaller! */
rc=h_merge.DefineKey("IID");
rc=h_merge.DefineData("FIRST_NAME","MIDDLE_NAME","LAST_NAME","SUFFIX_NAME");
rc=h_merge.DefineDone();
do while(not eof);
set WORKING (keep=IID) end=eof;
call missing(FIRST_NAME,MIDDLE_NAME,LAST_NAME,SUFFIX_NAME);
rc=h_merge.find();
output;
end;
drop rc;
stop;
run;
所需的输出:
IID FIRST_NAME MIDDLE_NAME LAST_NAME SUFFIX_NAME
---------------------------------------------------
B Carol Elizabeth Collins
B Carol Elizabeth Collins
A Wayne Mark Rooney
A Wayne Mark Rooney
A Wayne Mark Rooney
C Nancy Lynn Brown
D
虽然这是可行的,做你说,我怀疑你会从一个非专门制造的宏中获得。那是因为这不是通常的做法;通常你想保持主数据集的形式,并把关系数据集放在哈希表中。通常情况下,尺寸是相反的 - 关系表通常比主表小。
就我个人而言,我不会在这个特殊情况下使用散列。我会使用格式(或三)。就像散列一样快,并且具有较小的尺寸问题(因为它不需要适应内存),但由于尺寸的原因,它最终会放慢速度(但不会中断!)。
格式的解决方案:
data working;
length IID TYPE $12;
input IID $ TYPE $;
datalines;
B 0
B 0
A 1
A 1
A 1
C 2
D 3
;
run;
data master;
length IID FIRST_NAME MIDDLE_NAME LAST_NAME SUFFIX_NAME $12;
input IID $ FIRST_NAME $ MIDDLE_NAME $ LAST_NAME $ SUFFIX_NAME;
datalines;
X John James Smith Sr
Z Sarah Marie Jones .
Y Tim William Miller Jr
C Nancy Lynn Brown .
B Carol Elizabeth Collins .
A Wayne Mark Rooney .
;
run;
data for_fmt;
set master;
retain type 'char';
length fmtname $32
label $255
start $255
;
start=iid;
*first;
label=first_name;
fmtname='$FIRSTNAMEF';
output;
*last;
label=last_name;
fmtname='$LASTNAMEF';
output;
*middle;
label=middle_name;
fmtname='$MIDNAMEF';
output;
*suffix;
label=suffix_name;
fmtname='$SUFFNAMEF';
output;
if _n_=1 then do;
start=' ';
label=' ';
hlo='o';
fmtname='$FIRSTNAMEF';
output;
fmtname='$LASTNAMEF';
output;
fmtname='$MIDNAMEF';
output;
fmtname='$SUFFNAMEF';
output;
end;
run;
proc sort data=for_fmt;
by fmtname start;
run;
proc format cntlin=for_fmt;
quit;
data want;
set working;
first_name = put(iid,$FIRSTNAMEF.);
last_name = put(iid,$LASTNAMEF.);
middle_name = put(iid,$MIDNAMEF.);
suffix_name = put(iid,$SUFFNAMEF.);
run;
也就是说......
如果你想做到这一点在哈希表中,你需要做的是,对每一行MASTER什么,在工作表中做一个FIND,然后如果成功了一个REPLACE,那么FIND_NEXT和REPLACE直到失败。
问题?你至少在每个主排处找到至少一个找到,你自己指出这是非常大的。如果WORKING
为100k,MASTER
为100M,那么您为每场比赛做了1000次查找。这非常昂贵,并且可能意味着您最好使用其他解决方案。
感谢一如既往的卓越建议,@Joe。有道理,因为我的场景使用散列表没有太多的文档。我会给格式方法一个镜头! 'WORKING'有22MM的行,'MASTER'有一些类似350MM的行 - 讨厌的东西,但必须完成。 – Foxer
我绝对不会用散列做 - 然后找到另一个解决方案。也许把MASTER分成几组并散列。你可以在散列中填入多大的大小?你有多少内存?获得更多的内存或更小的数据集 - 例如,如果您可以在散列中容纳100MM,则四个散列可能就足够了,特别是如果您能够智能地分割它(例如索引),那么您只能从WORKING加载5MM行,从MASTER校正100MM行,而不是每次22/100)。 – Joe
您可以使用工作数据集的IID过滤主数据集,然后将过滤后的主数据集与工作数据集合并,因此这两个数据集都很小,很容易处理。 –
我尝试了一个'SQL left join'过滤器,它花费的时间比读取主数据集,排序和合并使用'if a'工作(in = a)master'花费的时间要长。 – Foxer
试试这个过滤器:proc sql;创建表New_master作为select * from master(keep = keep = IID FIRST_NAME MIDDLE_NAME LAST_NAME SUFFIX_NAME)where IID in(select IID from working(keep = IID));放弃; –