ARRAY使用的一些实例

1.Array语句缺失值的填充

data missing;
input x y$ z$ m;
cards;
. . . 1
2 . 3 .
;
run;
 
data result;
set missing;
array char _character_;
array numr _numeric_;
do over char;
if char eq "" then char="null";
end;
do over numr;
if numr eq . then numr=0;
end;
run;

结果显示: java


需求:
若是给定一个数据集,发现其中有不少变量确实,可是事先又不知道究竟是哪些变量缺失,并且该数据集数据结构很是不稳定,此次的变量数和下次的变量数可能不同,因此,尽管SAS有一个过程步PROC STDIZE能够完成相似的需求,可是对于这种需求是没法完成的,除非每次调用程序的时候更改PROC STDIZE的VAR变量列表,这在实际项目中时不可能的,主要缘由是维护代码成本过高。


程序解读:
1)程序声明了两个数组语句,一个是全部字符变量,一个是全部数值变量。
2)DO OVER CHAR 语句是循环语句,意思是循环全部的数组CHAR对应的变量(这里固然是全部的字符变量),每循环一次,程序将执行一次IF CHAR语句,若是CHAR EQ ""条件为真,则执行CHAR="null",不然不执行。
3)循环完毕全部的字符变量后,程序继续执行下面的DO OVER NUMR语句,原理和上面相似。
4)执行完两个循环语句后,系统执行RUN语句,输出第一条观测。程序跳回至DATA步开头,再次执行第二条观测,依此类推。
算法

2.统计及格人数

data score;
input id$ x y z;
cards;
a 75 84 65
b 54 74 71
c 51 56 52
d 50 50 60
;
run;
 
 
data qualify;
set score;
k=0;
array chengji(3) x y z;
array base(3)_temporary_ (60,60,60);
do i=1 to 3;
if chengji(i) ge base(i) then k+1;;
end;
if k=3 then output qualify;
run;

结果以下: 编程

score数据集: 数组


Qualify数据集: 数据结构


需求以下:
如今有四个学生选修了三门课程,x;y和z。其成绩单分布如数据集score,要求统计所欲课程都及格的学生,并输出该学生的成绩单。

程序解读:
1)程序编译后,数据指针指向score第一条观测,接下来设置变量K的初始值为0,而下面的两个ARRAY语句在程序编译的时候已经声明,程序不会执行一个声明语句,根据前面对临时数组的解释,这里BASE显然是一个临时数组名,且初始值都设置为60.接下来程序执行DO循环语句,并对DO循环语句里面的IF语句做出判断是否执行。
例如,当i=1时,chengji(1)对应x变量,BASE(1)=60,在第一条观测上,x=75,显然,条件成立,因而执行累加语句k+1,获得K=1(由于此时K的初始值为0)。而后DO语句执行END,并进入第二次循环,对CHENGJI(2)即Y变量执行一样的操做,因为84>60,K值再次被累加,获得K=2.最后,因为CHENGJI(3)即Z变量的值65>60,K值又一次被累加,此时程序跳出DO循环,最终在第一条观测上,K=3,接下来的IF语句显然成立,程序执行OUTPUT语句,输出 第一条观测

2)接下来,程序跳到DATA步开头,继续执行第二条观测,再次初始化K值为0,这一点很是重要!不然, 因为累加语句的变量本质上是一个RETAIN变量,PDV将会保留第一条观测时计算的K=3到第二条观测,这显然是不符合要求的,由于需求是要统计每个学生是否都及格,而不是统计累计有多少课程及格。

3)对第二条到最后一条观测,系统通过相似的执行,最后知足要求的显然只有第一条观测。 编程语言

3.统计选择题回答正确题数。
data single;
input id$ q1$ q2$ q3$ @@;
cards;
01 a b c 02 a b a
03 b a c 04 a b c
;
run;
 
 
data correct(drop=i);
k=0;
set single;
array q(3);
array crt(3) $_temporary_('a','b','c');
do i=1 to 3;
if q(i)=crt(i) then  k+1;
end;
run;
结果显示:
single数据集:


correct数据集: spa


需求以下:
对数据集single,一共有三道选择题,四个学生都给出了本身的答案,而每一题的正确答案只有一个,分别是a;b;c。试统计所有正确回答三个问题的学生。


程序解读:
参考上面的2.统计成绩及格人数

指针

4.横向排序变量
data a;
input x1-x7;
cards;
23 44 81 13 42 34 26
14 18 10 20 33 11 50
;
run;
 
data final;
set a;
array arr(1:7) x:;
array copy(1:7) cx1-cx7;
do m=1 to dim(arr);
copy(m)=arr(m);
end;
do i=1 to dim(copy);
do j=i+1 to dim(copy);
if copy(j) > copy(i) then do;
temp=copy(j);copy(j)=copy(i);copy(i)=temp;
end;
end;
end;
run;
结果显示以下:
a数据集:


final数据集: code

需求以下:
数据集A有7个变量,原始数据是无序的,如今要求从新生成7个新的变量,其值是对应的原7个变量的降序排列。

程序解读:
该程序的难点是如何排序,注意这里不是SORT过程的纵向排序,学过编程语言的读者应该对冒泡算法比较熟悉,该题就是利用冒泡算法来实现需求。
1)程序中的第四道第七行生成7个新的变量。

2)从第八行到倒数第二行程序执行冒泡算法,经过两个DO循环语句,在嵌套DO语句里面,经过比较相邻两个新变量的值,若是后一个变量值大于前面的变量值,借用一个中间临时变量TEMP对调二者,如此循环直到最后一个变量。 排序

5.删除缺失值比例超过必定阈值的变量列表

程序以下:

