在 SAS 宏中执行循环
Do loop within SAS Macro
我正在尝试创建一个宏来遍历列的字符串值。
这是数据:
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');
如有任何见解,我们将不胜感激。
此代码作为解决方案:
%macro want();
data _null_;
set HAVE;
call symput('lengthmac',_N_);
run;
%do i = 1 %to &lengthmac;
data _null_;
set have;
IF _N_ = &i;
call symput('parammac',parameter);
run;
data want&i;
SET have;
IF PARAM = "¶mmac";
run;
%end;
%mend want;
如果您想将多个值传递给宏调用,那么使用分隔列表通常是最简单的方法。如果需要,宏可以使用 %SCAN()
宏函数来 select 单个值。您可以使用 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= 数据集选项。
我正在尝试创建一个宏来遍历列的字符串值。
这是数据:
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');
如有任何见解,我们将不胜感激。
此代码作为解决方案:
%macro want();
data _null_;
set HAVE;
call symput('lengthmac',_N_);
run;
%do i = 1 %to &lengthmac;
data _null_;
set have;
IF _N_ = &i;
call symput('parammac',parameter);
run;
data want&i;
SET have;
IF PARAM = "¶mmac";
run;
%end;
%mend want;
如果您想将多个值传递给宏调用,那么使用分隔列表通常是最简单的方法。如果需要,宏可以使用 %SCAN()
宏函数来 select 单个值。您可以使用 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= 数据集选项。