SAS筆記(1) PDV與數據讀入


其實我是不喜歡SAS的。當然,我不喜歡她,並不代表她不好,實際上在某些應用場景下SAS是款很優秀的軟件。我的數據分析之路始於R,品嘗過R的靈活與簡潔(不論是軟件安裝還是語法)后,再來學習SAS,的確提不起興致。然而由於:1.導師的項目數據量較大(幾Gb到幾十Gb);2.之前的項目代碼師兄已經用SAS很優美地實現了;3.我莫名地當上了該項目負責人,要帶着師弟師妹做該項目。我也只好硬着頭皮學習SAS。奈何現在腦力大不如前,看的東西越來越記不住,於是下定決心梳理一下SAS相關知識。

1. DATA步簡介

在SAS中,我們使用DATA步來讀入數據,DATA步在讀入數據時實際上有兩個階段:編譯(compilation)和執行(execution)。過程如下:

  1. 在編譯階段中,逐個掃描語句,如果發現語法錯誤,SAS報錯並終止運行;如果編譯階段中沒有發現任何語法錯誤,進入執行階段。
  2. 在執行過程中,DATA部讀入第一條數據,在SAS中創建第一條觀測;讀入第二條數據,在SAS中創建第二條觀測;讀入第三條數據,在SAS中創建第三條觀測……直至讀入最后一條數據並在SAS中創建最后一條觀測。我們可以把這個過程當做隱式循環(和DO,DO WHILE,DO UNTIL語句區分,它們是顯示循環)。

需要注意的是,並不是DATA步中的所有語句都是在執行階段運行,事實上,可以把DATA步語句分為兩類:可執行語句(executable)和聲明語句(declarative)。
聲明語句只在編譯階段起作用,它可以放在DATA步的任何位置。下面是一些基本的DATA步聲明語句:
LENGTH:設置內部變量長度
FORMAT:設置變量輸出格式
LABEL:設置變量標簽
DROP:指示輸出文件中刪掉哪些變量
KEEP:指示輸出文件中包含哪些變量

與聲明語句不同,可執行語句在DATA步中順序很重要。比如從外部讀取一個文本文件,我們必須以INFILE語句開始,告訴SAS從哪里讀文件;然后輸入INPUT語句,告訴SAS怎么讀該文件。所以,INFILE語句必須在INPUT語句前面,順序很重要。

2. DATA步的編譯階段(DATA Step Compilation Phase)

SAS從外部讀入原始數據(raw data)時,會在編譯階段開始時創建一個輸入緩沖區(input buffer)來存儲raw data。如果是從外部直接讀入SAS數據(.sas7bdat文件)則不會創建輸入緩沖區。SAS在編譯階段還會創建PDV(program data vector),PDV其實就是內存中的一塊區域,通過PDV將讀入的raw data的每一條數據變成SAS數據集中的每一條觀測。在PDV中有兩個自動變量,_N_和_ERROR_。_N_=1表示正在創建第一條觀測,_N_=2表示正在創建第二條觀測,依次類推。_ERROR_只有0和1兩個取值,等於0表示在創建當前觀測時未發現錯誤,等於1表示在創建當前觀測時發現錯誤。除了這兩個自動變量外,PDV中還有DATA步在創建的數據變量。

假設在我們電腦D盤里有一個student.txt文件,內容如下(第一行紅字表示每個字符的所占列位置編號,不是文檔內容)

12345678901234567890

Barbara 61 12D
John    62 175

現在我們用DATA步讀入這個文件,並計算每個學生的BMI,看看PDV的工作原理。代碼很簡單:

data ex1;
infile 'C:\student.txt';
input name $ 1-7 height 9-10 weight 12-14;
BMI = 700*weight/(height*height);
output;
run;
  1. 一開始,PDV中只有_N_,_ERROR_這兩個自動變量。
    f1
  2. 代碼運行到 input name $ 1-7 height 9-10 weight 12-14;時,PDV中會按照input后變量的順序創建NAME,HEIGHT,WEIGHT三個變量,D表示dropped,K表示kept。只有帶K的變量才會output到數據集中。
    f2 
  3. 代碼運行到BMI = 700*weight/(height*height);時,PDV中創建BMI這個變量f3

在編譯階段,SAS會檢查語法是否正確,在編譯結束的時候,會創建SAS數據集的內容描述,包括數據集的名字,觀測數,變量名,變量數目,變量類型,所有這些內容都可以通過CONTENTS輸出。

3. DATA步的執行階段(DATA Step Execution Phase)

  1. 在執行階段的開始,自動變量_N_會被初始化1,自動變量_ERROR_被初始化0。一旦INFILE語句識別了我們待讀取文件的路徑,INPUT語句就會把待讀取文件的第一條數據復制到輸入緩沖區。
    f4
  2. 接着,我們的輸入指針(input pointer,下圖的紅色箭頭)會在(@)輸入緩沖區的開始處。
    f5
  3. 然后,輸入指針(紅色箭頭)會根據input語句定義的方式讀入輸入緩沖區的這條記錄,並移動輸入指針,在我們的例子中是將1-7列讀入NAME,9-10列讀入HEIGHT,12-14列讀入WEIGHT,此時輸入指針位於第15列。將記錄寫入到PDV,因為WEIGHT變量類型錯誤,所以WEIGHT變量值為空(.),同時_ERROR_會變為1,因為WEIGHT為空,所以BMI也為空。
    f7
  4. 然后執行OUTPUT語句,將PDV中的這條數據輸出到我們的SAS數據集--WORK邏輯庫中的ex1。到此student.txt中的第一條數據已讀入SAS數據集。f6
  5. SAS返回到DATA步的第一條語句,也就是data ex1;開始讀取student.txt中的第二條數據,此時_N_變為2,_ERROR_重新置為0,其余過程同上。如此往復,直至我們的輸入指針遇到EOF(End Of the File),退出循環。DATA步結束。

在我們的這個例子中,如果我們不使用OUTPUT也可以讀入該數據,這是因為在DATA步中,當用戶沒有顯式指定OUTPUT時,SAS會隱式調用OUTPUT。不論顯式還是隱式output,它們的作用都是講PDV的那條數據output到我們的SAS數據集中。

 

參考資料:《Handbook of SAS® DATA Step Programming》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM