跳出 SAS DO loop 的陷阱:LEAVE statement 讓迴圈更有效率

前言

在面對有序且重複的步驟時 SAS DO loop 是我們的好幫手,他能幫助我們以精簡的語句完成工作,省去重覆貼語法的費時工作 (也避免可能貼錯語法的風險)。

但是在某些情況下,DO loop 其實不需要跑完所有的重複指令 (iterations) 也可以得到正確的結果,替我們省下時間和系統資源。

2020 年的 SAS 全球論壇一篇精巧而實用的文章,介紹了 LEAVE statement 如何勝任這項任務,一起來認識新同學 LEAVE statement 吧。


IF THEN 語句

IF THEN 語句是所有程式語言的基本條件句,例如以下常見的條件句,由 IF 與 OR 來判斷 cancer 的有無:

if brain_cancer=1 or lung_cancer=1 or skin_cancer=1 then cancer=1;

或者另一種 IF 的多條件寫法:

if brain_cancer=1 then cancer=1;
else if lung_cancer=1 then cancer=1;
else if skin_cancer=1 then cancer=1;

上述兩種寫法,只要第一個變項 brain_cancer 的值為 1,不論後續的變項 lung_cancer 和 skin_cancer 的值是多少,新的變項 cancer 都會被標記為 1。

也就是說 brain_cancer=1 成立的情況下,其實 SAS 多跑了 lung_cancer=1 和 skin_cancer=1 這二個條件句,在效率上不免要打些折扣。


現在讓我們考慮更複雜也更貼近真實的情況。假設是否有癌症的條件變成由 25 個診斷代碼 (dx1~dx25) 來判斷,只要任一的診斷代碼符合「C00 至 D49」皆判斷為發生癌症 (cancer=1)。資料簡示如下:

如果按照上述直覺的寫法,我們可以寫作:

if ‘C00’ ≤ dx1 ≤ ‘D49’ then cancer=1;
if ‘C00’ ≤ dx2 ≤ ‘D49’ then cancer=1;
if ‘C00’ ≤ dx3 ≤ ‘D49’ then cancer=1;
… (我是重複值)
… (一直重複)
… (還在重複)
if ‘C00’ ≤ dx25 ≤ ‘D49’ then cancer=1;

可以想像語法會變得很長一串,這時候 IF THEN 語句可利用 SAS ARRAY 搭配 DO loop 來改寫。

SAS ARRAY 與 DO loop 語句

array dx(*) dx1-dx25;
do i=1 to dim(dx);
if ‘C00’ le dx(i) le ‘D49’ then cancer=1;
end;

SAS Array 搭配 DO loop 讓語法變得更簡便,能快速的完成多個條件句而不易出錯。

  • 一直寫重複的語句時你需要→ SAS ARRAY + DO loop

但是從語法的核心來看,其實條件句本身並沒有改變,DO loop 仍然會重複執行 25 次的 IF THEN 語句來判斷 cancer 是否為 1。

由疊代次數 i=26 可知,對每個觀測對象來說 SAS 都會逐一檢查所有 25 個變數,以識別出癌症患者 (cancer=1)。

然而我們知道,有許多的診斷代碼是空白的(沒有資料),表示大部分的情況並不需要檢查所有變項。顯然我們需要更有效率的方法。

LEAVE statement

較有效率的條件句:

array dx() dx1-dx25;
do i=1 to 25;
if cancer=1 then leave;
if ‘C00’ dx(i) ‘D49’ then cancer=1;
end;

只要在 DO loop 底下加上 LEAVE statement,SAS 就會依據條件句「if cancer=1 then leave」 判斷迴圈是否繼續,只要條件一成立 (cancer=1) 該觀測對象就會立刻結束迴圈,再繼續往下一個觀測對象進行判斷。

  • LEAVE statement → 跳出不必要的迴圈

由 i 可知 SAS 檢查變項的次數大幅減少,不需要檢查所有25個變項才做出有無癌症的判斷。


加入更多條件來提高效率

眼尖的讀者可能已經觀察到,dx3 是空白的。對於疾病診斷的資料來說,空白 (如dx3) 就代表之後的變項 (dx4-dx25) 皆為空白 (因為沒有更多診斷了)。因此我們可以多加個條件,讓判斷更有效率:

array dx() dx1-dx25;
do i=1 to 25;
if cancer=1 or dx(i)=’ ’ then leave;
if ‘C00’
dx(i) ‘D49’ then cancer=1;
end;


結語

LEAVE statement 是簡單卻相當有用的工具,他可以適時幫助我們跳出迴圈,大大減少 SAS 重複執行 IF THEN 條件句,讓我們節省系統資源與執行時間,更有效率的完成條件句的判斷,有機會時不妨也來試試。


參考文獻

SAS GLOBAL FORUM 2020, Paper 5001-2020. Make Your DO Loop More Efficient. G Lin.

如有任何問題和意見歡迎提出