do 循环中的 SAS if 语句

SAS if statement in do loop

您好,我正在尝试编写一个带有 do 循环和 if 语句的宏函数。我想我搞砸了 if-then do 和 do 循环,我无法找出问题所在。 我有一个 table 儿童信息,其中包含年龄、性别、运动、乐器等列。

我的原始代码是这样的:

data old;
   set new;
   if sports in ("football","basketball") and age <=7 then type =1;
      else if sports='swimming' then type=2;
   if special_kid=. then do;
     if piano ^=. and piano_1 ^=. then do; talent_type=1; type_name=piano_1; end;
     if violin ^=. and violin_1 ^=. then do; talent_type=1; type_name=violin_1; end;
   end;
 run;

我有一堆乐器要编辑类型和名称。我想写一个循环来自动执行它,但我不确定为什么下面的代码不起作用。

%let instrm = piano violin;
%macro my_func;
   data old;
   set new;
   %if sports in ("football","basketball") and age <=7 %then type =1;
      %else %if sports='swimming' %then type=2;
   %do %while (special_kid=.);
      %do i % to sysfunc(countw(&instrm));
          %let word = %scan(&name, &i);
          %if &word ^=. and ^word._1 ^=. %then %do;
          talent_type=1; type_name=&word._1;
          %end;
     %end;
  %end;
run;
%mend;

它一直给我错误

 ERROR: An unexpected semicolon occurred in the %DO statement.
 ERROR: A dummy macro will be compiled.

有人可以回答我的问题吗?谢谢!

宏变量 instrm 实际上是一个包含 space 分隔的变量名列表的值。您最好从特定的变量使用角色中抽象出来,然后回退到更通用的参数名称 vars。此外,与其依赖在全局或包含范围内定义的宏变量,不如在调用期间传入列表。您是正确的,space 分隔列表可以在宏中使用 %do 循环迭代,其上限是列表中 'words' 的 countw 数量——你的语法只是有点偏差。

你不必宏观化一切,体育逻辑的额外宏观化已经很远了。请记住,宏调用发出(或生成)输入 SAS 提交系统的源代码。宏编码编码过程比较抽象或者toolboxy有时也被称为codegen。

您的原始代码可能有错误,因为您评估(在一行中)多个特殊的 kid 变量并对相同的 2 个变量(talent_typetype_name)执行赋值,因此可能会覆盖先前分配的值。有时,这样的评估和分配是 OUTPUT 分隔行。

%macro my_skill_classifier(data=, out=, special_vars=, special_type=);
   %local i var;

   data &out;
   set &data;

   if sports in ("football","basketball") and age <=7 then type = 1;
   else
   if sports='swimming' then type=2;

   * what happens to football/baskeball > 7yr ?;

   if missing(special_kid) then do;
      %do i = 1 %to sysfunc(countw(&special_vars));
        %let var = %scan(&special_vars, &i);

        * regular data step code with macro resolutions sprinkled in;
        if &var ^=. and var._1 ^=. then do; 
          talent_type = &special_type;
          type_name = &var._1;
          * maybe you really mean type_name = "&var._1";
        end;
      %end; %* end loop over special_vars list;
    end;
  run;
%mend;

%my_skill_classifier(data=new, out=old, special_vars=piano violin, special_type=1)

总而言之,在开始宏编码之前,请确保您的数据整形和评估处理方法是坚如磐石的。如果您问自己 我应该对此进行宏设置吗?,请保守一点并回答否。对维护者和未来的自己友好,不要让事情过于复杂。

您的代码几乎不需要调整,我做了一些更改。此外,当我们使用 %if 时,我们总是使用宏变量。否则我们最好只使用带有普通数据集变量的 if 语句。

%let instrm = piano violin;
%macro my_func;
 data old;
   set new;
   if sports in ("football","basketball") and age <=7 then type =1;
      else if sports='swimming' then type=2;
   if missing(special_kid) then do;
      %do i=1 %to %sysfunc(countw(&instrm));
          %let word = %scan(&instrm, &i);
          %If &word ^=. and &word._1 ^=. %then %do;
          talent_type=1; type_name=&word._1;
          %end;
      %end;
  end;
run;
%mend my_func;