Sas 带宏的分类变量

Sas 带宏的分类变量,sas,sas-macro,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

我试图在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;

您以一种不正确的方式将宏代码与数据步骤代码组合在一起。%if=macro language,这意味着您实际上是在计算文本“coverageid”是否等于%superq(&v)计算结果所对应的文本,而不是coverageid变量的内容是否等于&v中的值。您可以将%if转换为if,但即使您让它正常工作,效率也会非常低(您将数据集重写N次,因此如果您有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;

这里有另一种不使用格式的方法,可能更容易遵循

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

data test;
    input coverageid @@;
    cards;
3 27 99 105
;
run;
接下来,为
coverageid
的每个级别创建一个数据集,其中不包含观察值,只有一个变量。请注意,这种方法允许在此处使用任意值

proc transpose data=test out=wide(drop=_name_);
    id coverageid;
run;
最后,创建一个新的数据集,将初始数据集和宽数据集结合起来。然后,对于x的每个级别,查看每个分类变量并决定是否将其“打开”

线路

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

可能需要更多的解释
vname
返回变量的名称,由于我们没有在
proc transpose
中指定
前缀
,所有变量的名称都类似于
\u 1
\u 2
,等等。因此我们取从第二个位置开始的变量名称的子字符串,并将其与
coverageid
进行比较;如果它们相同,我们将变量设置为1;否则它的计算结果为0。

您提到的SAS邮件列表是这样的:另外,在分解您在这里编写的代码后,我可能还有一些问题,所以如果您不介意,我将在这里的注释中发布它们。我得到以下错误:错误:编号变量列表(coverageid1 coverageid)上缺少数字后缀。警告:定义具有零元素的数组。错误22-322:语法错误,应为以下内容之一:名称,(,;,ALL,CHARACTER,CHAR,NUMERIC。错误200-322:符号无法识别,将被忽略。啊,忘记-使用CALL SYMPUTX而不是CALL SYMPUT,或&coverage count。其中将包含大量空格。仍在努力理解所有这些好东西。不得不说,来自T-SQL和C#,SAS有点…复杂(这个词对吗?)在游戏的这一阶段,但从统计数据上看肯定要好得多。我注意到一件事……我如何回去找出原始的Coverage id是什么?我希望变量名中有原始的数字,但如果SAS中的人们通常不是这样做的,那很好,但是找出原始id的简单方法是什么(我知道我可以使用proc-sql获得一个id列表,然后将其放入excel,然后在下一列中添加1,2,3,…)有两件事让我困惑:1)为什么有时会看到
\n\u、\u name\u或数组vars{*}\u:;
在sas中的
\u
有什么意义?2)两种解决方案都使用输入函数(它是函数吗?),但第一个解决方案传递参数,而第二个解决方案没有参数?这意味着不同的事情吗?这些都是非常基本的SAS问题,因此您显然是SAS新手。我鼓励您开始阅读一些文档。
input
是一个函数和一个语句,它们做不同的事情。在这种情况下,它只是做不到o将数据输入到数据集中。
\u name\uu
只是SAS在运行
proc transpose
时生成的变量:
表示“所有以“\uu”开头的变量”。
vars{i} = (coverageid = substr(vname(vars{i}),2));