如何使SAS宏可以自动运行变量列表

时间:2018-01-31 00:12:01

标签: macros sas

我正在使用一个SAS宏,它使用sql来构建CODELIST,然后在数据中添加一个标志。因此格式表包含ICD代码和一些变量标志名称。所以这个宏基本上只是如果我输入一个flagName它会在mydata中创建一个标志变量。

%MACRO flag(flagName); 
PROC SQL;
    SELECT QUOTE(ICD) INTO :CODELIST SEPARATED BY "," 
        FROM Format_Table
        WHERE FLAG = %unquote(%str(%')&flagName%str(%'));
QUIT;


DATA mydata; SET mydata;
    IF DIAG IN (&CODELIST) THEN &flagName = 1;
RUN;
%MEND flag;

但是当我有太多的flagNames时,它将无法正常工作,这意味着我必须逐个输入每个变量名称。而falgNames是所有的疾病名称,如乳房,前列腺等。我想知道是否有一种方法可以创建一个具有变量名称的数组,并每次运行宏与数组值而不是列出所有的宏命令。 像:

  Array variables [I] breast prostate lung;
  %DO I = 1 to DIM(variables);
  %macro(inputVarialeName = variables[I]);
  END;

如果有办法,请帮助我。非常感谢您的帮助。

4 个答案:

答案 0 :(得分:0)

使用CALL EXECUTE,文档中有一个完整的示例here

首先,你需要以某种方式创建一个变量列表,要么输入它,要么从SASHELP.VCOLUMN或PROC CONTENTS中提取它。

/********************************************************************
Example : Call macro using parameters from data set
********************************************************************/

proc sort data=sashelp.class out=class;
by age sex;
run;

%macro summary(age=, sex=);

proc print data=sashelp.class;
    where age=&age and sex="&sex";
run;

%mend;

data sample;
set class;
by age sex;

if last.sex;
string =
    catt('%summary(age=', age, ',sex=', sex, ');');
put string;
run;


data _null_;
set sample;
call execute(string);
run;

答案 1 :(得分:0)

您可以创建第二个循环输入的宏,并为每个项调用另一个宏。

你应该真正发布工作代码,%macro (inputVarialeName = v1);有点不敏感 - 你定义或调用吗? %my_macro (inputVarialeName = v1);在调用方面会更加明确。

假设您有一个需要多次调用的宏

%macro my_macro (var=);
  /* generate some data step code that does something with &var, lets log it */
  putlog 'NOTE: ' &var=;
%mend;

或者宏可能是某些将片段转换为百分比的SQL片段

%macro my_macro (var=);
  , &var * 100 as &var._pct
%mend;

或是Proc REPORT

的定义声明
%macro my_macro (var=);
  define &var / center;
%mend;

创建第二个宏,它接受一个空格分隔的变量列表,就像程序中的VAR语句一样。

%macro do_my_macro_for_each (vars=);
  %local index token;
  %let index = 1;
  %do %while (1);
    %let token = %scan(&vars, &index);
    %if %length(&token) = 0 %then %return;

    /* invoke my macro using i-th token */
    %my_macro (var=&token)

    %let index = %eval (&index + 1);
  %end;
%mend;

然后调用' do-er'使用您的变量列表

data have;
  array v(1000) (1:1000);
run;

data _null_;
  set have;
  %do_my_macro_for_each (vars=v1 v32 v185 v237);
run;

----- LOG -----
NOTE: v1=1
NOTE: v32=32
NOTE: v185=185
NOTE: v237=237
NOTE: There were 1 observations read from the data set WORK.HAVE.

可以通过互联网搜索或SAS conference paper searches(lexjansen.com)找到实施SAS宏代码的其他讨论,这些代码可以执行通用的每个处理。

答案 2 :(得分:0)

Qimeng有一个ICD分类表,用于设置状态标志。

data DX_CLASSES;
length ICD $5 flag $32;
input 
ICD & Flag ; datalines; /* NOTE: & requires data values be separated by 2 or more spaces */
1     xxx
23.1  xxx
2     yyy
2.1   yyy
3.3   yyy
run;

并且有一些患者诊断信息

data DIAGNOSES;
length pat_id visit_id diagnosis $5;
input
pat_id & visit_id & diagnosis & record_id; datalines;
 1       1          23.1        1
 1       1          2           2
 1       1          77.7        3
 1       2          23.1        4
 2       1          2.1         5
 run;

并希望每个不同的标志值添加一列。 将“标志”这个短语视为“医疗概念”

是合适的
 pat_id visit_id diagnosis record_id xxx  yyy
 ------ -------- --------- --------- ---  ---
 1      1        23.1      1          1    0
 1      1        2         2          0    1
 1      1        77.7      3          0    0
 1      2        23.1      4          1    0
 2      1        2.1       5          0    1

单个SQL可以为每个不同的应用分类查找。此纯SQL语句可用作开发重复调用的适当宏的基础。 EXISTS条件可用作高效IN查找评估。

proc sql;
  create table want as 
  select have.* 
  , exists (select * from DX_CLASSES where DX_CLASSES.flag = "xxx" and DX_CLASSES.ICD = have.DIAGNOSIS) as xxx
  , exists (select * from DX_CLASSES where DX_CLASSES.flag = "yyy" and DX_CLASSES.ICD = have.DIAGNOSIS) as yyy
  from DIAGNOSES as have
  ;

假设流程

%macro do'ee
  emits something specific to one flag
%mend

%macro do'er
  do for each item in flags
    invoke do'ee
  end
%mend;

proc sql;
  create ... as
  select ...
  %do'er ( list of flags )
  from ...
  ;

'do-er'调用可能是

%apply_concepts (data=DIAGNOSES, concepts=DX_CLASS, flag=xxx yyy);

'do-er'实现中的'do-ee'(flag =中的每个项目)调用可能是

%binary_flag_concept(outer=have, inner=&concepts, flag=&flag_item)

'do-ee'实现会发出一个exist子句

, exists (
    select * 
    from &concepts as inner 
    where inner.flag = "&flag" 
      and inner.ICD = have.DIAGNOSIS
  ) as &flag

最外面的代码可能是

proc sql;
  create table want as 
  select have.*

  %apply_concepts (data=DIAGNOSES, concepts=DX_CLASS, flag=xxx yyy)

  from DIAGNOSES as have
  ;

我的第一个答案中的信息应该指导编写do'er并且它是do'ee。尝试后,如果您有任何问题,请创建一个新问题。

注意:SAS有许多其他方法可以将分类查找和应用程序作为新列执行。其中包括格式,合并和哈希对象。并且每种方式也可以利用'do-er'和'do-ee'流程。最重要的是在开始宏观化之旅之前理解数据处理的简单代码版本。

答案 3 :(得分:0)

由于您已经拥有一个宏,因此最简单的方法是将宏更改为一次支持多个标志。您可以保持逻辑相同,只需添加一些宏循环。

%macro flag(flaglist);
%local flagname i n &flaglist;
%let n=%sysfunc(countw(&flaglist));

proc sql noprint;
%do i=1 %to &n ;
  %let flagname=%scan(&flaglist,&i);
  %let &flagname='Not Found';
  select quote(trim(icd)) into :&flagname separated by ','
    from format_table
    where flag = "&flagname"
  ;
%end;
quit;

data mydata;
  set mydata;
%do i=1 %to &n ;
  %let flagname=%scan(&flaglist,&i);
  &flagname = diag in (&&&flagname);
%end;
run;
%mend flag;