【问题标题】:SAS Hash Merge Macro - output multiple data setsSAS Hash Merge Macro - 输出多个数据集
【发布时间】:2016-08-15 22:01:24
【问题描述】:

我正在创建一个哈希合并宏,我想为合并表创建一个数据集,并为缺失值创建一个数据集。这是我正在寻找的常规合并示例。

data &onto miss&varnm xtra&varnm;
  merge &onto(in=in1) fr2(in=in2);
    by &byvars;
    if in2 then from = "&from";
    else from = "&onto";
    if in1 and in2 then output &onto;
    else if in1 and not in2 then output &onto miss&varnm;
    else if not in1 and in2 then output xtra&varnm;
run;

我认为我的合并运行得很好,但我不确定如何获取“丢失”的数据集,因此我们将不胜感激。

%macro hashmerge(varnm,onto,from,byvars);
/* The inputs are the variables to merge,
   the merge onto data set, the merge from
   data set and the key(s). vanrnm and 
   byvars are set up to accept multiple inputs. */

%let data_vars   = %trim   (&varnm);
%let data_vars_a = %sysfunc(tranwrd(&data_vars.,%str( ),%str(",")));
%let data_vars_b = %sysfunc(tranwrd(&data_vars.,%str( ), %str(,)));
%let data_key    = %trim   (&byvars);
%let data_key    = %sysfunc(tranwrd(&data_key.,%str( ), %str(",")));

data &onto(drop=rc);
set &onto &from(keep=&varnm &byvars);

 declare hash h_merge (dataset: "&from.");

 rc = h_merge.DefineKey  ("&data_key.");
 rc = h_merge.DefineData ("&data_vars_a.");
 rc = h_merge.DefineDone ();

 do until (eof);
   set &onto end = eof;
   call missing(&data_vars_b.);
   rc = h_merge.find ();
   output;
 end;
stop;
run;

%mend;

【问题讨论】:

  • 您是否仅将其用于一对一合并?
  • 不,我将使用它进行不同的合并。

标签: hash merge sas


【解决方案1】:

使用您设置哈希对象的方式,您无法轻松获得xtra 数据集。您将能够通过类似这样的方式轻松获得missonto 的内容,以及对data 声明的必要更改:

if rc = 0 then output &onto;
else output miss&varnm;

但是,要在 from 数据集中找到您尚未使用的所有值,这些值通常会转到 xtra 数据集,您需要跟踪您拥有的值 在合并时使用,然后在数据步骤结束时将其余部分复制到新的哈希对象中并输出该对象。

注意使用您当前的代码,所有行都会输出到 &onto 数据集,即使它们缺少查找变量的值。

【讨论】:

    【解决方案2】:

    做到这一点并不难,但在这里您可以了解如何做到这一点。

    创建另一个散列散列对象,就像第一个一样。从第二个对象中,您将删除所有已匹配的项目。最后,您只需将第二个对象输出到数据集。它需要双倍的内存来存储哈希对象,但它是第一次尝试。

    (没有运行代码,对任何错误表示抱歉)

    %macro hashmerge(varnm,onto,from,byvars);
    /* The inputs are the variables to merge,
       the merge onto data set, the merge from
       data set and the key(s). vanrnm and 
       byvars are set up to accept multiple inputs. */
    
    %let data_vars   = %trim   (&varnm);
    %let data_vars_a = %sysfunc(tranwrd(&data_vars.,%str( ),%str(",")));
    %let data_vars_b = %sysfunc(tranwrd(&data_vars.,%str( ), %str(,)));
    %let data_key    = %trim   (&byvars);
    %let data_key    = %sysfunc(tranwrd(&data_key.,%str( ), %str(",")));
    
    data &onto (drop=rc);
       if 0 set &onto &from(keep=&varnm. &byvars.);   
    
       declare hash h_merge    (dataset: "&from.");
       rc = h_merge.DefineKey  ("&data_key.");
       rc = h_merge.DefineData ("&data_vars_a.");
       rc = h_merge.DefineDone ();
    
       /*hash table that will hold data not yet founded by find method */
       declare hash h_merge_copy    (dataset: "&from.");
       rc = h_merge_copy.DefineKey  ("&data_key.");
       rc = h_merge_copy.DefineData ("&data_vars_a.");
       rc = h_merge_copy.DefineDone ();
    
       do until (eof);
    
          set &onto. end = eof;
    
          if h_merge.find () = 0 then do;
             /*removing data from h_merge_copy if founded and if not allready removed*/
             if h_merge_copy.check() = 0 then do;
                rc = h_merge_copy.remove();
             end;
          end;
          else
             output miss&varnm.; /*no find match - output to miss&varnm.*/
    
          output &onto.; /*find match in hash or not output to &onto. (left join)*/
       end;
    
       h_merge_copy.output(dataset: "&onto.");
    
       stop;
    run;
    
    %mend;
    

    我可以改进这一点以减少内存消耗,例如在第二个哈希中不存储数据,但今天已经太晚了。希望这会有所帮助。

    【讨论】:

    • 如果是一对一合并,这种方法不能只使用一个哈希表吗?如果 Find() 成功,您可以 remove() 因为您只需要读取每条记录一次。
    • @Quentin 你是对的,但我采用了更通用的方法。如果 one2one 那么它可以是一个哈希。
    • 因此,使用这种方法,您可以在 &onto 中有重复的值,但它无法处理 &from 中的重复值,对吗?
    • 哈希对象默认不允许键记录重复。您必须将哈希显式定义为多数据才能使用 sama 键加载多条记录。
    • 对于 OP 来说值得注意的是,这种方法期望 &from 数据集对于 &byvars 是唯一的。
    【解决方案3】:

    感谢大家的帮助和建议。我不确定如何在不创建另一个哈希值的情况下添加“xtra”数据集,这违背了哈希合并的目的。所以这就是我必须创建丢失和合并的数据集的内容。

    %macro hashmerge(varnm,onto,from,byvars);
    
    
    %let data_vars   = %trim   (&varnm);
    %let data_vars_a = %sysfunc(tranwrd(&data_vars.,%str( ),%str(",")));
    %let data_vars_b = %sysfunc(tranwrd(&data_vars.,%str( ), %str(,)));
    %let data_key    = %trim   (&byvars);
    %let data_key    = %sysfunc(tranwrd(&data_key.,%str( ), %str(",")));
    
    data &onto(drop=rc) miss&varnm(drop=rc);
       if 0 then set &onto &from(keep=&varnm. &byvars.);
    
       declare hash h_merge (dataset: "&from.");
       rc = h_merge.DefineKey  ("&data_key.");
       rc = h_merge.DefineData ("&data_vars_a.");
       rc = h_merge.DefineDone ();
    
       do until (eof);
         set &onto end = eof;
         call missing(&data_vars_b.);
         rc = h_merge.find ();
         if rc = 0 then do;
           output &onto;
           from = "&from.";
         end;
         else do;
           output miss&varnm &onto;
           from = "&onto.";
         end;
       end;
    
    stop;
    run;
    
    %mend;
    

    如果您只想将非缺失值包含到新数据集中或删除“来自”变量,那么修改代码就足够简单了。

    如果有人知道更有效的方法,请发表建议。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-11
      • 1970-01-01
      • 2017-03-26
      • 1970-01-01
      • 1970-01-01
      • 2017-12-30
      • 1970-01-01
      相关资源
      最近更新 更多