一起來(lái)學(xué)SAS PDV!

?初學(xué)SAS的時(shí)候,往往注重程序語(yǔ)法結(jié)構(gòu),而忽略了SAS編譯和執(zhí)行階段如何處理數(shù)據(jù)。所以很多時(shí)候,寫(xiě)的程序看起來(lái)沒(méi)有問(wèn)題,但是創(chuàng)建出的數(shù)據(jù)集觀測(cè)數(shù)和預(yù)期的卻不一致,一些變量也沒(méi)有按照預(yù)期retain下來(lái),嘗試另起一個(gè)data步或者用一個(gè)新變量名問(wèn)題就解決了,但是究竟問(wèn)題出在哪里,也無(wú)從得知。今天就一起研究下SAS處理數(shù)據(jù)的機(jī)制吧!?

SAS data步包含包含兩個(gè)階段:

  • 編譯階段
  • 執(zhí)行階段

編譯階段

這個(gè)階段sas主要做:

  1. 掃描code是否存在語(yǔ)法錯(cuò)誤;
  2. 結(jié)束后創(chuàng)建數(shù)據(jù)集的描述信息;
  3. 會(huì)產(chǎn)生兩個(gè)對(duì)象:input buffer(輸入緩沖區(qū))、PDV(program data vector)

具體講,就是確保program滿足語(yǔ)法規(guī)則,例如sas數(shù)據(jù)集、變量名命名規(guī)則,關(guān)鍵拼寫(xiě)是否有誤,引號(hào)括號(hào)不配對(duì),每個(gè)語(yǔ)句是否以分號(hào)結(jié)束等等。編譯階段完成之后,sas數(shù)據(jù)集的描述信息就創(chuàng)建好了,例如變量名、變量屬性。

語(yǔ)法錯(cuò)誤核查完之后,SAS會(huì)創(chuàng)建input buffer(只在讀取raw data時(shí)產(chǎn)生)。input buffer只是一個(gè)邏輯概念,并沒(méi)有實(shí)際的物理儲(chǔ)存位置,可以理解為一個(gè)臨時(shí)儲(chǔ)存記錄的位置。

input buffer創(chuàng)建之后,PDV也隨著創(chuàng)建,和input buffer類(lèi)似,PDV也是一個(gè)邏輯概念。

PDV的變量:data步中的所有變量,以及自動(dòng)生成的變量 by-group創(chuàng)建的變量,選項(xiàng)生成的變量等等。

variables description
_n_ Data步執(zhí)行次數(shù)的計(jì)數(shù)變量
_error_ 錯(cuò)誤信息 表示當(dāng)前觀測(cè)執(zhí)行時(shí)發(fā)生了錯(cuò)誤
first.variable 同一by組第一個(gè)觀測(cè)
last.variable 同一by組最后一個(gè)觀測(cè)
_all_ 所有變量
indsname= 數(shù)據(jù)集名稱
nobs= 數(shù)據(jù)集總觀測(cè)數(shù)
curobs= 數(shù)據(jù)集當(dāng)前觀測(cè)數(shù)
end= 布爾值 最后一個(gè)數(shù)據(jù)集最后一條觀察為1,否則為0
in= 布爾值 可以標(biāo)識(shí)數(shù)據(jù)集
point= 取指定觀測(cè) 等號(hào)右邊為變量 不能設(shè)置為數(shù)字 需和stop連用

執(zhí)行階段

創(chuàng)建數(shù)據(jù)部分,_N_初始化為1,_ERROR_初始化為0,F(xiàn)irst.var, Last.var初始化為1,其它的自動(dòng)變量為缺失。

input語(yǔ)句執(zhí)行,將raw data第一行copy進(jìn)input buffer, 執(zhí)行其他語(yǔ)句,最后輸出該條觀測(cè)到數(shù)據(jù)集中,然后返回DATA步繼續(xù)執(zhí)行,讀取下一條觀測(cè)。

在執(zhí)行階段,DATA步看起來(lái)更像是一個(gè)循環(huán),讀取一行數(shù)據(jù),執(zhí)行所有語(yǔ)句,創(chuàng)建一行觀測(cè)記錄,并重復(fù)這個(gè)操作。每次循環(huán)就稱作一次迭代。

并非所有的語(yǔ)句都是在執(zhí)行階段執(zhí)行,DATA步中的語(yǔ)句可以分為:聲明語(yǔ)句可執(zhí)行語(yǔ)句。聲明語(yǔ)句:在編譯階段就開(kāi)始生效了,可以放在DATA步中的任何位置。比如LENGTH、FORMAT、LABEL、DROP、KEEP等。

可執(zhí)行語(yǔ)句:必須要按照預(yù)期執(zhí)行的順序進(jìn)行放置,比如input之前要先infile。

example


data total_points (drop=TeamName);  
   input TeamName $ ParticipantName $ Event1 Event2 Event3;
   TeamTotal + (Event1 + Event2 + Event3);
   datalines;
