SAS哈希合并 - 较小的数据集作为哈希对象

时间:2017-02-23 15:59:28

标签: hash merge sas hashtable

我使用http://www.sascommunity.org/mwiki/images/2/22/Hashmerge.sas处的%HASHMERGE宏和以下示例数据集:

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                   

1 个答案:

答案 0 :(得分:0)

虽然按照你说的做法是可行的,但我怀疑你是否会从一个非专用的宏中得到它。那是因为这不是正常的做法;通常,您希望将主数据集保留在其表单中,并将关系数据集放在哈希表中。通常大小相反 - 关系表通常小于主表。

我个人不会在这种特殊情况下使用哈希。我会使用一种格式(或三种)。与哈希一样快,并且具有较少的大小问题(因为它不必适合内存),但由于大小最终会减慢(但不会中断!)。

格式解决方案:

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次查找。这非常昂贵,可能意味着你可以通过其他解决方案获得更好的效果。