SAS在臨床試驗中用得比較多的是SAS Base, SQL, STAT等模塊。還有比較高級的編程就是Macro, 都說比較牛逼的SAS programmer是Macro用得比較好的。今天就講講臨床那些常用的宏技巧。記得前面第19講講過一些宏函數與宏程序,有興趣的可以回顧一下。這裡再講一些SAS Macro作為補充。
1.宏變量列表
* 創建宏變量;
proc sql noprint;
select count(distinct name)
into:N
from sashelp.class;
select distinct name
into :varname1 - :varname%left(&N)
from sashelp.class;
select distinct name
into:varlist separated by ' ", " '
from sashelp.class;
quit;
%put &N;
%put &varname1;
%put &varname19;
%put "&varlist"; 這裡不加引號會報錯
%put %bquote(&varlist); 可以加上%bquote函數屏蔽引號,不出錯。
日誌輸出如下:
84 %put &N;
19
85 %put &varname1;
Alfred
86 %put &varname19;
William
87 %put "&varlist";
"Alfred", "Alice", "Barbara", "Carol", "Henry", "James", "Jane", "Janet", "Jeffrey", "John", "Joyce", "Judy", "Louise", "Mary",
"Philip", "Robert", "Ronald", "Thomas", "William"
關於宏變量列表裡面元素的個數還有一種求法:
%let N = %sysfunc(countw(&varlist));
%put &N;
19
這樣雖然N求對了,但是日誌還是有錯,不完美。
所以這裡涉及到引號的問題。需要用到%bquote函數來屏蔽引號。
%let N = %sysfunc(countw(%bquote(&varlist)));
%put &N;
19
我們先來看一個簡單的例子,按照條件拆分數據集。
data Alfred;
set sashelp.class;
if name = "Alfred" then output Alfred;
run;
再來看一個宏程序,遍歷宏變量列表每個元素。
%macrosplit;
%global i;
%do i =1 %to %sysfunc(countw(%bquote(&varlist)));
data &&varname&i;
set sashelp.class;
if name = "&&varname&i" then output &&varname&i;
run;
%end;
%mend;
%split
巧妙的是%sysfunc(countw(%bquote(&varlist)))前面不用帶解析符號&。
2.遍歷宏變量列表
(1)找出列表最後一個元素
%macro listlast(list);
%scan(&list,-1,%str(","));因為之前&varlist宏變量是以", "為分隔符的,所以這裡%str(", "),括號裡面是specific delimiter
%mend listlast;
%put %listlast(%bquote(&varlist));
結果是 William
3.得到宏變量列表其中一個具體元素
%let var2 = %scan(%bquote(&varlist),2,%str(","));
%put &var2;
結果是 Alice
4.遍歷宏變量列表所有元素
%macro scanlist(list);
data a;
%do i=1 %to &N;
var&i = "%scan(&list,&i,str(","))";
%end;
run;
%mend;
%scanlist(%bquote(&varlist));
5.%do %until 遍歷宏變量列表所有元素
proc contents data=sashelp.class out=class noprint;
run;
proc sort data=class out=vars(keep=name);
by varnum;
run;
proc sql noprint;
select distinct name
into :varlist separated by' '
from vars;
quit;
%put &varlist;
%macro countvar(list);
%global cnt;
%leti = 1;
%do %until (%scan(&list,&i,%str())=%str());
%global var&i;
%let var&i = %scan(&list,&i,%str());
%let i = %eval(&i + 1);
%end;
%let cnt = %eval(&i-1);
%mend;
%countvar(&varlist)
%put &cnt;
%do %while 遍歷宏變量列表所有元素
%macro wordcount(list);
%local cnt;
%let cnt=0;
%do %while (%qscan(&list,&cnt+1,%str()) ne %str());
%let cnt = %eval(&cnt+1);
%end;
&cnt
%mend;
%put %wordcount(&varlist);
宏函數%superq的理解
data_null_;
call symputx('xxx','&A&B&C&D');
call symputx('A','IF');
call symputx('B','I');
call symputx('C', 'WERE');
call symputx('D', 'YOU');
call symputx('IfIwereYou', 'I want to go ...');
run;
%put %superq(&xxx);
大家猜結果會是什麼,對,就是I want to go ...,可以看出這裡xxx是一個宏變量,加上&就是每遇到能夠解析的&就不斷的解析下去,直到最後的宏變量不能解析為止。
%cmpres函數
%let text = %str( The quick brown fox jumped over the lazy dog );
%put text= %cmpres(&text);
結果是:The quick brown fox jumped over the lazy dog
全部壓縮成一個空格。
給一個空格分隔符的列表變成 引號逗號引號 為分隔符的列表,感覺這種功能以後用到很有用。
%macro qstr(list);
%str(%')%qsysfunc(tranwrd(%cmpres(&list),%str(),
%str(%', %')))%str(%')
%mendqstr;
optionsnomprint;
%put %qstr(www baidu);
%put %qstr(www.baidu.com org);
日誌:
'www', 'baidu'
'www.baidu.com', 'org'
像Python一樣將列錶轉化為集合:集合裡面的元素具有唯一性(無重複)。
%macro DistinctList(list);
%local dlist i;
%let dlist = %scan(&list,1,%str());
%let i=2;
%do %while(%scan(&list,&i,%str()) ne %str());
%if %sysfunc(indexw(&dlist,%scan(&list,&i,%str())))=0%then%do;
%let dlist = &dlist %scan(&list,&i,%str());
%end;
%leti = %eval(&i+1);
%end;
&dlist
%mend;
%let list=name name sex sex height height;
%put %distinctlist(&list);
name sex height
好了,今天的宏技巧就分享到這裡了,上面幾個宏主要講解宏變量列表的一些操作,熟練運用這些技巧,在實際工作中會很有用的,其實宏技巧遠不止這些,SAS官網有很多講解宏的相關書籍(配套data與code)可供大家學習。如果上面關於宏有不懂的童鞋,歡迎一起交流討論。今天就講到這裡啦。。(^_^)