在SAS

时间:2018-01-30 04:59:10

标签: sas

我正在尝试动态创建保留列表。说:

%MACRO TEST(A=,B=,OUT_VAR=,KEEP_VAR=);
&OUT_VAR=MAX(&A,&B);
%IF &KEEP_VAR = 'Y' %THEN VAR_LIST=%SYSFUNC(CATS(VAR_LIST,&OUT_VAR));
%PUT VAR_LIST;
%MEND;

DATA ABC (keep = VAR_LIST);
LENGTH VAR_LIST $100.;
RETAIN VAR_LIST '';
%TEST(A=1,B=3,OUT_VAR=FIRS,KEEP_VAR='Y');
%TEST(A=2,B=4,OUT_VAR=SEC,KEEP_VAR='Y');
%TEST(A=3,B=5,OUT_VAR=THIR,KEEP_VAR='N');
RUN;

我有一个datastep,我在其中创建由宏代码计算的几个变量。 我想创建这些输出变量的动态列表,然后在keep语句中使用它。 上面的代码似乎不起作用,有人可以建议我在这里缺少什么。

2 个答案:

答案 0 :(得分:0)

正在运行的数据步骤是已编译的源代码。您正在尝试在运行时更改源 - 这不会发生。这是在宏代码和生成的代码之间混合范围和上下文的症状。

但是,TEST宏正在生成源,因此可以

  • 维护状态信息,以便在调用宏之后生成KEEP源代码语句。
  • 为每个KEEP调用生成一个额外的TEST语句

通常,仅宏参数值已经是'字符串',并且不需要引用。

%MACRO TEST(A=,B=,OUT_VAR=,KEEP_VAR=);
  &OUT_VAR=MAX(&A,&B);/* generates data step source code*/
  %IF &KEEP_VAR = 'Y' %THEN
    %LET VAR_LIST=&VARLIST &OUT_VAR;
%MEND;

* must occur before sequence of TEST invocations;
%global VARLIST; * globals generally want to be avoided, next version avoids it;
%let VARLIST =;

DATA ABC;
%TEST(A=1,B=3,OUT_VAR=FIRS,KEEP_VAR='Y');
%TEST(A=2,B=4,OUT_VAR=SEC,KEEP_VAR='Y');
%TEST(A=3,B=5,OUT_VAR=THIR,KEEP_VAR='N');
KEEP &VARLIST;
RUN;

%symdel VARLIST;

我希望这是一个学习练习 - 上面的编码模式有一个宏生成代码,就像两个正常的非宏数据步骤语句一样。太多的宏观化可能会混淆。

此外,输出ABC可能与您的预期不符。将有一个行,A = 3,B = 5,FIRS = 4,SEC = 6且无THIR = 8。所以你也有一些混合的行和列数据概念。

以下是TEST生成KEEP

的更清晰的替代方案
%MACRO TEST(A=,B=,OUT_VAR=,KEEP_VAR=);
  &OUT_VAR=MAX(&A,&B);/* generates data step source code*/
  %IF %upcase(&KEEP_VAR) = Y %THEN %STR(KEEP &OUT_VAR;);
%MEND;

DATA ABC;
  %TEST(A=1,B=3,OUT_VAR=FIRS,KEEP_VAR=Y);
  %TEST(A=2,B=4,OUT_VAR=SEC,KEEP_VAR=Y);
  %TEST(A=3,B=5,OUT_VAR=THIR,KEEP_VAR=N);      
RUN;

宏代码仍然需要依赖调用者来指定正确的KEEP_VAR参数Y或不是Y.

另一种方法是将Y / N KEEP概念推入两个参数,使用一个参数而不是另一个参数来区分KEEP。

%MACRO TEST(A=,B=,KEEP_VAR=,TEMP_VAR=);
  %IF %length (&KEEP_VAR) %then %do;
    &KEEP_VAR 
  %end;
  %else %do;
    &TEMP_VAR
  %end;

  MAX(&A,&B);

  %IF %length (&KEEP_VAR) %then %do;
    KEEP &KEEP_VAR;
  %end;
%MEND;

DATA ABC;
  %TEST(A=1,B=3,KEEP_VAR=FIRS);
  %TEST(A=2,B=4,KEEP_VAR=SEC);
  %TEST(A=3,B=5,TEMP_VAR=THIR);
RUN;

对我来说,一个广泛使用的宏应该具有明确的调用。宏实现的黑盒子可以努力保持干净和高效,但不一定如此。

答案 1 :(得分:0)

目前尚不清楚您要做什么,但如果需要,您可以使用多个KEEP语句。

data want ;
   x=1;
   keep x;
   y=2;
   z=3;
   keep z;
run;

虽然对于您的应用程序,您可能希望生成DROP语句。

%MACRO TEST(A=,B=,OUT_VAR=,KEEP_VAR=Y);
  &OUT_VAR=MAX(&A,&B);
%IF (&KEEP_VAR ^= Y) %THEN %DO;
  drop &out_var ;
%end;
%MEND;

DATA ABC ;
  %TEST(A=1,B=3,OUT_VAR=FIRST)
  %TEST(A=2,B=4,OUT_VAR=SECOND)
  %TEST(A=3,B=5,OUT_VAR=THIRD,KEEP_VAR=N)
RUN;