You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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.

报错原因

  1. 宏解析顺序冲突:call execute(&F)在data步执行时,会将宏定义文本直接提交给SAS处理器,但%macro和%mend属于宏语句,不能在data步的开放代码中直接执行,导致语法解析错误。
  2. 宏命名冲突:两条宏定义都使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 06:37:48