sas執行後無結果輸出 帶你走進SAS巨集的世界

2021-10-13 22:40:57 字數 3287 閱讀 9131

當我們剛開始接觸巨集的時候,往往會使用些由%let、call symput和proc sql into等建立乙個全域性的巨集,應用到後續的過程步中,隨著這些巨集的頻繁使用,我們腦海裡往往會形成乙個這樣的概念:在sas中,預處理器會根據一系列預定義的「內容」對源**進行替換執行。如下例1:

%let outpath = %str(e:test) ;

%let tablename = %str(test);

ods rtf file = 「&outpath.&tablename..rtf」 ;

但隨著巨集更進一步的使用,慢慢的會發現自己之前給的這麼乙個定義也沒那麼準確,好像差點什麼,尤其是在巨集過程的使用中。巨集參雖然也是乙個個「內容」,但更確切的說,它是乙個個符合需求的條件,這個時候我們的概念就更加清晰了:在sas中,預處理器會根據一系列定義的規則有條件地對源**進行替換執行。如下例2:

let outpath = %str(e:test) ;

%macro class(factor ,tablename) ;

data class ;

set sashelp.class ;

&factor. ;

run ;

ods rtf file 「&outpath.&tablename..rtf」 ;

proc report data = class ; run ;

ods rtf close ;

%mend ;

%class(where age > 13 ,tablename1);

%class(where age > 15 ,tablename2);

我們使用的巨集的目的往往是因為它「省事」,使用巨集可以讓我們少寫點**,讓我們**看起來很簡潔,減少手動更改的操作量。基於這些目的我們可以知道我們應當在以下情境下使用巨集:

1、乙個重複使用的變數,如例1的&outpath;

2、乙個重複使用的語句內容,如例2的&factor;

3、乙個重複使用的過程步,如例2的data step;

4、乙個重複使用的綜合過程,如這個例2;

我們接下來會通過三個方面來講解怎麼去使用巨集,第乙個方面是全域性巨集和區域性巨集,第二個方面是迴圈體和條件語句,第三個方面是如何進一步的提公升執行效率。但在考慮怎麼應用巨集之前,我們有必要了解下巨集在pdv(program data vector)是怎麼被處理的。如下圖1所示:

我們可以看到,相對一般data step的pdv過程,擁有巨集的程式內會多乙個巨集處理器的過程。在首次確定巨集之後會進行乙個預編譯,再到了巨集展開的時候,會將預編譯的結果返回值buffers進行一次非巨集過程過程的編譯過程。這過程也很簡單,但不能被忽略,比如在data step中應用call execute,而且在call execute中建立巨集變數的同時應用該巨集變數,這就犯了這個pdv的過程,要知道call execute裡邊的內容是先被編譯然後再去執行的。

在應用巨集過程中,我們需要知道全域性巨集變數和區域性巨集變數的概念,全域性巨集的定義是在開放型**中定義的巨集為全域性巨集,而區域性巨集的定義則為在乙個巨集過程中定義或生成的巨集為區域性巨集。兩者的區別很顯然,是乙個相對的概念,是否是在巨集過程中建立的巨集變數。兩者都可以通過%let、call symput語句和proc sql過程等語句或過程建立,全域性巨集不可以轉換為區域性巨集,但區域性巨集可以通過%global轉換為全域性巨集。

我們了解了全域性巨集和區域性巨集,還需要知道的是全域性巨集可以應用到區域性巨集,一級巨集中巢狀了二級巨集,這個時候一級巨集的巨集參可以被應用到二級巨集中。值得注意的是,如果一級巨集的巨集參名字和二級巨集參的名字出現了一樣的情況,這會出現以下的情況:

雖然對於懶得想名字的人來說,這無疑是個好應用,但如果這樣操作,勢必會增加debug的難度。

在巨集應用裡邊,還有個重要的內容我們需要了解的是迴圈體和條件語句,迴圈體如下:

1、%do = %to [%by step];

macro statement ;

%end ;

2、%do %while ;

macro statement ;

%end ;

3、%do %until ;

macro statement ;

%end ;

條件語句如下:

1、%if %then ;

%else ;

和平常使用的未加百分號的迴圈體不同的是,這裡加了百分號的迴圈體是可以脫離data step而存在的,也就是說迴圈體中間的「macro statement」可以是過程步,也可以是語句。那麼怎麼去迴圈乙個資料集呢?

以dixon檢驗法為例,不同樣本量之間的高階離群值、低端離群值、檢出水平和剔除水平都是不一致的,每發現出乙個新的統計離群值,就要在原來的樣本上剔除該樣本,對剩下的樣本繼續檢驗,直至高階和低端都沒有統計離群值出現,才終止迴圈,同時這個時候需要將統計學離群值呈現出來。如果使用迴圈體,又該如何操作?

很顯然,我們是反覆的對同乙個資料集進行操作,中止迴圈的條件是高階和低端同時沒有出現統計離群值,在這裡會使用到巨集巢狀巨集的辦法摻雜著迴圈體,如下所示簡要**:

%macro dixon(macro parameters1 ,……);

%do %until(&dixon_outliers. = 0 );

%global dixon_outliers ;

%dixon_process(&data._&target._4) ;

%end;

%mend;

巨集過程dixon中巢狀著巨集過程dixon_process,同時巨集過程中會返回資料集之外還會返回由巨集過程dixon_process產生的全域性巨集dixon_outliers,用以做迴圈體%do %until的迴圈判斷。

❑ 從巨集過程輸出著手

減少中間資料集的生成及陳列,可以使用proc datasets指定性的刪除work中的資料集,同時不陳列刪除了的資料集名稱,這樣使用sas eg或 sas base的時候很快捷的瀏覽自己所需要的資料集,可以使用 nolist 和 noprint選項的盡量使用該選項,這樣某些程式產生的結果不必要的生成在html頁面或sas結果頁面上;

❑ 從巨集結構著手

減少巨集過程,增加巨集過程;比如就簡單的區分空腹和餐後,在開頭就進行簡單判斷,只分析餐後的資料或者只分析空腹的資料,如果能在不區分空腹和餐後的前提下分析資料,結果還是區分了空腹和餐後,那就一次性分析完,結果呈現上再區分空腹和餐後輸出。

執行如下結果 輸出時什麼?

執行如下 輸出時什麼?一 char getstring1 char getstring2 int tmain int argc,tchar argv 原文解釋 第乙個函式返回的是陣列的首位址,因為當函式getstring1函式返回時,陣列內的空間被釋放,所以列印的結果是隨機的東西 而函式getstr...

為啥VC6 0或VS2010執行後輸出結果總是0

toc下面程式輸入0 9十個數字,為啥vc6.0或vs2010執行後輸出結果總是0 include int main e dt z 0 t z 1e tdt 你可以找到更多關於的資訊latex數學表示式here.可以使用uml圖表進行渲染。mermaid.例如下面產生的乙個序列圖 這將產生乙個流程圖...

修改SAS統計過程輸出結果的小數字數

結合ods trace語句與ods output語句可以將任意過程步的結果輸出至資料集中,以便進一步處理。某些情況下,sas輸出結果提供的小數字數可能不符合實際輸出的要求,這時候就需要修改預設的數值輸出格式了。例如 使用proc means過程對資料集sashelp.class中的height變數進...