首页 > 解决方案 > 在 SAS 宏中执行循环

问题描述

我正在尝试创建一个将遍历列的字符串值的宏。

这是数据:

SUBJECT          VISIT            PARAMETER
001              Baseline         param1
001              Visit 2          param1
001              Visit 3          param1
001              Baseline         param2
001              Visit 2          param2
001              Visit 3          param2
002              Baseline         param1
002              Visit 2          param1
002              Visit 3          param1
002              Baseline         param2
002              Visit 2          param2
002              Visit 3          param2

这是我现在拥有的宏:

%macro want(numb, string);

DATA want&numb;
   SET have;
   IF parameter = &string;
RUN;

%mend want;

在其当前形式中,我必须在 PARAMETER 列中输入数字和字符串值。我想修改宏,以便可以迭代 30 个参数而不是以下参数:

%want(1, 'param1');
%want(2, 'param2');
...
%want(30, 'param30');

任何见解将不胜感激。

标签: sassas-macro

解决方案


如果您想将多个值传递给宏调用,那么通常最容易使用分隔列表。如果需要,宏可以使用%SCAN()宏功能来选择单个值。您可以使用该COUNTW()函数来确定值的数量。将其包装在%SYSFUNC()宏函数中以在宏逻辑中使用它。

由于您想在 SAS 代码中将值用作字符串文字,因此最简单的方法是要求用户在他们传递的值中包含引号。与在 SAS 语句中写入值时相同。

当您像这样一次拥有所有值时,您可以使用一个数据步骤在输入数据的一次传递中写入所有输出数据集。

%macro split(inds,prefix,values);
%local i n dsname sep;
%let n=%sysfunc(countw(&values,%str( ),q));
data 
%do i=1 %do &n;
  %let dsname=&prefix.&n;
  &dsname.
%end;
;
  set &inds ;
%do i=1 %to &n;
  %let dsname=&prefix.&n;
  &sep. if parameter = %scan(&values,&i,q) then output &dsname.;
  %let sep=else;
%end;
run;
%mend ;

那么您的示例将是这样的调用:

%split(inds=have,prefix=want,values='param1' 'param2' ... 'param30')

如果您有一个包含值列表的数据集,则可以使用简单的 SQL 查询来构建值列表。像这样:

proc sql noprint;
  select distinct quote(trim(param),"'") into :parmlist separated by ' '
  from list_of_parameters
  ;
quit;

并在调用中使用该宏变量。

 %split(inds=have,prefix=want,values=&parmlist.)

如果您希望生成的数据集数量仅基于出现在 HAVE 中的 PARAMETER 的值,那么您可以将该逻辑移至宏本身,并使宏的用户更容易使用。

请注意,通常不需要像这样拆分数据集。如果您想使用原始数据集 HAVE 但仅对特定 PARAMETER 值使用观察结果,则只需使用 WHERE 语句或 WHERE= dataset 选项。


推荐阅读