志当存高远i 发表于 2019-6-20 14:01:13

SAS 循环与数组


SAS提供了循环语句以满足在编程中需要多次执行相同操作的情 况。有时还需要对不同的变量执行相同的操作,此时可定义SAS数组,并通过数组名和下标来引用这些变量。

1 循环
SAS循环语句通常有如下几种形式:迭代DO语句、DO WHILE语句 和DO UNTIL语句。

1.迭代DO语句
迭代DO语句的基本形式如下:
DO索引变量=开始值<TO结束值><BY递进值><WHILE(表达式)><UNTIL(表达式)>;
…   SAS语句…
END;

其中:
·索引变量用于指定一个变量,若该变量不存在,则创建新变量。DO语句和END语句之间的语句称为DO组,索引变量的值会控制DO组 的执行。
·开始值指定索引变量的初始值,可以是表达式或表达式序列。DO组的执行从“索引变量=开始值”开始。在循环的第一个迭代开始前,对开始值求值。如果结束值和递进值不存在,那么开始值可能是一系列 项,则DO语句的形式如下。
DO索引变量=项1<,…项n>;
项1~项n可以是数字常量、字符常量或变量。SAS为列表中的每个 项执行一次DO组。

·结束值指定索引变量的结束值。当开始值和结束值都存在时,DO 组执行直到下面任意一种情况发生时循环执行结束:索引变量的值超过 结束值;DO组中存在指示退出循环的语句,例如LEAVE语句、GO TO 语句;如果有WHILE或UNTIL选项,则WHILE之后的表达式不满足或 UNTIL之后的表达式满足(可参考后面对DO UNTIL语句和DO WHILE 语句的介绍)。
·递进值指定一个数字,或者是产生数字值的表达式,来控制索引 变量的增量。递进值在循环执行前进行计算。因此,在DO组内对递进 值的修改不会影响循环迭代次数。每次迭代后,索引变量的值为其当前 值的基础上增加递进值。如果未指定递进值,则索引变量的值增加1。

data work.square;
do x=1 to 5 by 2;
y = x**3;
output;
end;
run;
proc print data=work.square;
run;

2.DO UNTIL语句
DO UNTIL语句重复执行DO循环中的语句,直到条件为真。DO UNTIL语句的基本形式如下:
DOUNTIL(表达式);
...SAS语句...
END;
表达式可是任意的SAS表达式。DO UNTIL语句中至少包含一个表 达式,也可以包含多个表达式。在DO循环中的语句执行完成后将对表 达式求值。所以,DO循环至少被执行一次。

将给定字符串中包含的各个单词分开写入数据集中。 在DO循环中使用SCAN函数依次读取字符串中的单词,并存储在变量word中且输出。LENGTHN函数用于判断循环结束的标志。当SCAN 函数扫描到字符串结尾,word值为空时,LENGTHN函数返回0,循环 结束。

代码如下:
datawork.all;
lengthword$20;
dropstring;
string='Thequickbrownfoxjumpsoverthelazydog.';
do   until(lengthn(word)=0);
count+1;
word=scan(string,count);
output;
end;
run;
procprintdata=work.allnoobs;
run;

3.DO WHILE语句
DO WHILE语句在条件为真时重复执行DO循环。DO WHILE语句 的基本形式如下:
DOWHILE(表达式);
...SAS语句...
END;
表达式可是任意的SAS表达式。DO UNTIL语句中至少包含一个表 达式,也可以包含多个表达式。在DO循环中的语句被执行前先对表达式求值。如果第一次执行时表达式为假(false),DO循环不会被执行。

将给定字符串中包含的各个单词分开写入数据集中。 代码如下:
datawork.all;
lengthword$20;
dropstring;
string='Thequickbrownfoxjumpsoverthelazydog.';
word=scan(string,1);
do   while(lengthn(word)>0);
count+1;
word=scan(string,count);
output;
end;
run;

因为要WHILE表达式必须成立才会执行DO循环,也就是说在执行 到DO WHILE语句之前,word不能为空或缺失值,所以代码中先对word 值赋值(word可以赋值为其他任何不为空的字符值)。DO循环中,当 SCAN函数扫描到字符串结尾,word值为空时,LENGTHN函数返回0,不满足条件lengthn(word)>0,循环结束。所生成的数据集与例3.25的 结果一样,这里不再给出。

下面是对3种循环语句的比较:

·迭代DO语句基于索引变量值重复执行DO语句和END语句之间的SAS语句。使用迭代DO语句较容易控制循环次数。
·DO UNTIL语句重复执行在DO循环中的语句,直到条件为真。DOUNTIL语句在每次DO循环迭代结束后检查条件。
·DO WHILE语句在条件为真时重复执行DO循环中的语句。DO WHILE语句在每次DO循环迭代开始前检查条件。

2SAS数组
如果需要对许多变量做相同的操作,虽然可以通过写一系列赋值语句来实现,使用数组可以简化程序代码。

