带宏的分类变量

时间:2012-11-01 01:15:24

标签: sas sas-macro

我正在尝试在sas中创建分类变量。我编写了以下宏,但是当我尝试运行时出现错误:“无效的符号变量名称xxx”。我不确定这是否是实现目标的正确方法。

这是我的代码:

%macro addvars;
proc sql noprint;
select distinct coverageid 
into :coverageid1 - :coverageid9999999
from save.test;

%do i=1 %to &sqlobs;
%let n=coverageid&i;
%let v=%superq(&n);
%let f=coverageid_&v;
%put &f;
data save.test;
 set save.test;
%if coverageid eq %superq(&v)
  %then &f=1;
  %else &f=0;
run;
%end; 
%mend addvars;
%addvars;

2 个答案:

答案 0 :(得分:4)

您正在以不正确的方式将宏代码与数据步骤代码组合在一起。 %if =宏语言,意味着您实际上正在评估文本“coverageid”是否等于%superq(& v)评估的文本,而不是coverageid变量的内容是否等于& v中的值。您可以将%if转换为if,但即使您正常工作也会非常低效(您将重写数据集N次,因此如果您有覆盖ID为1500的值,则重写整个500MB数据集或1500时间,而不只是一次)。

如果您要做的是采用变量'coverageid'并将其转换为一组变量,这些变量由coverageid的所有可能值组成,1/0二进制,对于每个变量,有一些方法可以做到这一点。我很确定ETS模块有一个程序可以做到这一点,但我不记得它在我的脑海中 - 如果你要将它发布到SAS邮件列表,其中一个人无疑会有很快。

对我而言,简单的方法是使用完全的datastep代码来完成此操作。首先确定COVERAGEID有多少潜在值,然后将每个值分配给一个直接值,然后将值赋给正确的变量。

如果COVERAGEID值是连续的(即1到某个数字,没有跳过,或者你不介意跳过)那么这很容易 - 设置一个数组并迭代它。我会假设它们不是连续的。

*First, get the distinct values of coverageID.  There are a dozen ways to do this, this works as well as any;
proc freq data=save.test;
tables coverageid/out=coverage_values(keep=coverageid);
run;

*Then save them into a format.  This converts each value to a consecutive number (so the lowest value becomes 1, the next lowest 2, etc.)  This is not only useful for this step, but it can be useful in the future in converting back.;

data coverage_values_fmt;
set coverage_values;
start=coverageid;
label=_n_;
fmtname='COVERAGEF';
type='i';
call symputx('CoverageCount',_n_);
run;
*Import the created format;
proc format cntlin=coverage_values_fmt;
quit;

*Now use the created format.  If you had already-consecutive values, you could skip to this step and skip the input statement - just use the value itself;
data save.test_fin;
set save.test;
array coverageids coverageid1-coverageid&coveragecount.;
do _t = 1 to &coveragecount.;
  if input(coverageid,COVERAGEF.) = _t then coverageids[_t]=1;
  else coverageids[_t]=0;
end;
drop _t;
run;

答案 1 :(得分:1)

这是另一种不使用格式的方式,可能更容易理解。

首先,只需制作一些测试数据:

data test;
    input coverageid @@;
    cards;
3 27 99 105
;
run;

接下来,为coverageid的每个级别创建一个没有观察但只有一个变量的数据集。请注意,此方法允许使用任意值。

proc transpose data=test out=wide(drop=_name_);
    id coverageid;
run;

最后,创建一个组合初始数据集和宽数据集的新数据集。然后,对于x的每个级别,查看每个分类变量并决定是否将其“打开”。

data want;
    set test wide;
    array vars{*} _:;
    do i=1 to dim(vars);
        vars{i} = (coverageid = substr(vname(vars{i}),2,1));
    end;
    drop i;
run;

该行

vars{i} = (coverageid = substr(vname(vars{i}),2));

可能需要更多解释。 vname返回变量的名称,由于我们未在prefix中指定proc transpose,因此所有变量都被命名为_1_2,所以我们采用从第二个位置开始的变量名的子串,并将其与coverageid进行比较;如果它们是相同的,我们将变量设置为1;否则评估为0。