options symbolgen;
data missing;
input n1 n2 n3 n4 n5 n6 n7 n8 c1$ c2$ c3$ c4$;
datalines;
1 . 1 . 1 . 1 4 a . c .
1 1 . . 2 . . 5 e . g h
1 . 1 . 3 . . 6 . . k l
1 . . . . . . . a b c d
;
 
data _null_;
if 0 then
set missing nobs=obs;
array num_vars[*] _NUMERIC_;
array char_vars[*] _CHARACTER_;
call symputx('num_qty', dim(num_vars));
call symputx('char_qty', dim(char_vars));
call symputx('m_obs',obs);
stop;
run;
 
 
%put &num_qty &char_qty &m_obs;
 
 
data _null_;
set missing end=finished;
array num_vars[*] _NUMERIC_;
array char_vars[*] _CHARACTER_;
array num_miss [&num_qty] (&num_qty * 0);
array char_miss [&char_qty] (&char_qty * 0);
length list $ 50;
 
do i=1 to dim(num_vars);
if num_vars(i) eq . then num_miss(i)+1;
end;
do i=1 to dim(char_vars);
if char_vars(i) eq '' then char_miss(i)+1;
end;
if finished then do;
do i=1 to dim(num_vars);
if num_miss(i)/&m_obs. ge 0.7 then list=trim(list)||' '||trim(vname(num_vars(i)));
end;
do i=1 to dim(char_vars);
if char_miss(i)/&m_obs. ge 0.7 then list=trim(list)||' '||trim(vname(char_vars(i)));
end;
call symputx('mlist',list);
end;
run;
%put &mlist;
data notmiss;
set missing(drop=&mlist);
run;

结果显示以下:
Missing数据集以下:


Notmiss数据集以下:


需求以下:
要求删除数据集missing里面缺失值比例超过70%的全部变量。

程序解读:
这个程序对于初学者而言,比较复杂,可是这是一个典型的ARRAY语句和RETAIN语句(这里是累加语句)综合应用的例子。主题程序主要分红三部分:

(1)第1个DATA  _NULL_程序:
if 0表示条件恒为假,then后面的语句永远不执行。可是nobs在编译时就能够获得,所以,上面程序是一种不打开数据集而得到数据集观测的巧妙方法。
整体介绍:
这个DATA步,区分并计算全部数值型和字符型变量个数,并把结果赋值给两个不一样的宏变量num_qty和char_qty,同时获取数据集missing的观测数,也赋值给另一个宏变量m_obs,整个程序都是在编译阶段完成的,没有执行任何语句,这是为了提升程序运行的效率。
(2)第2个DATA _NULL_程序:
此处须要讲解一下end=finished语句。
end=variable语句,定义一个变量variable,做为文件结束的标志。而且该变量的初始值为0,当SET语句读完输入数据集的最后一个观测或合并后的数据集的最后一个观测时,其值变为1。
整体介绍:
对数值型和字符型分别计算每个变量的缺失值个数并累加,最后根据预设的阈值(这里是70%)找到知足条件的变量,并赋值给宏变量MLIST。
详细介绍:
1)这个DATA过程, 声明了四个数组,
num_vars指向全部的数值型变量(n1-n8),使用_numeric_故不在输出数据集中显示
char_vars指向全部的字符型变量(c1-c8),使用_character_故不在输出数据集中显示
数组num_miss,以全部的数值型变量个数为数组元素个数(8个),默认变量名是num_miss1-num_miss8,并设置初始值为0;
数组char_miss,全部的字符型变量个数做为数组元素个数(4个),默认变量名是char_miss1-char_miss8,并设置初始值为0;

2)接着执行下面的两个do语句,即分别检查num_vars和char_vars中的数据,若是是缺失值,则对应的num_miss(i)和char_miss(i)的0就会变成1。
3)下边的语句是if finished then do;因为上边咱们还 没有读取到missing文件结尾, 即此时的finished=0,因此程序不执行该语句,直接执行RUN语句,输出第一条观测,程序跳回DATA步开头,继续执行下一条观测
4)这样依次执行下去,当读到最后一条观测时,程序执行IF finished语句,完成两个DO循环操做:
【1】第3个do循环执行dim(num_vars)=8次,每次都对num_miss(i)/&&m_obs.的值进行判断,若是缺失值比例超过70%,则执行list=trim(list)||' '||trim(vname(num_vars(i)))赋值语句。注意,该赋值语句中的list不是一个RETAIN变量,由于RETAIN变量是专门针对一个变量的不一样观测操做的,是纵向操做,而这里因为数据指针一直停留在最后一条观测,对list进行的是横向的ARRAY操做。
变量vname返回数组元素对应的变量值。好比第一次执行DO循环时,因为num_miss(i)/&m_obs.=num_miss1/4=0/4=0不大于70%,所以未执行IF语句。进入第二次循环,因为num_miss(i)/&m_obs.=num_miss2/4=3/4=0.75大于70%,所以执行IF语句,获得list=N2。一样程序一直执行到第四次循环时才又获得list=N4,可是因为数据指针仍然停留在最后一条观测上,所以前面的list=N2还保留在内存缓冲区,并经过list=trim(list)||' '||trim(vname(num_vars(i)))赋值语句把list=N4的值加上去,如此下去,直到读完 第8个数值变量num_miss8,最后获得list=N2 N4 N6 N7。

【2】第4个DO循环执行dim(char_vars),4次,一样能够获得以下结果:list=C2,可是一样是因为数据指针的缘由,第3个DO循环获得的list值会加到list=C2上面去,最终获得list=N2 N4 N6 N7 C2。

5)最后程序经过CALL语句把list值赋值给一个宏变量,进行接下来的操做。
相关文章
相关标签/搜索