【问题标题】:Proc sql and macro variablesProc sql 和宏变量
【发布时间】:2019-11-27 00:02:21
【问题描述】:

我正在尝试运行一个代码,该代码应该适用于考虑到不同因素而创建的表。由于这些因素可能超过 1,我决定创建一个宏 %let 来列出它们:

%let list= factor1 factor2 ...;

我想做的是运行代码来使用不同的因素创建这些表。对于每个因素,我使用proc means 计算平均值和标准差,因此我应该在proc means 为每个因素创建的表中包含变量&list._mean&list._stddev。该表标记为t2,我需要加入另一个表t1。从 t1 我正在考虑所有变量。

因此,我的主要困难在于 proc sql:

proc sql;
create table new_table as
select t1.*
, t2.&list._mean as mean
, t2.&list._stddev as stddev
from table1 as t1
left join table2 as t2
on t1.time=t2.time
order by t2.&list.
quit;

此代码返回错误,我认为是因为我正在考虑 t2.factor1 factor2,即 t2 仅适用于第一个因素,而不适用于第二个因素。 我期望的是以下内容:

  proc sql;
    create table new_table as
    select t1.*
    , t2.factor1._mean as mean
    , t2.factor1._stddev as stddev
    from table1 as t1
    left join table2 as t2
    on t1.time=t2.time
    order by t2.factor1.
    quit;

另一个是factor2。 更新代码:

%macro test_v1(
     _dtb
    ,_input
    ,_output
    ,_time
    ,_factor
);

data &_input.;
    set &_dtb..&_input.;
    keep &_col_period. &_factor.;
run;

proc sort data = work.&_input.
           out = &_input._1;
    by &_factor. &_time.;
run;

%put ERROR: 2

proc means data=&_input._1 nonobs mean stddev;
    class &_time.;
    var &_factor.;
    output out=&_input._n (drop=_TYPE_) mean= stddev= /autoname ;
run;

%put ERROR: 3

proc sql;
create table work.&_input._data as 
select t1.*
        ,t2.&_factor._mean as mean
        ,t2.&_factor._stddev as stddev
from &_input. as t1
left join &_input._n as t2
on t1.&_time.=t2.&_time.
order by &_factor.;
quit;

%mend test_v1;