数组是一组以特殊顺序排列并由数组名标识的SAS变量。只要一组变量名都是同一类型,例如都是数值型或字符型,就可以为该组变量定 义一个数组。这些变量可以是数据集中已经存在的,也可以是要创建的 新变量。数组仅仅在当前DATA步中存在,在同一DATA步中,数组按 名字区分。SAS数组不是一种数据结构,只是临时标识一组变量较方便 的方法,在这点上SAS数组不同于其他编程语言中的数组。

1.数组定义及引用
在DATA步中使用ARRAY语句定义数组。定义数组的基本形式如 下:
ARRAY数组名{下标}   <$>   <长度><数组元素><(初始值列表)>;
其中:

·数组名是指定给数组的名称。该数组名在同一DATA步中不能与任何其他变量名或关键字重名。其命名需遵循SAS变量的命名规范(不超 过32个字符,以字母或下划线开始,可包含字母、数字和下划线)。
·下标可以有多种形式,通常为指定数组元素个数、上下边界或*。*表示通过计算数组元素个数确定数组下标。
·$指定数组中的元素是字符元素。如果数组元素是数字元素或先前 已经定义的字符元素,则不需要使用$。
·长度指定先前未指定长度的元素的长度。
·数组元素指定组成数组的元素名称。
·初始值列表给出数组中对应元素的初始值,以空格隔开。定义数组时的括号可以是()、{}或[]。定义数组时的下标形式指定了数组维度、各个维度的下边界和上边界。

还可以通过不同格式的下标指定多维数组,多个维度之间用逗号(,)分隔,同一个维度内的上下边界使用冒号(:)分隔,如表3.8所示。

数组元素可以是数值型或字符型,并且可以以任何顺序列出,其个数必须等于括号{}中给出的下标值。

数组元素可以是已经存在的变量或不存在的变量,当数组元素是不存在的变量时,SAS会创建新变量。除了列出变量外,变量可以是关键 字_NUMERIC_、_CHARACTER_或_ALL_。


还可使用关键字_TEMPORARY_来创建临时数据元素。临时数据元素不会出现在输出数据集中,并且其值总是自动保持,而不会在DATA 步的每次迭代开始时自动设置为缺失值。临时数组元素仅用于计算,如果要保留计算结果,需要将结果赋值给其他变量。使用临时数组元素的 好处是可以提高性能。

使用数组名引用变量时,要给出数组名和该变量的下标。例如,使 用如下ARRAY语句定义变量STORE,共4个元素,分别为变量Macys、Penneys、Sears和Target。
arrayStore{4} MacysPenneysSearsTarget;

使用数组名引用变量时,STORE{1}是变量Macys,STORE{2}是Penneys,STORE{3}是Sears,STORE{4}是Target。 如果定义数组时指定了上下边界,例如:
arrayMonth{4:6}AprilMayJune;
则Month{4}是变量April,Month{5}是变量May,Month{6}是变量June。

这样就可以在循环中通过改变数组下标来操作每个数组元素对应的 变量,所以数组经常在DO组中使用。

2.数组函数
SAS提供了DIM、HBOUND和LBOUND函数返回数组中指定维度 的元素个数、上边界和下边界。

DIM函数返回一维数组中的元素个数或多维数组中指定维度中的元素个数。其形式如下:
DIM<n>(数组名)或DIM(数组名,维度)
HBOUND函数返回一维数组的上边界或多维数组中指定维度的上 边界。其形式如下:
HBOUND<n>(数组名)或HBOUND(数组名,维度)
LBOUND函数返回一维数组的下边界或多维数组中指定维度的下边 界。其形式如下:
LBOUND<n>(数组名)或LBOUND(数组名,维度)
其中:

·n指定维度的整型常量。如果未指定n值,则返回数组的第一维的结果。
·数组名指定在同一DATA步中先前定义的数组名称。
·维度是指定维度的数字常量、数字变量或数字表达式。
3.DO循环中引用数组元素 将数组与迭代DO语句结合使用,在对用数组所表示的变量进行处理时会变得简单。其基本形式如下:
DO索引变量=1TO数组元素个数;
…   SAS语句…
END;
使用数据集saslib.revenue_quarter制定明年的销 售计划,预期各季度的销售额为今年的150%。

代码如下:
datasaslib.revenue_2014;
setsaslib.revenue_quarter;
arrayQuarter{4} Rev_Q1-Rev_Q4;
do i=1 to 4;
Quarter{i}=Quarter{i}*1.5;
end;
dropi;
run;
其中:

·ARRAY语句定义了数组Quarter,其元素个数为4。因为变量 Rev_Q1到Rev_Q4在输入数据集中存在,所以该数组只是引用存在的变 量Rev_Q1到Rev_Q4,并不创建新变量。这里数组元素使用了简化的表 达方式。
·在DATA步的每次迭代中,通过在DO循环中引用Quarter{1}到 Quarter{4}来分别操作变量Rev_Q1到Rev_Q4,将销售额在现有销售数据 的基础上增加50%。
数据集saslib.revenue_2014在VIEWTABLE窗口打开如图所示。


页: [1]
查看完整版本: SAS 循环与数组