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值賦值給一個宏變量,進行接下來的操做。
相關文章
相關標籤/搜索