本文重點:
- 使用RETIAN,INPUT在每次循環執行時保留上一次PDV中的變量值。
- SUM語句和SET語句會自動RETAIN變量。
1. RETAIN語句
1.1 Example 1
先來看看在DATA步不使用和使用RETAIN語句的差異
沒有使用RETAIN:
DATA WITHOUT_1; PUT "Before the INPUT statement: " _ALL_; INPUT X @@; PUT "After the INPUT statement: " _ALL_ /; DATALINES; 1 2 . 3 ;
使用RETAIN:
DATA WITH_1; RETAIN X; PUT "Before the INPUT statement: " _ALL_; INPUT X @@; PUT "After the INPUT statement: " _ALL_ /; DATALINES; 1 2 . 3 ;
注意比較兩段代碼的輸出紅色矩形的內容,結合上一篇博客里講的PDV,不難發現:
- 不使用RETAIN,INPUT在每次循環執行時會把PDV中的變量值清空,即置為(.)。
- 使用RETIAN,INPUT在每次循環執行時保留上一次PDV中的變量值。
實際上,上面這個例子里數據集WITHOUT_1和WITH_1的內容是一樣的,下面來看一個必須要用RETAIN的例子。
1.2 Example 2
考慮這樣一種場景:我們的數據集中有缺失值,我們想用該缺失值的前一個非缺失值來填補該缺失值,比如我們的數據是1,2,.,3填補后是1,2,2,3。
這在SAS中很好處理,我們只需要用一個變量記住上一個非缺失值即可:
DATA WITHOUT_2; PUT "Before INPUT: " _ALL_ ; INPUT X @@; IF X NE . THEN OLD_X = X; ELSE X = OLD_X; PUT "After assignment: " _ALL_ /; DATALINES; 1 2 . 3 ;
遺憾的是這段代碼並沒有實現我們的目的
查看日志,問題就很明顯了,因為沒有使用RETAIN,所以在數據步的每一次循環開始時,PDV中的變量均被置空,所以OLD_X每一次都是空:
既然想讓OLD_X記住DATA步每次迭代的前一個值,我們RETAIN住OLD_X即可:
DATA WITH_2; RETAIN OLD_X; PUT "Before INPUT: " _ALL_ ; INPUT X @@; IF X NE . THEN OLD_X = X; ELSE X = OLD_X; PUT "After assignment: " _ALL_ /; DATALINES; 1 2 . 3 ;
1.3 Example 3
考慮這樣一種場景:在我們讀入數據的時候,我們想給每個數據加一個順序的行號,第一條觀測是1,第二條觀測是2,依次到最后一條觀測。
下面用RETAIN語句實現:
DATA WITH_3; RETAIN SUBJECT 0; PUT "Before the INPUT statement: " _ALL_ ; INPUT X @@; SUBJECT = SUBJECT + 1; PUT "After the INPUT statement: " _ALL_ /; DATALINES; 1 3 5 ;
RETAIN SUBJECT 0;表示在DATA步的每一次迭代時RETAIN住SUBJECT這個變量,不要將其置為空,“0”表示SUBJECT的初始值。
上面這段代碼,可以利用SAS中的SUM語句進行簡化:
DATA WITHOUT_4; PUT "Before the INPUT statement: " _ALL_ ; INPUT X @@; SUBJECT+ 1;
/* SUM statement */ PUT "After the INPUT statement: " _ALL_ /; DATALINES; 1 3 5 ;
注意到SUM語句的作用:
- 不需要顯示地用“=”賦值
- 不需要顯示地初始化SUBJECT,它會自動初始化為0
- 不需要顯示地RETAIN,它會自動RETAIN變量
其實,如果你還記得上一篇博客中我們在講PDV時提到的自動變量_n_,這段代碼可以更簡潔:
DATA USE_n_; PUT "Before the INPUT statement: " _ALL_ ; INPUT X @@; n=
_n_; PUT "After the INPUT statement: " _ALL_ /; DATALINES; 1 3 5 ;
1.4 Example4
上一個例子中我們發現SUM語句會自動RETAIN變量,其實SAS中的SET語句也會自動RETAIN變量:
DATA ONE; INPUT X Y; DATALINES; 1 2 ; DATA TWO; IF _N_ = 1 THEN SET ONE; PUT "Before INPUT statement: " _ALL_; INPUT NEW; PUT "After INPUT statement: " _ALL_ / ; DATALINES; 3 4 5 ;
看一下日志,就發現SET的確自動RETAIN了變量X,Y。最開始,_N_=1,將X=1,Y=2讀入,然后_N_=2,_N_=3等后面的每一步,粉色框里的X,Y值並沒有在DATA步的每次迭代中被置空。