然后我的问题是如何考虑多个因素,在宏中定义为列表、表的列以及宏中的输入数据(例如:%test(dataset, tablename, list)

【问题讨论】:

  • 即使您修复了语法错误,您的计划也无法奏效。您不能将 FACTOR1_MEAN 和 FACTOR2_MEAN 重命名为相同的名称。
  • 我认为你可以使用一步(proc 排序)而不是两步(data+proc 排序):proc sort data = have1(keep=time factor1) out = have3_1; by factor1 time; run; 而不是data data have2; set have1; keep time factor1; run; proc sort data = have2 out = have2_1; by factor1 time; run;
  • 为什么你的宏引用了一个完全未定义的宏变量_col_period?为什么要按“因子”变量而不是 TIME 排序?您是使用 FACTOR 变量作为分析变量还是分组变量?

标签: sas


【解决方案1】:

我怀疑尝试使用 PROC SQL 是使问题变得困难的原因。如果您坚持只使用普通的 SAS 语法,那么以空格分隔的变量名列表很容易使用。

所以拿你的代码并稍微调整一下:

%macro test_v1
(_dtb    /* Input libref */
,_input  /* Input member name */
,_output /* Output dataset */
,_time   /* Class/By variable(s) */
,_factor /* Analysis variable(s) */
);

proc sort data= &_dtb..&_input. out=_temp1;
  by &_time. ;
run;

proc means data=_temp1 nonobs mean stddev;
  by &_time.;
  var &_factor.;
  output out=_temp2 (drop=_TYPE_) mean= stddev= /autoname ;
run;

data &_output. ;
  merge _temp1 _temp2 ;
  by &_time.;
run;

%mend test_v1;

然后我们可以使用 SASHELP.CLASS 对其进行测试,将 SEX 作为“时间”变量,将 HEIGHT 和 WEIGHT 作为分析变量。

%test_v1(_dtb=sashelp,_input=class,_output=want,_time=sex,_factor=height weight);

【讨论】:

  • 错误 22-322:语法错误,应为以下之一:!, !!, &, *, **, +, ',', -, /, , =, >, >=, ?, AND, AS, CONTAINS, EQ, EQT, FROM, GE, GET, GT, GTT, LE, LET, LIKE, LT, LTT, NE, NET, OR, ^=, |,||,~=。这是我得到的错误。 proc sql的问题是我以这种方式申请t2。只到第一个因素,factor1,所以我有 t2.factor1 factor2,这是错误的,我应该有:t2.factor1,t2.factor2
  • @a.rimbaud 正如 Tom 所展示的,Proc MEANS 有一个庞大的功能集供您使用。而不是编写一个简单地将 args 替换为语句的宏,学习 Procs 语句和没有宏的编码意味着对长期支持的支持更少,并使编码器或代码继承者的生活更轻松。
【解决方案2】:

您可以尝试通过扫描因素列表来将宏循环添加到您的宏中。它可能看起来像:

%macro test(list);
   %do i=1 to %sysfunc(countw(&list,%str( )));
      %let factorname=%scan(&list,&i,%str( ));
       /* if macro variable list equals factor1 factor2 then there would be
       two iterations in loop, i=1 factorname=factor1 and i=2 factorname=2*/
      /*your code here*/
   %end
%mend test;

更新:

%macro test(_input, _output, factors_list); %macro d; %mend d;
%do i=1 %to %sysfunc(countw(&factors_list,%str( )));
%let tfactor=%scan(&factors_list,&i,%str( ));
proc sort data = work.&_input.
           out = &_input._1;
    by &factors_list. time;
run;

proc means data=&_input._1 nonobs mean stddev;
    class time;
    var &tfactor.;
    output out=&_input._num (drop=_TYPE_) mean= stddev= /autoname ;
run;

proc sql;
   create table &_output._&tfactor as
   select t1.*
   , t2.&tfactor._mean as mean
   , t2.&tfactor._stddev as stddev
   from &_input as t1
   left join &_input._num as t2
   on t1.time=t2.time
   order by t1.&tfactor;
quit;

%end;
%mend test;

%test(have,newdata,factor1 factor2);

有数据集:

+------+---------+---------+
| time | factor1 | factor2 |
+------+---------+---------+
|    1 |   12345 |    1234 |
|    2 |     123 |      12 |
|    3 |       1 |      -1 |
|    4 |     -12 |    -123 |
|    5 |   -1234 |  -12345 |
|    6 |    9876 |     987 |
|    7 |      98 |       8 |
|    8 |       9 |       7 |
|    1 |    1234 |     123 |
|    2 |      12 |       1 |
|    3 |      12 |     -12 |
|    4 |    -123 |   -1234 |
|    5 |  -12345 | -123456 |
|    6 |     987 |      98 |
|    7 |       9 |      -9 |
|    8 |    1234 |    1234 |
+------+---------+---------+

NEWDATA_FACTOR1:

+------+---------+---------+---------+--------------+
| time | factor1 | factor2 |  mean   |    stddev    |
+------+---------+---------+---------+--------------+
|    5 |  -12345 | -123456 | -6789.5 | 7856.6634458 |
|    5 |   -1234 |  -12345 | -6789.5 | 7856.6634458 |
|    4 |    -123 |   -1234 |   -67.5 | 78.488852712 |
|    4 |     -12 |    -123 |   -67.5 | 78.488852712 |
|    3 |       1 |      -1 |     6.5 | 7.7781745931 |
|    7 |       9 |      -9 |    53.5 | 62.932503526 |
|    8 |       9 |       7 |   621.5 | 866.20580695 |
|    3 |      12 |     -12 |     6.5 | 7.7781745931 |
|    2 |      12 |       1 |    67.5 | 78.488852712 |
|    7 |      98 |       8 |    53.5 | 62.932503526 |
|    2 |     123 |      12 |    67.5 | 78.488852712 |
|    6 |     987 |      98 |  5431.5 |  6285.472178 |
|    1 |    1234 |     123 |  6789.5 | 7856.6634458 |
|    8 |    1234 |    1234 |   621.5 | 866.20580695 |
|    6 |    9876 |     987 |  5431.5 |  6285.472178 |
|    1 |   12345 |    1234 |  6789.5 | 7856.6634458 |
+------+---------+---------+---------+--------------+

NEWDATA_FACTOR2:

+------+---------+---------+----------+--------------+
| time | factor1 | factor2 |   mean   |    stddev    |
+------+---------+---------+----------+--------------+
|    5 |  -12345 | -123456 | -67900.5 | 78567.341564 |
|    5 |   -1234 |  -12345 | -67900.5 | 78567.341564 |
|    4 |    -123 |   -1234 |   -678.5 |  785.5956339 |
|    4 |     -12 |    -123 |   -678.5 |  785.5956339 |
|    3 |      12 |     -12 |     -6.5 | 7.7781745931 |
|    7 |       9 |      -9 |     -0.5 |  12.02081528 |
|    3 |       1 |      -1 |     -6.5 | 7.7781745931 |
|    2 |      12 |       1 |      6.5 | 7.7781745931 |
|    8 |       9 |       7 |    620.5 | 867.62002052 |
|    7 |      98 |       8 |     -0.5 |  12.02081528 |
|    2 |     123 |      12 |      6.5 | 7.7781745931 |
|    6 |     987 |      98 |    542.5 | 628.61792847 |
|    1 |    1234 |     123 |    678.5 |  785.5956339 |
|    6 |    9876 |     987 |    542.5 | 628.61792847 |
|    1 |   12345 |    1234 |    678.5 |  785.5956339 |
|    8 |    1234 |    1234 |    620.5 | 867.62002052 |
+------+---------+---------+----------+--------------+

【讨论】:

  • 谢谢阿列克谢。 %let 列表=因子 1 因子 2;我是这样写的:%macro test(list); %do i=1 %to %sysfunc(countw(&list,%str())); %let factorname=%scan(&list,&i,%str()); %macro_v1(dataset,table, time, &list); %end %mend test; 但是没有返回任何输出。我在macro_v1中使用列表的方式是否正确?
  • 试试这个:%macro test(list); %do i=1 %to %sysfunc(countw(&list,%str())); %let factorname=%scan(&list,&i,%str()); %macro_v1(dataset,table, time, &factorname); %end; %mend test; %test(&list);
  • 它给了我以下错误:“错误:文本表达式 &list 包含对宏变量列表的递归引用。宏变量将被赋予空值。”
  • @a.rimbaud tfactor 存储来自 factor_list 的一个因子,并且在每次迭代中它都会改变。例如我们有 factor_list 等于 factor1 factor2 factor3,countw 函数计算被空格分割的单词的数量,然后循环迭代每个单词,并且 tfactor 包含每次迭代中的单词(在第一次迭代时,tfactor 包含 factor_list 的第一个单词,等于 factor1等)
  • 谢谢阿列克谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-31
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多