如何在SAS中实现多变量分组宏并执行数据集列中的宏代码?
SAS实现可变参数分组汇总宏及执行报错解决方法
需求背景
需要在SAS中实现支持一个或多个变量分组的汇总宏,功能类似R中使用可变参数(...)的分组汇总逻辑。R示例代码如下:
example <- function(...) { vars1 <- syms(...) df1 <- mtcars %>% group_by(!!!vars1) %>% summarise(Mean = mean(mpg)) df2 <- mtcars %>% group_by(!!!vars1) %>% summarise(Median = median(hp)) }
现有尝试与报错
为实现需求,将宏定义存储在名为ref的数据集Macro_Nm列中,数据内容如下:
| Macro_Nm |
|---|
| %macro grp_by_turnover; Rptmth,mia_grp,acctnpl,NewNPL_byClass,turnover1band,CustIDBand %mend grp_by; |
| %macro grp_by_turnover; Rptmth,mia_grp,acctnpl %mend grp_by; |
尝试通过以下代码读取并执行该列中的宏代码,出现报错:
%macro ExtractACell(DThave,rownum, VarName, Name); data _null_; set &DThave.(obs=&rownum. firstobs=&rownum. keep = &VarName.); call symputx(&Name., &VarName., "G"); stop; run; %mend ExtractACell; data _null_; %ExtractACell(ref, 11, F, "F"); %put &F; call execute(&F); run;
报错信息:
ERROR: Open code statement recursion detected.
ERROR: Macro keyword MEND appears as text.
WARNING: Extraneous text on %MEND statement ignored for macro definition GRP_BY_TURNOVER.
ERROR 180-322: Statement is not valid or it is used out of proper order.
报错原因
- 宏解析顺序冲突:
call execute(&F)在data步执行时,会将宏定义文本直接提交给SAS处理器,但%macro和%mend属于宏语句,不能在data步的开放代码中直接执行,导致语法解析错误。 - 宏命名冲突:两条宏定义都使用
grp_by_turnover作为宏名,重复定义会触发递归或语法检查错误。
报错解决方法
调整代码逻辑,通过call execute正确提交宏定义文本,同时避免重复宏名:
/* 读取数据集里的宏定义并执行 */ data _null_; set ref; /* 为每个宏定义添加唯一后缀,避免命名冲突 */ length macro_code $2000; macro_code = tranwrd(Macro_Nm, 'grp_by_turnover', cats('grp_by_turnover', _n_)); /* 使用单引号包裹宏代码,确保call execute正确提交宏语句 */ call execute('%nrstr(' || macro_code || ')'); run; /* 调用生成的宏示例 */ %grp_by_turnover1; %grp_by_turnover2;
可变参数分组宏的SAS实现方案
直接编写支持可变参数的SAS宏,无需将宏定义存储在数据集中,更符合SAS的宏编程规范:
方案1:使用位置可变参数
%macro grp_summary(data=, out_prefix=summary, ...); /* 获取分组变量列表 */ %let group_vars = &sysfunc(compbl(&...)); /* 生成均值汇总表 */ proc sql noprint; create table &out_prefix._mean as select &group_vars, mean(mpg) as Mean from &data group by &group_vars; quit; /* 生成中位数汇总表 */ proc sql noprint; create table &out_prefix._median as select &group_vars, median(hp) as Median from &data group by &group_vars; quit; %mend grp_summary; /* 调用示例:单个分组变量 */ %grp_summary(data=mtcars, cyl); /* 调用示例:多个分组变量 */ %grp_summary(data=mtcars, cyl, am);
方案2:使用关键字参数传递分组变量
%macro grp_summary(data=, group_vars=, out_prefix=summary); /* 生成均值汇总表 */ proc means data=&data noprint; class &group_vars; var mpg; output out=&out_prefix._mean mean=Mean; run; /* 生成中位数汇总表 */ proc means data=&data noprint median; class &group_vars; var hp; output out=&out_prefix._median median=Median; run; %mend grp_summary; /* 调用示例 */ %grp_summary(data=mtcars, group_vars=cyl am);
内容的提问来源于stack exchange,提问作者Wawa
相关产品推荐
相关产品推荐

