Макрос Hash Merge - с помощью индикатора записи файла «HASH + point = Key» - PullRequest
0 голосов
/ 07 ноября 2018

Нужно обновить этот макрос, чтобы он был HASH + точка = ключ. Мы начали превышать пределы памяти с нашей текущей версией этого макроса для одного из наших прогонов данных. Причина, по которой я обращаюсь за помощью, заключается в том, что у меня не так много времени, и я никогда не анализировал этот код, поскольку до недавнего времени он не был частью моего процесса.

Из чего я на самом деле не понимаю, https://www.lexjansen.com/nesug/nesug11/ld/ld01.pdf, - как устанавливается RID и как его включить в наш макрос. На самом деле я даже не знаю, возможно ли сделать это таким образом с нашим текущим макросом.

Любая помощь будет принята с благодарностью.

%macro hashmerge2(varnm,onto,from,byvars,obsqty);

%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(" , ")));

%if %index(&varnm,' ') > 0 %then %let varnm3=%substr(%substr(&varnm,1,%index(&varnm,' ')),1,4);
%else %let varnm3=%substr(&varnm,1,4);


data &onto(drop=rc) miss&varnm3(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&varnm3 &onto;
      from = "&onto.";
   end;
 end;

stop;
run;

%mend;

1 Ответ

0 голосов
/ 07 ноября 2018

Так что я думаю, что это то, что вы ищете, но все же необходимо загрузить все значения ключей из таблицы «поиска» в хеш-объект. Но это может сэкономить место, вместо того, чтобы загружать неключевые переменные, которые просто необходимы для загрузки номера наблюдения, соответствующего ключевым переменным.

%macro hash_merge_point
/*-----------------------------------------------------------------------------
Merge variables ONTO large table FROM small table using POINT= dataset option.
-----------------------------------------------------------------------------*/
(varnm  /* Space delimited list of variable to retrieve */
,onto   /* Dataset to update */
,from   /* Dataset to get values from */
,byvars /* Space delimited list of key variables to match on */
);
%local missds key_vars;
%let missds=%scan(&varnm,1,%str( ));
%let missds=miss%substr(&missds,1,%sysfunc(min(28,%length(&missds))));

%let key_vars="%sysfunc(tranwrd(%sysfunc(compbl(&byvars)),%str( )," "))";

data &onto(drop=rc) &missds(drop=rc);
  if 0 then set &onto &from(keep=&varnm. &byvars.);

  declare hash h_merge ();
  rc = h_merge.DefineKey  (&key_vars);
  rc = h_merge.DefineData ('_point');
  rc = h_merge.DefineDone ();
  do _point=1 to _nobs;
    set &from(keep=&byvars) point=_point nobs=_nobs;
    rc = h_merge.add();
  end;

  do until (eof);
    set &onto end = eof;
    rc = h_merge.find ();
    if rc = 0 then do;
      set &from (keep=&varnm) point=_point;
      from = "&from.";
      output &onto;
    end;
    else do;
      call missing(of &varnm);
      from = "&onto.";
      output ;
    end;
  end;

stop;
run;

%mend hash_merge_point;

Итак, вот тривиальный пример:

data lookup;
  input id age sex $1.;
cards;
1 10 F
2 20 .
4 30 M
;
data master ;
  input id wt ;
cards;
1 100
2 150
3 180
4 200
;

%hash_merge_point
/*-----------------------------------------------------------------------------
Merge variables ONTO large table FROM small table using POINT= dataset option.
-----------------------------------------------------------------------------*/
(varnm=age sex  /* Space delimited list of variable to retrieve */
,onto=master   /* Dataset to update */
,from=lookup  /* Dataset to get values from */
,byvars=id /* Space delimited list of key variables to match on */
);

enter image description here

Если в целевой таблице уже есть переменные, создаваемые слиянием (поэтому вы просто хотите перезаписать текущие значения), тогда вы можете использовать инструкцию MODIFY вместо инструкции SET, чтобы изменить набор данных на месте. Но вы можете убедиться, что у вас есть резервная копия таблицы, прежде чем пытаться это сделать. Также обратите внимание, что если вы хотите указать для источника переменную from, то эта переменная также должна существовать.

Итак, с помощью этой обновленной главной таблицы:

data master ;
  input id wt ;
  length age 8 sex $1 from $50;
cards;
1 100
2 150
3 180
4 200
;

И эта версия макроса:

%macro hash_merge_point
/*-----------------------------------------------------------------------------
Merge variables ONTO large table FROM small table using POINT= dataset option.
-----------------------------------------------------------------------------*/
(varnm  /* Space delimited list of variable to retrieve */
,onto   /* Dataset to update */
,from   /* Dataset to get values from */
,byvars /* Space delimited list of key variables to match on */
);
%local key_vars;
%let key_vars="%sysfunc(tranwrd(%sysfunc(compbl(&byvars)),%str( )," "))";

data &onto;
  if 0 then set &onto (keep=&byvars.);

  declare hash h_merge ();
  rc = h_merge.DefineKey  (&key_vars);
  rc = h_merge.DefineData ('_point');
  rc = h_merge.DefineDone ();
  do _point=1 to _nobs;
    set &from(keep=&byvars) point=_point nobs=_nobs;
    rc = h_merge.add();
  end;

  do until (eof);
    modify &onto end = eof;
    rc = h_merge.find ();
    if rc = 0 then do;
      set &from (keep=&varnm) point=_point;
      from = "&from.";
    end;
    else from = "&onto.";
    replace;
  end;

stop;
run;

%mend hash_merge_point;

Если вы запустите этот код:

proc print data=master; 
 title 'BEFORE';
run;

%hash_merge_point
/*-----------------------------------------------------------------------------
Merge variables ONTO large table FROM small table using POINT= dataset option.
-----------------------------------------------------------------------------*/
(varnm=age sex  /* Space delimited list of variable to retrieve */
,onto=master   /* Dataset to update */
,from=lookup  /* Dataset to get values from */
,byvars=id /* Space delimited list of key variables to match on */
);

proc print data=master; 
  title 'AFTER';
run;

Вы получите этот результат:

enter image description here

...