在sas中定义变量以清理代码

时间:2013-03-07 05:36:52

标签: dataset sas

我是来自python,java和C ++的SAS的新手。从这些语言中,在编写/重复大型语句时要正确的做法是将它们封装在一次定义的变量中,并在代码中重复多次。

即。而不是每次合并两个相似的数据集时反复写出相同的where语句,我想写:

WHERE_CONDITION_VARIABLE = 'X in (10, 100, 1000, 10000 ......100000000);

data output;
merge in1 in2;
WHERE WHERE_CONDITION_VARIABLE;
run;

data output2;
merge in3 in4;
WHERE WHERE_CONDITION_VARIABLE;
run;

不幸的是,我无法弄清楚如何定义一个变量,例如WHERE_CONDITION_VARIABLE来简化代码。我在SAS中可以做什么?

3 个答案:

答案 0 :(得分:4)

您可以使用宏变量。 你可以像这样定义它们:

%let WHERE_CONDITION_VARIABLE = X in (10, 100, 1000);

并像这样引用它们:

&WHERE_CONDITION_VARIABLE

答案 1 :(得分:1)

SAS有很多选项可以避免重复代码;以这种方式它实际上很像python,虽然实现它的方法有点不同,因为你有一个单独的编译步骤(所以你不能像你直接问的那样说什么)。 / p>

首先,你有宏变量。如果您只是多次重复文本,则可以在宏变量中定义它,如下所示:

%let condition=X in (1,10,100,1000);

将宏变量视为您编写的文本。它们不需要引号或其他文本限定符,除非它们旨在将它们包含为合法代码,即:

%let condition=X in ('A','B','C');

是合法的,但

%let condition="X in ('A','B','C')";

可能不是您想要的(除非您希望将其评估为字符串,无论如何)。

通过宏变量,您还可以在datastep中生成更大量的代码,然后将其包含在内。例如,如果您有一个包含条件列表的数据集,则可以这样应用它们:

data conditions;
format condition $50.;
input condition $;
datalines4; 
if x = 15 then y=5;
if x = 20 then y=10;
if x = 20 and z = 5 then y=15;
if x = 20 and z = 10 then y=20;
;;;;
run;

proc sql;
 select condition into :condlist separated by ' ' from conditions;
quit;

data want;
set have;
&condlist;
run;

这将采取条件"条件"数据集并将其推入宏变量"& condlist"。 PROC SQL调用是将其转换为宏变量的最简单方法,但还有其他方法; CALL SYMPUT也可以在数据步骤中执行,或者您可以将其写入文本文件,然后%包含文本文件作为代码。这通常通过生成对宏的调用在高级编程中使用,条件数据集提供宏参数;在这种情况下,您可能有一个宏

%macro cond(x=,y=,z=);
 if x=&x and z=&z then y=&y;
%mend cond;

然后,您可以从仅具有x,y,z值的数据集生成对cond的调用:

proc sql;
 select cats('%cond(x=',x,',y=',y,',z=',z,')') into :condlist separated by ' ' from conditions;
quit;

并以相同的方式使用它。

宏编程通常是避免代码蠕变的好方法;宏写入一次然后可以使用不同的参数运行多次。宏可以是从数据步骤内执行的一行代码(如上所述)到包含多个DATA和PROC步骤的数百行的任何地方。宏编程本身就是一个复杂的话题,值得一读。


您也可以在SAS中编写功能。 PROC FCMP(函数编译)允许您编写相当复杂的函数并在数据步骤甚至PROC语句中执行它们。如果您有9.2,那么http://www.lexjansen.com/pharmasug/2011/tu/pharmasug-2011-tu07.pdf是开始使用FCMP的好地方;如果你有9.3,我还没有看到任何论文(但可能有一些)在FCMP中展示了新的东西。 FCMP是相当新的,因此SAS的每次迭代都会有很多变化。

以下是FCMP的一个例子:

proc fcmp 
 outlib=work.funcs.Test; /* where will the functions be saved */ 
 function condition(x); /* declare a function returning a number */ 
 if x in (1,10,100,1000) then return(1);
 else return(0);
