SAS DATA STEP—PDV循環

發布時間:2019-03-29 文章來源:SAS DATA STEP—PDV循環

     今天我們要分享的是SAS的運行機制—PDV(program data vector)循環。

 

       SAS功能強大,實現的結果數不勝數,但很多新人,甚至是寫了很多SAS程序的人,也有對SAS產生的結果感到困惑不解,對發生的錯誤一頭霧水的時候。但如果能夠靜下心來了解PDV,理清楚SAS的運行機制,很多疑問或許就迎刃而解了。當然,小編也只是小白一只,PDV到底是什么呢?暫且我們可以把它想象成一個個存儲向量的小方格。下面我們就來一起初步了解PDV循環的過程。


SAS的運行過程包括編譯和執行兩個部分。

首先進行編譯過程。

       1 . 檢查輸入代碼的語法,然后將代碼翻譯成機器語言。這個就可以解釋,在我們編程過程中若有error,則首先報有關語法錯誤。

         2 . 如果使用INPUT語句讀入的外部原始數據,則建立輸入數據緩存區(input buffer),DATA步執行結束,則釋放內存空間。但如果是讀入SAS數據集,則直接建立PDV(program data vector)。

        3 . 建立的PDV中包含兩種類型的變量:①程序中出現的所有變量;②系統自動變量,_N_、_ERROR_,若數據進行排序分類后還可自動產生first.和last.變量。

         4 . 建立SAS數據集以及變量屬性的信息,如數據集命名、創建日期時間、變量名稱、類型(數值型、字符型)、序號等。

下面我們輸入代碼:

data PDV;

input ID $ x y z;

Sum = Sum(x+y+z);

datalines;

S001 85 99 56

S002 88 94 77

S003 90 85 73

;

Run;

這樣的DATA STEP可以簡單的用下圖表示編譯過程,

接下來是執行過程。

       1 . 每一個DATA/RUN標志著一次迭代的開始與結束,DATA步開始是自動變量 _N_=1 ,每迭代一次變量 _N_ 自動加1,當某一處程序出現錯誤時,此次迭代中自動變量 _ERROR_=1,程序終止,若沒有錯誤,_ERROR_=0。

        2 . 把PDV中的變量設為缺失值。

      3 . 用INPUT語句把一條數據記錄讀入到緩存區(input buffer)然后讀入到PDV,或者直接將SAS數據集里的一條觀測值讀入PDV。

        4 . 對當前讀入的觀測執行DATA步以后的語句直到RUN,SAS自動執行輸出、返回、重設動作,到達要讀入的原始外部數據集或SAS數據集的末尾行后DATA步終止。注意,系統的自動變量在此過程中將不會輸出到數據集中。

整個編譯執行過程可簡單表示為下圖:

其中產生的一些指針變量(系統自動變量):

在SAS運行過程中PDV循環的流程圖如下(圖片來源:SAS編程演義):

 

      下面我們就要用更直觀的方法將PDV循環的過程輸出到LOG中。

 

用input輸入以下代碼

 

data PDV;

Put “第” _n_ “次運行前:” _all_;

input ID $ x y z;

Sum = Sum(x+y+z);

Put “第” _n_ “次運行后:” _all_;

datalines;

S001 85 99 56

S002 88 94 77

S003 90 85 73

;

Run;

 

      (當然,將PUT xxx _all_語句放到不同位置時,顯示的步驟也會不同,這也再次說明了DATA STEP在運行過程中是從上至下一步一步執行的。)

在LOG中我們會看到這樣的結果:

輸入以下代碼,直接SET一個數據集:

data class_pdv01;

put "第" _n_ "次運行前:" _all_;

    set sashelp.class;

put "第" _n_ "次運行后:" _all_;

run;

 

得到以下結果:

      從以上兩種演示結果我們可以驗證在DATA STEP的PDV循環過程中INPUT讀入數據和直接讀入SAS數據集的不同之處。

 

       若在DATA STEP中SET兩次不同觀測條數的數據集會出現什么結果呢?

輸入代碼

data class_pdv01;

put "第" _n_ "次運行前:" _all_;

    set sashelp.class;

    set sashelp.cntainer;

put "第" _n_ "次運行后:" _all_;

run;

結果得到

LOG中顯示

        在LOG中我們可以看到循環只運行到第8次前,從結果數據集也可知兩個不同觀測條數的數據集set兩次會得到一個條數較少的新數據集。因為在PDV循環過程中無論被set的數據集哪個在前哪個在后,執行總會在找不到下一條觀測的時候終止,得到最終的數據集。

       以上展示的是SAS默認的、最基礎、最簡單的PDV運行機制,上面說到DATA STEP在運行過程中是從上至下一步一步執行,一條一條讀入的,其實也有一些特殊的函數會在DATA步開始的時候最先執行,如where、output、retain、keep、drop等循環、選擇、聲明語句以及一些描述性的變量format、lable、length等,SAS的處理流程會有所不同,他們對于PDV循環中變量的初始化沒有影響。下面我們來看一些PDV循環中的retain示例。

       示例一:Retain如何能夠在讀取數據集中改變變量的順序?實際上PDV過程按照最先見到的變量進行變量順序;

      將Retain語句放在兩個不同位置,我們得到的數據集變量順序不同。

 

     示例二:以sashelp.class數據集為例輸入以下代碼:

那么wh_1將得到什么結果?

(由于篇幅關系我們只截取前后各兩條觀測的讀入過程)

       從LOG以及最后的數據集中我們可以看出wh_1只在最后一條觀測第十九行顯示非空缺值,并且由第十八行wh變量的值得到。這是因為在執行語句“if last then wh_1 = wh*100;”時,PDV中還未有_N_=19時wh的計算結果,而仍然儲存著_N_=18時wh的計算結果,所以使然。若把語句“if last then wh_1 = wh*100;”換到被注釋掉的位置,得到結果如下:

        示例三:如何運用debug來檢查程序或者看到程序每一步執行的過程?

以示例二為例,在data步中加“/debug”后運行程序;

界面會彈出這樣兩個debug窗口(DEBUGGER LOG/DEBUGGER SOURCE);

    在DEBUGGER LOG窗口下方交替輸入“ex _all_”和“step N”(這里的N代表任意小于運行行數的阿拉伯數字)就可以在DEBUGGER LOG窗口中看到程序運行至每行后的PDV儲存值啦。

 

最后送上一些關于PDV的Little Tips:

① DATA STEP在運行過程中對數據進行逐條讀取,從而形成循環;

② PDV中變量按照先來后到的原則,是根據其在DATA步中第一次出現的位置決定整個PDV中的變量順序;

③ First/Last/_n_/nobs/obs/end/point等為數據指針變量;

④ 使用First.varieble/Last.varieble前必須進行排序處理;

⑤ drop/keep/lable/length/format等是對數據變量的描述性(聲明)語句或變量,對PDV循環的初始化沒有影響。


上一篇:沒有了 下一篇:沒有了