2

我正在尝试在 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;
4

2 回答 2

4

您以不正确的方式将宏代码与数据步骤代码组合在一起。%if = 宏语言,这意味着您实际上是在评估文本“coverageid”是否等于 %superq(&v) 评估的文本,而不是 coverageid 变量的内容是否等于 &v 中的值。您可以将 %if 转换为 if,但即使您让它正常工作,它也会非常低效(您正在重写数据集 N 次,因此如果您有 1500 个coverageID 值,您将重写整个 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;
于 2012-11-01T01:57:06.817 回答
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返回变量的名称,并且由于我们没有指定 a prefixin proc transpose,所有变量都被命名为_1,_2等。所以我们取变量名称从第二个位置开始的子字符串,并将其与coverageid;进行比较 如果它们相同,我们将变量设置为 1;否则评估为 0。

于 2012-11-01T20:51:07.103 回答