endsub; 
quit; 


data have;
do x = 1,5,10,20,100,150,1000,1500;
output;
end;
run;

options cmplib=work.funcs; 
data want;
set have;
if condition(x) then output;
run;

您还拥有CALL EXECUTE语句,该语句允许您直接执行数据集中的代码。使用相同的CONDITIONS数据集:

data _null_;
 set conditions end=eof;
 if _n_ = 1 then call execute('data want; set have;');
 call execute(condition);
 if eof then call execute('run;');
run;

这将有效地构建一个数据步骤,该步骤在数据 null 步骤之后立即执行,其代码与宏变量示例中的相同。调用执行的工作方式稍有不同,所以虽然在这个例子中不应该有任何区别,但是有一些问题会导致问题(或者可能是有利的)。你使用的取决于具体情况。特别是对于CALL EXECUTE,请阅读文档和在线论文(最常见的SUGI论文)以了解更多详情。


除了通过宏变量或CALL EXECUTE直接执行代码之外,还有许多其他方法可以执行任务以避免使用壁纸代码。例如,为了更容易执行上面的if语句,您可以使用格式。格式将一个值转换为另一个值;最常见的是,您可能会遇到像DOLLAR6.2'这将从3.5的数字给你$ 3.50。但是,格式也可以用来替换if-this-then-that表达式。如果只有X和Y(并且没有Z条件),那么你可以这样做,给定这个条件数据集:

data conditions;
input x y;
datalines;
1 5
2 10
3 20
4 50
5 100
;;;;
run;

data for_fmt;
set conditions;
rename x=start y=label;
fmtname='XTOY';
type='i'; *type=i means numeric informat, so numeric to numeric conversion.  Informat = to numeric, Format= to character.;
run;

proc format cntlin=for_fmt;
quit;

data want;
set have;
y = input(x,XTOY.);
run;

你有一行代码将x转换为y。 (当然有一些代码设置格式,但它可以与主代码分开,并包含在代码的设置部分,如c中的.h文件。)

您还有哈希表查找,当您有更复杂的转换时,它们非常有用 - 从1到多或从1到1.它们的工作方式就像它们听起来一样 - 您将哈希表加载到内存中并执行查找。 http://support.sas.com/rnd/base/datastep/dot/hash-getting-started.pdf是一个很好的起点。


最后,避免重复代码的一个好方法是使用较少的单独数据集。 SAS数据步骤和程序具有" BY"声明可用,这意味着它们将BY变量的每个不同值视为一个单独的数据集。变量名称和长度需要匹配,因为它在技术上仍然是一个数据集,但如果您有许多类似数据的数据集,并且想要对每个数据集执行相同的操作,则可以使用BY语句而不是多次执行它们一次

例如,假设您有数据集SASHELP.CARS。您可能想为每辆汽车分别计算一些东西。你可以这样做:

data acura;
set sashelp.cars;
if make='ACURA';
run;    

data honda;
set sashelp.cars;
if make='HONDA';
run;

然后分别在每个数据集上运行代码。但是,更常见的方法是使用BY语句:

proc means data=sashelp.cars;
by make;
var mpg_city mpg_highway;
run;

现在,每个品牌都会有一个单独的页面。您也可以在数据步骤处理中使用BY语句;你得到变量FIRST.make和LAST.make告诉你你是否在新MAKE的第一条记录或MAKE的最后一条记录(价值变化之前的记录),这可以让你做根据您在数据集的BY组中的位置(例如,if first.make then counter=0;将允许您在每次make中有新值时重置计数器。)对BY组的唯一警告是,您必须在使用之前通过BY变量对数据集进行排序(或者对该变量具有索引,或者两者都有)。这对于分析引导程序示例或其他具有许多几乎相同的数据集并对其执行相同操作的进程非常有用。

答案 2 :(得分:-2)

我假设您要将所有WHERE条件变量放入存储桶中,然后根据类似索引的结构(Python)使用它们。

如果是这种情况,那么您可能需要查看“INTO”。 在“INTO”中,你将丢弃所有的X. 然后你可以随时拿走它们。