Knights Sue    6  8  8
Kings Jane     9  7  8
Knights John   7  7  7
Knights Lisa   8  9  9
Knights Fran   7  6  6
Knights Walter 9  8 10
;
run;

Input Buffer


PDV


Output語(yǔ)句

讀進(jìn)PDV的數(shù)據(jù),默認(rèn)是會(huì)被output到數(shù)據(jù)集中的,這稱為隱式輸出。如果使用了output語(yǔ)句(顯式輸出)來(lái)輸出記錄,隱式輸出就不會(huì)起作用了。所以,如果使用了有條件的output語(yǔ)句,只有滿足的條件的記錄才會(huì)被輸出到數(shù)據(jù)集中,其它記錄不會(huì)再被默認(rèn)輸出,如果不同條件的記錄要以不同的要求output到數(shù)據(jù)集,可以使用多個(gè)output語(yǔ)句。

Reading raw data v.s. Reading sas dataset

Raw data:每次迭代時(shí),除了自動(dòng)創(chuàng)建的變量、Retain語(yǔ)句中的變量、SUM語(yǔ)句創(chuàng)建的變量、_TEMPORARY_數(shù)組中創(chuàng)建的元素、infile/file選項(xiàng)中創(chuàng)建的變量,其余變量在PDV中都會(huì)被設(shè)置為缺失。

SAS data set:只在執(zhí)行的第一次迭代時(shí)將PDV中的變量置為缺失,變量將會(huì)retain值直到被新的值代替。對(duì)于不是來(lái)自input dataset而是在data步中創(chuàng)建的新變量,會(huì)在執(zhí)行的每一次迭代的開(kāi)始被置空。如果想要使新創(chuàng)建的變量retain值,可以使用retain語(yǔ)句。

drop/keep語(yǔ)句和選項(xiàng)

drop/keep分別是刪除和保留變量

  • drop/keep語(yǔ)句和drop/keep選項(xiàng)作用在輸出數(shù)據(jù)集是一樣的;
  • drop/keep選項(xiàng)如果作用在輸入數(shù)據(jù)集,那么相應(yīng)drop的變量或者沒(méi)被keep的變量就不會(huì)進(jìn)入PDV。當(dāng)數(shù)據(jù)列非常多的時(shí)候,在輸入數(shù)據(jù)集時(shí)就keep或者drop變量,能夠提高運(yùn)行效率;
  • drop/keep同時(shí)使用,drop先起作用,然后再進(jìn)行keep;如果drop和keep沖突的話(drop或者keep不存在的變量),那么SAS會(huì)報(bào)錯(cuò)。

where/if

where在數(shù)據(jù)進(jìn)PDV之前就進(jìn)行篩選,只能篩選輸入數(shù)據(jù)集中的變量,在data步創(chuàng)建的新變量不可以篩選。

  • if是在數(shù)據(jù)讀進(jìn)PDV后才進(jìn)行篩選,可以篩選輸入數(shù)據(jù)集中的變量,也可以篩選在數(shù)據(jù)步創(chuàng)建的新變量。
  • 如果存在by語(yǔ)句,那么where是在by語(yǔ)句之前執(zhí)行,if語(yǔ)句是在by語(yǔ)句之后執(zhí)行。by語(yǔ)句可以產(chǎn)生first.var, last.var的PDV變量,所以where first.var?,if first.var?;
    where語(yǔ)句的優(yōu)勢(shì)就是可以提高效率,因?yàn)樵谧x取數(shù)據(jù)之前已經(jīng)進(jìn)行篩選減小了數(shù)據(jù)量,而if是每行都讀入PDV再篩選是否輸出到數(shù)據(jù)集中。

example
數(shù)據(jù)集Long如圖:



運(yùn)行如下程序:


data rewide(keep=sid programming stats english);
  format Sid Programming Stats English;
  array course{3} programming stats english;
  do i = 1 to 3;
    set long;
    course{i}=score;
    put _all_;
  end;
run;

得到的數(shù)據(jù)集Rewide如圖:



這段程序中,set語(yǔ)句被放置在do循環(huán)內(nèi)。set語(yǔ)句每次只讀取一行記錄,到run結(jié)束,返回至開(kāi)頭讀取下一條記錄,循環(huán)往復(fù)。

第一條do end循環(huán)結(jié)束后,PDV會(huì)讀取三行記錄:



遇到Run;之后將當(dāng)前的PDV記錄輸出至Rewide數(shù)據(jù)集中,然后指針+1,繼續(xù)進(jìn)行第二個(gè)Do end循環(huán),輸出S02的一條記錄。

當(dāng)我們對(duì)sas讀取數(shù)據(jù)階段有困惑時(shí),可以使用put all語(yǔ)句,將PDV的所有變量都輸出在Log中,查看每次執(zhí)行時(shí)每個(gè)變量的賦值情況。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容