<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6268919072942670865</id><updated>2012-01-04T17:26:32.294-04:00</updated><category term='其他'/><category term='模型配適'/><category term='報表輸出'/><category term='程序語法'/><category term='資料整理'/><category term='巨集程式'/><category term='繪圖技巧'/><title type='text'>SUGI CLUB — SAS User Group International Club</title><subtitle type='html'>[公告]本站所有文章嚴禁未經本人同意之轉錄或使用於商業用途</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>97</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-3007982196442964918</id><published>2108-09-30T12:21:00.011-04:00</published><updated>2011-05-20T12:29:09.293-04:00</updated><title type='text'>問題討論區</title><content type='html'>&lt;span class="Apple-style-span" style="color: #6aa84f;"&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #6aa84f;"&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #6aa84f;"&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'courier new'; font-size: 180%;"&gt;&lt;span style="font-size: 100%;"&gt;&lt;span class="Apple-style-span" style="color: blue; font-size: medium;"&gt;1.有要問語法問題的請在此留言。&lt;br /&gt;2.即日起不回覆私底下email給我的問題，請善加利用此問題討論區。&lt;br /&gt;3.不保證能夠回答所有問題，若不見我回覆則盼熱心網友能協助解答。&lt;br /&gt;4.請勿貼出一大串程式碼說跑不出來要我幫忙debug。&lt;br /&gt;5.SAS軟體本身的問題請自行聯繫SAS客服部門。&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'courier new'; font-size: 180%;"&gt;&lt;span style="font-size: 100%;"&gt;&lt;span class="Apple-style-span" style="color: blue; font-size: medium;"&gt;6.不幫忙代寫程式。&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #6aa84f;"&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #6aa84f;"&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #6aa84f;"&gt;&lt;b&gt;[版規]&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;div id="fb-root"&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="http://connect.facebook.net/en_US/all.js#xfbml=1"&gt;&lt;/script&gt;&lt;fb:comments href="sugiclub.blogspot.com" num_posts="5" width="700"&gt;&lt;/fb:comments&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-3007982196442964918?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/3007982196442964918/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=3007982196442964918&amp;isPopup=true' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/3007982196442964918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/3007982196442964918'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2008/09/blog-post.html' title='問題討論區'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-4224919921175314040</id><published>2011-10-14T18:52:00.001-04:00</published><updated>2011-10-14T18:52:44.645-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><category scheme='http://www.blogger.com/atom/ns#' term='模型配適'/><title type='text'>Fitting Cox Model Using PROC PHREG and Beyond in SAS</title><content type='html'>&lt;a href="http://support.sas.com/resources/papers/proceedings09/236-2009.pdf"&gt;http://support.sas.com/resources/papers/proceedings09/236-2009.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Cox PH 模型在倖存分析（survival analysis）被廣泛的使用。一篇發表在SAS GLOBAL FORUM 2009的技術文件解說了在 SAS 底下如何用 Cox PH 模型來計算一些重要估計量的方法，並且提供一個方便的巨集程式來簡化繁複的程式寫作和運行。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;C-index&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;C-index原本是在ROC curve裡面用來解釋預測鑒別能力的測量指標，但後來在Cox PH model裡也可以應用。在倖存分析裡，C-index可以解釋為一個機率，是從某個事件(如：死亡)來的一個病人，他會比非該事件內的任何一個病人都擁有較高的機會會發生該事件。以下列程式來說明如何用 SAS 算出 C-index：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc phreg data=sample;&lt;br /&gt;  id idn;&lt;br /&gt;  model combdays*combfv(0)=mihx diabhx lowef;&lt;br /&gt;  &lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;output out=obs survival=surv;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;這個PROC PHREG程序並沒有什麼特別，使用者唯一需要額外做的就是利用一個ODS OUTPUT指令把個體的ID, 觀測到的倖存時間以及倖存函數估計值另存一個新檔(ods)。接著，用下面兩到程序去整理出一個concordance data。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sql;&lt;br /&gt;      create table allset as&lt;br /&gt;      select idn_j, y_j, x_j, idn as idn_i, surv as y_i, combdays as x_i&lt;br /&gt;      from evtset, obs&lt;br /&gt;      where idn_j&amp;lt;&amp;gt;idn;&lt;br /&gt;quit;&lt;br /&gt;data concord;&lt;br /&gt;      set allset;&lt;br /&gt;      if (x_i&lt;x_j and="" y_i=""&gt;y_j) or (x_i&amp;gt;x_j and y_i&lt;y_j) code="" concord="1;" else="" run;&lt;="" then=""&gt;&lt;/y_j)&gt;&lt;/x_j&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;然後用下面這一串程式直接把C-index及其95%信賴區間該算出來：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data _null_;&lt;br /&gt;    set concord end=eof;&lt;br /&gt;    retain nch ndh;&lt;br /&gt;    if _N_=1 then do;&lt;br /&gt;      nch=0;&lt;br /&gt;      ndh=0;&lt;br /&gt;      end;&lt;br /&gt;    if concord=1 then nch+1;&lt;br /&gt;    if concord=0 then ndh+1;&lt;br /&gt;    if eof=1 then do;&lt;br /&gt;      call symput('ch',trim(left(nch)));&lt;br /&gt;      call symput('dh',trim(left(ndh)));&lt;br /&gt;      call symput('uspairs',trim(left(_n_)));&lt;br /&gt;      end;&lt;br /&gt;run;&lt;br /&gt;data _null_;&lt;br /&gt;     set sample end=eof;&lt;br /&gt;     if eof=1 then call symput('totobs',trim(left(_n_)));&lt;br /&gt;run;&lt;br /&gt;%put &amp;amp;ch &amp;amp;dh &amp;amp;uspairs &amp;amp;totobs;&lt;br /&gt;data calculat;&lt;br /&gt;    ch=input("&amp;amp;ch",12.0);&lt;br /&gt;    dh=input("&amp;amp;dh",12.0);&lt;br /&gt;    uspairs=input("&amp;amp;uspairs",12.0);&lt;br /&gt;    totobs=input("&amp;amp;totobs",10.0);&lt;br /&gt;    pc=ch/(totobs*(totobs-1));&lt;br /&gt;    pd=dh/(totobs*(totobs-1));&lt;br /&gt;    c_hat=pc/(pc+pd);&lt;br /&gt;    w=(2*1.96**2)/(totobs*(pc+pd));&lt;br /&gt;    low_ci_w=((w+2*c_hat)/(2*(1+w)))-(sqrt((w**2+4*w*c_hat*(1-c_hat))/(2*(1+w))));&lt;br /&gt;    upper_ci_w=((w+2*c_hat)/(2*(1+w)))+(sqrt((w**2+4*w*c_hat*(1-c_hat))/(2*(1+w))));&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;結果如下圖所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-OQR68PHZBt0/Tpi7LuG6WDI/AAAAAAAAGWE/x52sAZY4WsQ/s1600/sugi1.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="116" src="http://4.bp.blogspot.com/-OQR68PHZBt0/Tpi7LuG6WDI/AAAAAAAAGWE/x52sAZY4WsQ/s640/sugi1.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Calculating adjusted survival rates using corrected group prognosis method&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;作者自製了一段巨集程式 %CGPM_adj 可將倖存機率以及倖存曲線圖直接輸出。其原始碼如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;*****************************************************************************;&lt;br /&gt;* Program: CGPM_adj.sas;&lt;br /&gt;* Purpose: Calculate the unadjusted and adjusted survival rates and plot the&lt;br /&gt;*survival curves using corrected group prognosis method;&lt;br /&gt;*****************************************************************************;&lt;br /&gt;*----------------------------------------------------------------------------;&lt;br /&gt;* 1. All variables used in the model have to be binary variable.&lt;br /&gt;*Categorical and numeric variables need to be re-coded as dummy&lt;br /&gt;*variable to meet this requirement;&lt;br /&gt;* 2. The maximum number of variables in the model is limited to 20;&lt;br /&gt;*(not including the control variable). But this number can be&lt;br /&gt;*easily expanded as needed.;&lt;br /&gt;* 3. The analysis dataset for modeling was assign to be in SAS&lt;br /&gt;*default library WORK. ;&lt;br /&gt;*----------------------------------------------------------------------------;&lt;br /&gt;%macro CGPM_adj(outputpath, figname, tbname, dsn, covars, ctrlvar, outcom, cnsrval=0, timevar, rlalpha=0.05);&lt;br /&gt;*----------------------------------------------------------------------------;&lt;br /&gt;* Calculate unadjusted survival rate;&lt;br /&gt;*----------------------------------------------------------------------------;&lt;br /&gt;*create dataset for controlled variable;&lt;br /&gt;proc sql;&lt;br /&gt;      create table ctrlset as&lt;br /&gt;      select distinct &amp;amp;ctrlvar&lt;br /&gt;      from &amp;amp;dsn&lt;br /&gt;      order by &amp;amp;ctrlvar;&lt;br /&gt;quit;&lt;br /&gt;*get the unadjusted survival rates for controlled variable;&lt;br /&gt;proc phreg data=&amp;amp;dsn noprint;&lt;br /&gt;      model &amp;amp;timevar * &amp;amp;outcom (&amp;amp;cnsrval) = &amp;amp;ctrlvar;&lt;br /&gt;      baseline covariates=ctrlset out=unadjset survival=survival / nomean;&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;*----------------------------------------------------------------------------;&lt;br /&gt;* Calculate adjusted survival rates using corrected group prognosis method;&lt;br /&gt;*----------------------------------------------------------------------------;&lt;br /&gt;*create identifier set for all possible combinations of covariates;&lt;br /&gt;data _null_;&lt;br /&gt;      cnt=1+count("&amp;amp;covars",' ');&lt;br /&gt;      call symputx('varcnt', cnt);&lt;br /&gt;run;&lt;br /&gt;%put &amp;amp;varcnt;&lt;br /&gt;&lt;br /&gt;%macro idx;&lt;br /&gt;      %let i=1;&lt;br /&gt;      %do %until(%scan(&amp;amp;covars,&amp;amp;i,' ')=%str());&lt;br /&gt;      %local varnam;&lt;br /&gt;            %let varnam=%scan(&amp;amp;covars,&amp;amp;i,' ');&lt;br /&gt;            xp=&amp;amp;i+1;&lt;br /&gt;            if &amp;amp;varnam=1 then substr(idx,xp,1)=1;&lt;br /&gt;      %let i=%eval(&amp;amp;i+1);&lt;br /&gt;      %end;&lt;br /&gt;%mend;&lt;br /&gt;%macro idxrv;&lt;br /&gt;      %let i=1;&lt;br /&gt;      %do %until(%scan(&amp;amp;covars,&amp;amp;i,' ')=%str());&lt;br /&gt;      %local varnam;&lt;br /&gt;            %let varnam=%scan(&amp;amp;covars,&amp;amp;i,' ');&lt;br /&gt;            xp=&amp;amp;i+1;&lt;br /&gt;            if substr(idx,xp,1)='1' then &amp;amp;varnam=1; else &amp;amp;varnam=0;&lt;br /&gt;      %let i=%eval(&amp;amp;i+1);&lt;br /&gt;      %end;&lt;br /&gt;%mend;&lt;br /&gt;&lt;br /&gt;data modelset;&lt;br /&gt;      set &amp;amp;dsn;&lt;br /&gt;      idx=left(put(10**(input("&amp;amp;varcnt",2.0)),21.));&lt;br /&gt;      %idx;&lt;br /&gt;      keep idx &amp;amp;ctrlvar &amp;amp;covars &amp;amp;timevar &amp;amp;outcom;&lt;br /&gt;run;&lt;br /&gt;proc freq data=modelset noprint;&lt;br /&gt;      tables idx / out=idx;&lt;br /&gt;run;&lt;br /&gt;data popset (drop=percent xp);&lt;br /&gt;      if _n_=1 then do until(last);&lt;br /&gt;            set idx end=last;&lt;br /&gt;            &amp;amp;ctrlvar=0;&lt;br /&gt;            %idxrv;&lt;br /&gt;            output;&lt;br /&gt;            end;&lt;br /&gt;      set idx;&lt;br /&gt;            &amp;amp;ctrlvar=1;&lt;br /&gt;            %idxrv;&lt;br /&gt;            output;&lt;br /&gt;run;&lt;br /&gt;ods output censoredsummary=censum parameterEstimates=parasum;&lt;br /&gt;proc phreg data=modelset;&lt;br /&gt;      id idx;&lt;br /&gt;      model &amp;amp;timevar * &amp;amp;outcom (&amp;amp;cnsrval) = &amp;amp;ctrlvar &amp;amp;covars / rl alpha=&amp;amp;rlalpha;&lt;br /&gt;      baseline covariates=popset out=adjset0 survival=survival / nomean;&lt;br /&gt;run;&lt;br /&gt;ods output close;&lt;br /&gt;proc sort data=popset out=count (keep=idx count);&lt;br /&gt;by idx;&lt;br /&gt;run;&lt;br /&gt;proc sort data=adjset0;&lt;br /&gt;by idx;&lt;br /&gt;run;&lt;br /&gt;data adjset1;&lt;br /&gt;      merge adjset0 count;&lt;br /&gt;      by idx;&lt;br /&gt;run;&lt;br /&gt;proc sort data=adjset1;&lt;br /&gt;      by &amp;amp;ctrlvar &amp;amp;timevar;&lt;br /&gt;run;&lt;br /&gt;data adjset;&lt;br /&gt;      set adjset1;&lt;br /&gt;      by &amp;amp;ctrlvar &amp;amp;timevar;&lt;br /&gt;            if first.&amp;amp;timevar then frqsum=0;&lt;br /&gt;            frqsum+count;&lt;br /&gt;            if first.&amp;amp;timevar then sursum=0;&lt;br /&gt;            sursum+survival*count;&lt;br /&gt;      if last.&amp;amp;timevar;&lt;br /&gt;      adjsurv=sursum/frqsum;&lt;br /&gt;      keep &amp;amp;ctrlvar &amp;amp;timevar adjsurv;&lt;br /&gt;run;&lt;br /&gt;data allsurv;&lt;br /&gt;      length group $22;&lt;br /&gt;      set adjset (in=a rename=(adjsurv=survival)) unadjset (in=b);&lt;br /&gt;      if a=1 and &amp;amp;ctrlvar=0 then group='Adjusted'||' '||"&amp;amp;ctrlvar"||'=0';&lt;br /&gt;     else if a=1 and &amp;amp;ctrlvar=1 then group='Adjusted'||' '||"&amp;amp;ctrlvar"||'=1';&lt;br /&gt;      else if b=1 and &amp;amp;ctrlvar=0 then group='Unadjusted'||'&lt;br /&gt;'||"&amp;amp;ctrlvar"||'=0';&lt;br /&gt;      else if b=1 and &amp;amp;ctrlvar=1 then group='Unadjusted'||'&lt;br /&gt;'||"&amp;amp;ctrlvar"||'=1';&lt;br /&gt;      eventrate=1-survival;&lt;br /&gt;run;&lt;br /&gt;data summary;&lt;br /&gt;      set allsurv;&lt;br /&gt;      by group;&lt;br /&gt;      if last.group;&lt;br /&gt;run;&lt;br /&gt;*----------------------------------------------------------------------------;&lt;br /&gt;* You can change the code below to modify the title and graph axis scale etc.;&lt;br /&gt;*----------------------------------------------------------------------------;&lt;br /&gt;goption reset=all device=emf gsfname=grfa hsize=6.0 vsize=4 ftext='Arial/bo' htext=11pt display;&lt;br /&gt;filename grfa "&amp;amp;outputpath.\&amp;amp;figname..emf";&lt;br /&gt;&lt;br /&gt;symbol1 i=steplj v=none l=1 ci=green w=1;&lt;br /&gt;symbol2 i=steplj v=none l=1 ci=black w=1;&lt;br /&gt;symbol3 i=steplj v=none l=3 ci=green w=1;&lt;br /&gt;symbol4 i=steplj v=none l=3 ci=black w=1;&lt;br /&gt;axis1 offset=(0.5 cm,0.5 cm);&lt;br /&gt;&lt;br /&gt;axis2 label=(angle=90 j=c 'Survival') order=(0.8 to 1 by 0.05) offset=(0.0cm,0.0 cm);&lt;br /&gt;   legend1 across=2&lt;br /&gt;   mode=share&lt;br /&gt;   position=(bottom left inside)&lt;br /&gt;   label=none&lt;br /&gt;   value=(j=l h=10pt)&lt;br /&gt;   offset=(0.5cm, 0cm);&lt;br /&gt;proc gplot data=allsurv;&lt;br /&gt;   plot survival * &amp;amp;timevar = group / legend=legend1 haxis=axis1 vaxis=axis2;&lt;br /&gt;   label eventrate='Survival Rate' &amp;amp;timevar='Days After Randomization';&lt;br /&gt;run;&lt;br /&gt;quit;&lt;br /&gt;title;&lt;br /&gt;footnote;&lt;br /&gt;ods rtf style=journal file="&amp;amp;outputpath.\&amp;amp;tbname..rtf" bodytitle&lt;br /&gt;startpage=no;&lt;br /&gt;proc print data=parasum noobs;&lt;br /&gt;title "Analysis of Maximum Likelihood Estimates (alpha=&amp;amp;rlalpha for CI)";&lt;br /&gt;run;&lt;br /&gt;proc print data=summary noobs;&lt;br /&gt;var group survival eventrate;&lt;br /&gt;title 'Estimated survival and event rates at the time of last event observed';&lt;br /&gt;run;&lt;br /&gt;ods rtf close;&lt;br /&gt;%mend;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;巨集參數定義如下：&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;outputpath=報表與圖形輸出的路徑&amp;nbsp;&lt;/li&gt;&lt;li&gt;figname=圖形檔名&lt;/li&gt;&lt;li&gt;tbname=報表檔名&lt;/li&gt;&lt;li&gt;dsn=存放在SAS裡面的資料檔名&lt;/li&gt;&lt;li&gt;covars=所有預測變數的名稱，不包含控制變數的名稱&lt;/li&gt;&lt;li&gt;ctrlvar=控制變數的名稱&lt;/li&gt;&lt;li&gt;outcom=輸出變數(事件)的名稱&lt;/li&gt;&lt;li&gt;cnsrval=設限的代碼，預設值為0&lt;/li&gt;&lt;li&gt;timevar=時間變數名稱&lt;/li&gt;&lt;li&gt;rlalpha=顯著水準alpha，預設值為0.05&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;承上面的範例，巨集程式執行的寫法如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%CGPM_adj(outputpath=L:\SGF2009\Examples, &lt;br /&gt;          figname=Adjdiab_fig, &lt;br /&gt;          tbname=adjdiab_summary, &lt;br /&gt;          dsn=sample, &lt;br /&gt;          covars=age65 lowef chfhx, &lt;br /&gt;          ctrlvar=diabhx, &lt;br /&gt;          outcom=deathfv, &lt;br /&gt;          cnsrval=0, &lt;br /&gt;          timevar=deathdays, &lt;br /&gt;          rlalpha=0.05);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;結果如下：&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-WP_3r9uILc0/Tpi7ODu2EII/AAAAAAAAGWM/k5vCMqlhcLA/s1600/sugi2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="316" src="http://3.bp.blogspot.com/-WP_3r9uILc0/Tpi7ODu2EII/AAAAAAAAGWM/k5vCMqlhcLA/s640/sugi2.png" width="640" /&gt;&lt;/a&gt;&lt;a href="http://4.bp.blogspot.com/-P4gYoTawjWk/Tpi7OppvWCI/AAAAAAAAGWU/K1g9zoCfTs8/s1600/sugi3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="408" src="http://4.bp.blogspot.com/-P4gYoTawjWk/Tpi7OppvWCI/AAAAAAAAGWU/K1g9zoCfTs8/s640/sugi3.png" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Presenting the effect of a continuous covariate on estimated survival&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;當模型內包含連續型變數時，需要額外多兩個步驟來計算n-year倖存率。首先，用PROC PHREG程序把基底函數(baseline function)等一干相關的估計量另存成兩個新檔 yrout &amp;amp; sample(紅色部分)：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc phreg data=sample;&lt;br /&gt;model combdays*combfv(0)=age male;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;baseline out=yrout lower=low_ci upper=up_ci survival=surv covariates=sample/alpha=0.05 nomean;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;再依照想要分類的變數(male)，去和倖存時間變數去排序(combdays)後再另存新檔(maxday)：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sort data=sample out=maxday (where=(combfv=1) keep=idn male combfv combdays);&lt;br /&gt;      by male combdays;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;然後利用下面兩個資料步驟程序去計算男人和女人的5-year倖存率：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data _null_;&lt;br /&gt;      set maxday;&lt;br /&gt;      by male;&lt;br /&gt;      if male=0 and last.male then call symput('lastday_f',combdays);&lt;br /&gt;      if male=1 and last.male then call symput('lastday_m',combdays);&lt;br /&gt;run;&lt;br /&gt;%put &amp;amp;lastday_f &amp;amp;lastday_m;&lt;br /&gt;data yrest;&lt;br /&gt;      set yrout;&lt;br /&gt;      evtrate=(1-surv)*100;&lt;br /&gt;      evtlow=(1-low_ci)*100;&lt;br /&gt;      evtup=(1-up_ci)*100;&lt;br /&gt;      if combdays=&amp;amp;lastday_m and male=1 then output;&lt;br /&gt;      if combdays=&amp;amp;lastday_f and male=0 then output;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;最後畫出的圖形如下所示：&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/-Bc6oGdJryz0/Tpi7O0tnWXI/AAAAAAAAGWc/Absq1KL9l3E/s1600/sugi4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="362" src="http://3.bp.blogspot.com/-Bc6oGdJryz0/Tpi7O0tnWXI/AAAAAAAAGWc/Absq1KL9l3E/s640/sugi4.png" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;(PS) 原文內並沒有附此圖的繪製程式。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Contact information&lt;/span&gt;&lt;/b&gt; &lt;br /&gt;Lea Liu, &amp;nbsp;Maryland Medical Research Institute&lt;br /&gt;600 Wyndhurst Ave. Baltimore, MD 21210&lt;br /&gt;(410) 435-4200, &amp;nbsp;Email: lliu@mmri.org, &amp;nbsp;Web: www.mmri.org&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-4224919921175314040?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/4224919921175314040/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=4224919921175314040&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/4224919921175314040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/4224919921175314040'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/10/fitting-cox-model-using-proc-phreg-and.html' title='Fitting Cox Model Using PROC PHREG and Beyond in SAS'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-OQR68PHZBt0/Tpi7LuG6WDI/AAAAAAAAGWE/x52sAZY4WsQ/s72-c/sugi1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-2375885139926829096</id><published>2011-08-16T17:38:00.000-04:00</published><updated>2011-08-16T17:38:00.617-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='繪圖技巧'/><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>Wow! You Did That Map with SAS/GRAPH®?</title><content type='html'>原文載點：&lt;a href="http://www.nesug.info/Proceedings/nesug07/np/np01.pdf"&gt;http://www.nesug.info/Proceedings/nesug07/np/np01.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;身為一個專門從事空間時間序列分析的學者我來講，每天跟不同的地圖奮鬥是很稀鬆平常的是。目前市面上最熱門的地圖分析軟體莫過於ArcGIS，但這套軟體僅提供有限的分析方法，而其主要的功能僅僅就是繪製地圖而已。如果你用了別的軟體進行分析，就必須要將結果另存新檔，然後把結果跟地圖檔一起輸入到ArcGIS裡面才能開始繪圖。想當然爾，這裡面也沒有太多強大的資料整理功能，所以一切的一切都還是要經過另外的軟體將資料結果整理好才行。如果分析和繪製地圖的動作可以一次在SAS裡面完成的話將會省下許多時間和精力。NESUG 2007年有一篇教學文件，提供一些在SAS繪製地圖的資訊。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;PROC MAPIMPORT&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;這是SAS專門用來輸入地圖資料的語法，不過必須先知道去哪裡可以找到地圖資料。以下是作者列出的幾個不錯的網頁資源：&lt;br /&gt;&lt;br /&gt;(1) ESRI (a GIS software company)&lt;br /&gt;&lt;a href="http://arcdata.esri.com/data/tiger2000/tiger_download.cfm"&gt;http://arcdata.esri.com/data/tiger2000/tiger_download.cfm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(2)&amp;nbsp;US Census Bureau&lt;br /&gt;&lt;a href="http://www.census.gov/geo/www/cob/index.html"&gt;http://www.census.gov/geo/www/cob/index.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(3)&amp;nbsp;CDC (Centers for Disease Control)&lt;br /&gt;&lt;a href="http://www.cdc.gov/epiinfo/shape.htm"&gt;http://www.cdc.gov/epiinfo/shape.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(4) CIP (International Potato Center, part of the Consultative Group on International Agricultural Research)&lt;br /&gt;&lt;a href="http://research.cip.cgiar.org/gis/index.php"&gt;http://research.cip.cgiar.org/gis/index.php&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;其中，ESRI 就是 ArcGIS 的母公司，而美國地圖大都可以在 US Census Bureau 的網站上免費下載。CDC 的網站則是可以下載一個名叫Epi Info的軟體，裡面除了有地圖外還有其他的流病資料。CIP 的網站則是除了地圖以外還提供氣候資料。個人的經驗是 US Census Bureau 網站就足夠提供所有需要使用美國資料來進行研究的地圖。如果想進行台灣的研究，則可以到交通部的運研所下載：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.iot.gov.tw/ct.asp?xItem=154948&amp;amp;ctNode=1091"&gt;http://www.iot.gov.tw/ct.asp?xItem=154948&amp;amp;ctNode=1091&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;如果要別的國家的地圖資料，有兩個網站可以下載：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.diva-gis.org/gData"&gt;http://www.diva-gis.org/gData&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.vdstech.com/map_data.htm"&gt;http://www.vdstech.com/map_data.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;接下來的範例是用北卡（North Carolina）的資料畫地圖。先去 US Census Bureau 找北卡的 shape 檔：&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 15px; -webkit-border-vertical-spacing: 15px; font-family: arial, helvetica; font-size: 13px;"&gt;North Carolina -&lt;/span&gt;&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 15px; -webkit-border-vertical-spacing: 15px; font-family: arial, helvetica; font-size: 13px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 15px; -webkit-border-vertical-spacing: 15px; font-family: arial, helvetica; font-size: 13px;"&gt;&lt;a href="http://www.census.gov/geo/cob/bdy/zt/z500shp/zt37_d00_shp.zip"&gt;zt37_d00_shp.zip&lt;/a&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 15px; -webkit-border-vertical-spacing: 15px; font-family: arial, helvetica; font-size: 13px;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 15px; -webkit-border-vertical-spacing: 15px; font-family: arial, helvetica; font-size: 13px;"&gt;(1,672,705 bytes)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;解壓縮後存在自定目錄，然後執行下列程式：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;/*Version 9.1 */&lt;br /&gt;proc mapimport &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;datafile="&lt;span class="Apple-style-span" style="color: red;"&gt;path&lt;/span&gt;/zt37_d00.shp" &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;out=mymap91;&lt;br /&gt;run;&lt;br /&gt;/* Version 9.2 */&lt;br /&gt;proc mapimport;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;datafile="&lt;span class="Apple-style-span" style="color: red;"&gt;path&lt;/span&gt;/zt37_d00.shp" &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;out=mymap92;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;id zcta;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;記得把上面的 path 改為自己的路徑。如此一來 SAS 就可以把 shapefile 裡面的資料都輸入進去。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;MAPSONLINE&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;這是 SAS 官網提供的線上工具，裡面也有地圖資料和一些其他資訊。網址如下：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://support.sas.com/rnd/datavisualization/mapsonline/html/home.html"&gt;http://support.sas.com/rnd/datavisualization/mapsonline/html/home.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;重點是如果你不小心把 sashelp 資料庫裡面一個叫做 ZIPCODE 的檔案刪掉的話，可以去上面這個網址重新下載，因為這個資料裡面包含美國所有的地理資訊，要畫美國地圖一定得連結到這個檔案。裡面還有一個很威的資料名為 WORLDCTS，包含全世界各大城市的基本資料，可以到這個連結直接下載：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://support.sas.com/rnd/datavisualization/mapsonline/html/sampledata.html"&gt;http://support.sas.com/rnd/datavisualization/mapsonline/html/sampledata.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;CHOOSING MAP COLORS&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;在繪製地圖時，定義顏色是相當重要的一件事情。如何讓地圖上的顏色不會眼花撩亂並且能夠使讀者一目了然，這已經無關統計分析能力，而是一門藝術了。SAS 裡面對於顏色的指定可以使用顏色本來的英文名稱、RGB值、HLS值以及HEX值。所有的定義都可以去 SAS TS-688 的網站去看：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://support.sas.com/techsup/technote/ts688/ts688.html"&gt;http://support.sas.com/techsup/technote/ts688/ts688.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;下面用一個簡單範例介紹：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%let color1=lightgreen&amp;nbsp;; &lt;br /&gt;%let color2=cornsilk&amp;nbsp;;&lt;br /&gt;proc template;&lt;br /&gt;&amp;nbsp; &amp;nbsp;define style styles.grade;&lt;br /&gt;&amp;nbsp; &amp;nbsp;parent=styles.listing;&lt;br /&gt;&amp;nbsp; &amp;nbsp;style twocolorramp / startcolor=&amp;amp;color1 endcolor=&amp;amp;color2;&lt;br /&gt;&amp;nbsp; &amp;nbsp;end; &lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;DISTANCE CALCULATIONS&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;計算點和點之間的距離是空間分析裡面的基本功，當知道兩個地點的經緯度（不知道的可以去用google map查詢）後，利用下面這個巨集程式便可輕鬆計算出來：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro geodist(lat1,long1,lat2,long2);&lt;br /&gt;%let pi180=0.0174532925199433;&lt;br /&gt;&amp;nbsp; &amp;nbsp; 7921.6623*arsin(sqrt((sin((&amp;amp;pi180*&amp;amp;lat2-&amp;amp;pi180*&amp;amp;lat1)/2))**2+&lt;br /&gt;&amp;nbsp; &amp;nbsp; cos(&amp;amp;pi180*&amp;amp;lat1)*cos(&amp;amp;pi180*&amp;amp;lat2)*(sin((&amp;amp;pi180*&amp;amp;long2- &amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;amp;pi180*&amp;amp;long1)/2))**2));&lt;br /&gt;%mend&lt;/code&gt;&lt;/pre&gt;如果是做美國的地理研究，則只需要知道每個 county 的 ZIP code 即可。在SAS V9.2版裡面有一個 ZIPCITYDIST() 函式就是專門用來計算兩個 ZIP code 之間的距離。範例如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%let zip1=27513;&lt;br /&gt;%let zip2=21202;&lt;br /&gt;/* latitude and longitude coordinates */&lt;br /&gt;proc sql;&lt;br /&gt;create table zip1 as select * from sashelp.zipcode where zip=&amp;amp;zip1;&lt;br /&gt;create table zip2 as select * from sashelp.zipcode where zip=&amp;amp;zip2;&lt;br /&gt;select x into :long1 from zip1;&lt;br /&gt;select y into :lat1 from zip1;&lt;br /&gt;select x into :long2 from zip2;&lt;br /&gt;select y into :lat2 from zip2;&lt;br /&gt;quit; run;&lt;br /&gt;%let city1=%sysfunc(zipcity(&amp;amp;zip1));&lt;br /&gt;%let city2=%sysfunc(zipcity(&amp;amp;zip2));&lt;br /&gt;/* two new 9.2 functions */&lt;br /&gt;%let zipdist=%sysfunc(zipcitydistance(&amp;amp;zip1,&amp;amp;zip2));&lt;br /&gt;%let geodist=%sysfunc(geodist(&amp;amp;lat1, &amp;amp;long1, &amp;amp;lat2, &amp;amp;long2, 'M'),comma10.5);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;GRAPHIC OVERLAYS&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-NpYERIPYae0/TkrZhYnSiuI/AAAAAAAAGR4/eMRd_vqXYXg/s1600/us_map_area.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="425" src="http://2.bp.blogspot.com/-NpYERIPYae0/TkrZhYnSiuI/AAAAAAAAGR4/eMRd_vqXYXg/s640/us_map_area.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;上面這張圖是利用 PROC GCHART 畫好柱狀圖，然後用 PROC GMAP 畫好地圖，之後把柱狀圖疊在地圖上面。首先把地圖畫好：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;pattern v=me c=gray98;&lt;br /&gt;proc gmap data=maps.us (obs=1) map=maps.us all anno=region_outline;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; id state;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; choro state / discrete nolegend coutline=gray98;&lt;br /&gt;run;&lt;br /&gt;quit;&lt;/code&gt;&lt;/pre&gt;再來把柱狀圖下面的文字設定好：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;axis1 label=('NEW ENGLAND' &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;j=c '%CHANGE 48.7') ;&lt;br /&gt;axis2 label=('MIDDLE ATLANTIC' &amp;nbsp; &amp;nbsp;j=c '%CHANGE 21.1') ;&lt;br /&gt;axis3 label=('SOUTH ATLANTIC' &amp;nbsp; &amp;nbsp; j=c '%CHANGE 18.7') ;&lt;br /&gt;axis4 label=('WEST NORTH CENTRAL' j=c '%CHANGE 63.3') ;&lt;br /&gt;axis5 label=('EAST NORTH CENTRAL' j=c '%CHANGE 33.3') ;&lt;br /&gt;axis6 label=('EAST SOUTH CENTRAL' j=c '%CHANGE 48.4') ;&lt;br /&gt;axis7 label=('WEST SOUTH CENTRAL' j=c '%CHANGE 22.5') ;&lt;br /&gt;axis8 label=('MOUNTAIN' &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; j=c '%CHANGE 50.9') ;&lt;br /&gt;axis9 label=('PACIFIC' &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;j=c '%CHANGE 23.9') ;&lt;br /&gt;axis10 order=0 to 20 by 5 label=none value=none style=0 major=none minor=none;&lt;/code&gt;&lt;/pre&gt;其中，axis1~axis9 自然就是九個柱狀圖 X 軸的文字和統計數據（這自己另外算好先），而 axis10 則表示用來控制 axis1~axis9 的 Y 軸共同設定。然後依序畫出每張柱狀圖，以右上角的 New England 為例：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc gchart data=tpay;&lt;br /&gt;goptions &lt;span class="Apple-style-span" style="color: blue;"&gt;horigin=8.75 in vorigin=6.75 in&lt;/span&gt;;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;where region eq 1;&lt;/span&gt;&lt;br /&gt;vbar time / type=mean discrete sumvar=x mean&lt;span class="Apple-style-span" style="color: red;"&gt; raxis=axis10 maxis=axis1&lt;/span&gt;;&lt;br /&gt;run;&lt;br /&gt;quit;&lt;/code&gt;&lt;/pre&gt;資料集 tpay 裡面因為有所有 region 的資料，所以要用一個 where statement 限制只使用 New England (region = 1) 的數據。而 raxis 和 maxis 就是設定 Y 軸和 X 軸的選項，所以把 axis10 和 axis1 分別填入。當要畫別區的柱狀圖時，只要把 maxis 後面的設定換掉即可。至於 goptions 則是用來控制柱狀圖出現的位置。這就必須自己一直更換不同的數據來看位置對不對。你也可以用一個巨集程式來簡化步驟：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro bars(reg,h,v);&lt;br /&gt;goptions horigin=&amp;amp;h in vorigin=&amp;amp;v in;&lt;br /&gt;where region eq &amp;amp;reg;&lt;br /&gt;vbar time / type=mean discrete sumvar=x raxis=axis10 maxis=axis&amp;amp;reg mean;&lt;br /&gt;run;&lt;br /&gt;%mend;&lt;/code&gt;&lt;/pre&gt;因此九張柱狀圖就可以用下面短短的程式碼一口氣完成：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc gchart data=tpay;&lt;br /&gt;%bars(1,8.75,6.45) %bars(2,7.75,4.90) %bars(3,7.50,3.00) &lt;br /&gt;%bars(4,4.00,5.00) %bars(5,6.00,4.25) %bars(6,6.10,2.50) &lt;br /&gt;%bars(7,4.00,1.85) %bars(8,1.95,4.20) %bars(9,0.00,2.00)&lt;br /&gt;quit; &lt;/code&gt;&lt;/pre&gt;最後一個步驟就是要把這些柱狀圖疊到地圖上。我們先用 ODS 開一個空白的 pdf 檔：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ods pdf file='z:\map_bars.pdf' notoc startpage=never;&lt;/code&gt;&lt;/pre&gt;後面的 notoc 和 startpage 主要是抑制 pdf 檔的書籤出現以及讓所有圖形都出現在同一頁。然後進行 pdf 檔裡面的環境設定：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;goptions reset=all ftext='Helvetica/bo' htext=3.5 gunit=pct ctext=blue lfactor=3;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;這些都是來設定字形、字色還有字體大小。這樣就大功告成了。整個流程可以用下列四步驟來簡單描述：&lt;br /&gt;&lt;br /&gt;步驟一：用 GOPTIONS 進行圖形整體環境設定。&lt;br /&gt;步驟二：用 ODS 開啟一個空白的 pdf 檔。&lt;br /&gt;步驟三：用 PROC GMAP 畫地圖。&lt;br /&gt;步驟四：用 PROC GCHART 畫柱狀圖&lt;br /&gt;&lt;br /&gt;最後用 ODS CLOSE 把整個圖形打包起來。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;REFERENCES &amp;amp; RECOMMENDED READING&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;以下是一些不錯的線上參考資料：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://support.sas.com/documentation/onlinedoc/index.html"&gt;http://support.sas.com/documentation/onlinedoc/index.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://support.sas.com/rnd/datavisualization/mapsonline/html/home.html"&gt;http://support.sas.com/rnd/datavisualization/mapsonline/html/home.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://support.sas.com/rnd/papers"&gt;http://support.sas.com/rnd/papers&lt;/a&gt;&lt;br /&gt;&lt;a href="http://support.sas.com/samples"&gt;http://support.sas.com/samples&lt;/a&gt;&lt;br /&gt;&lt;a href="http://ftp.sas.com/techsup/download/sample/graph/other-color.html"&gt;http://ftp.sas.com/techsup/download/sample/graph/other-color.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://arcdata.esri.com/data/tiger2000/tiger_download.cfm"&gt;http://arcdata.esri.com/data/tiger2000/tiger_download.cfm&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.census.gov/geo/www/cob/index.html"&gt;http://www.census.gov/geo/www/cob/index.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.cdc.gov/epiinfo/shape.htm"&gt;http://www.cdc.gov/epiinfo/shape.htm&lt;/a&gt;&lt;br /&gt;&lt;a href="http://research.cip.cgiar.org/gis/index.php"&gt;http://research.cip.cgiar.org/gis/index.php&lt;/a&gt;&lt;br /&gt;&lt;a href="http://support.sas.com/techsup/technote/ts688/ts688.html"&gt;http://support.sas.com/techsup/technote/ts688/ts688.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.colorbrewer.org/"&gt;http://www.colorbrewer.org&lt;/a&gt;&lt;br /&gt;&lt;a href="http://robslink.com/SAS/Home.htm"&gt;http://robslink.com/SAS/Home.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;CONTACT INFORMATION&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. &amp;nbsp;Contact the authors at:&lt;br /&gt;Robert Allison&lt;br /&gt;&lt;a href="mailto:robert.allison@sas.com"&gt;robert.allison@sas.com&lt;/a&gt;&lt;br /&gt;Louise Hadden&lt;br /&gt;&lt;a href="mailto:louise_hadden@abtassoc.com"&gt;louise_hadden@abtassoc.com&lt;/a&gt;&lt;br /&gt;Mike Zdeb&lt;br /&gt;&lt;a href="mailto:msz03@albany.edu"&gt;msz03@albany.edu&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-2375885139926829096?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/2375885139926829096/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=2375885139926829096&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/2375885139926829096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/2375885139926829096'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/08/wow-you-did-that-map-with-sasgraph.html' title='Wow! You Did That Map with SAS/GRAPH®?'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-NpYERIPYae0/TkrZhYnSiuI/AAAAAAAAGR4/eMRd_vqXYXg/s72-c/us_map_area.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-3460027840021288645</id><published>2011-07-09T10:17:00.001-04:00</published><updated>2011-07-09T10:27:54.212-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>MCPOWER: a Flexible Macro Suite for Generating Monte Carlo Power Estimates for Linear, Logistic, and Poisson Regression Models</title><content type='html'>原文載點：&lt;a href="http://support.sas.com/resources/papers/proceedings11/430-2011.pdf"&gt;http://support.sas.com/resources/papers/proceedings11/430-2011.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;哈佛的一位統計分析師分享了一個名為 %mcpower 的巨集程式，能夠輕鬆的完成在線性迴歸、羅吉斯迴歸以及卜瓦松迴歸的蒙地卡羅檢定力模擬與估計。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;%mcpower 主要包含 %glmpower 和 %manypower 兩個巨集程式。程式可從此處下載：&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.kenkleinman.net/home/index.php/sas-and-r-code/sas-macros.html"&gt;http://www.kenkleinman.net/home/index.php/sas-and-r-code/sas-macros.html&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;其中，%glmpower 是無法直接被執行的，所有的參數都是定義在 %manypower 裡面，格式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro manypower(alt1=.,&amp;nbsp;alt2=.,&amp;nbsp;alt3=.,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;n1=.,n2=.,n3=.,n4=.,n5=.,n6=.,n7=.,n8=.,n9=.,n10=.,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;outcomedist = "NORMAL", null=0, scaley=1,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;xdist="NORMAL", xloc=., xscale =.,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;nreps=,plotrows=2, descending = desc, intercept = 0,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;plotstyle=graphic, outputpower=YES, outputnsubs=YES, test=FALSE);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;不意外地，巨集變數很多，但因為模擬本來就是一件即為複雜的工作，所以參數多也是很正常的。這些參數主要可以分類為三大群：&lt;br /&gt;&lt;br /&gt;&lt;b&gt;假設巨集變數&lt;/b&gt;：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;null：所要檢定之虛無假設的值。預設值為 0。&lt;/li&gt;&lt;li&gt;alt1, alt2, alt3：所要檢定之對立假設(Ha)的數值。若是線性迴歸，則檢定的項目是斜率，若是羅吉斯迴歸，則檢定的項目是odds ratio。若是卜瓦松迴歸，則檢定的項目是risk ratio。無預設值。&lt;/li&gt;&lt;li&gt;n1, n2, ..., n10：每個模擬資料集裡面的樣本個數。最多可設定十個。無預設值。&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;分配巨集變數&lt;/b&gt;：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;outcomedist：依變數的分配。可填入 "NORMAL"、"BERNOULLI" 和 "POISSON"。預設值為 "NORMAL"。(注意，雙引號要寫上）&lt;/li&gt;&lt;li&gt;scaley：殘差變異數。若使用線性迴歸(即outcomedist = "NORMAL")，則可以省略這個參數的設定。預設值為 1。&lt;/li&gt;&lt;li&gt;intercept：模擬的模型裡面的截距項。預設值為 0。&lt;/li&gt;&lt;li&gt;xdist：應變數的分配。預設值是 "NORMAL"。&lt;/li&gt;&lt;li&gt;xloc：應變數分配的第一個參數值。若 xdist = "NORMAL" 時，此值表示平均數。若 xdist = "POISSON" 時，則此值表示 lambda。若 xdist = "BERNOULLI" 時，則此值表示 p。&lt;/li&gt;&lt;li&gt;xscale：應變數分配的第二個參數值。若 xdist 為 "POISSON" 或 "BERNOULLI" 時，則此值要省略，因為這兩個分配只有一個參數值。若 xdist = "NORMAL" 時，則可設定變異數。&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;輸出巨集變數：&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;outputpower：輸出檢定力表格。預設值為 YES。&lt;/li&gt;&lt;li&gt;outputnsubs：輸出樣本數表格。預設值為 YES。&lt;/li&gt;&lt;li&gt;plotstyle：輸出表格的格式。如果設定為 sg，則圖形會用 PROC SGPLOT 程序來畫。如果設定為 graphic，則圖形會用 PROC GPLOT &amp;nbsp;來畫。如果沒有設定，則圖形就不會輸出。預設值為 graphic。&lt;/li&gt;&lt;li&gt;plotrows：若 plotstyle = sg 時，則可設定圖形要有幾行。預設值為 2。&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;範例：&lt;/div&gt;&lt;pre&gt;&lt;code&gt;%manypower(null = 0, scaley=1,xdist = "bernoulli", xloc=.5, xscale=.,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;nreps = 100, n1=1000,n2=1100,n3=1200,n4=1400,n5=1700,n6=2000,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;alt1 = 1.15, alt2 = 1.20, alt3 = 1.25,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;plotrows=2,plotstyle=graphic, outcomedist="poisson", intercept = 1);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;結果：&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-5Ej8iN6EYls/TgSzAaHF43I/AAAAAAAAF80/RrFo2WMS5Y0/s1600/1308930817870.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="424" src="http://2.bp.blogspot.com/-5Ej8iN6EYls/TgSzAaHF43I/AAAAAAAAF80/RrFo2WMS5Y0/s640/1308930817870.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-APFgbfHFsXE/TgSxzCjURrI/AAAAAAAAF8c/-6NeUsHdF_4/s1600/1308930508385.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="326" src="http://3.bp.blogspot.com/-APFgbfHFsXE/TgSxzCjURrI/AAAAAAAAF8c/-6NeUsHdF_4/s640/1308930508385.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-jTRzRSxTkHk/TgSx6myXvYI/AAAAAAAAF8g/8J1eOpbF-TI/s1600/1308930538395.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="148" src="http://2.bp.blogspot.com/-jTRzRSxTkHk/TgSx6myXvYI/AAAAAAAAF8g/8J1eOpbF-TI/s640/1308930538395.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&lt;/b&gt;&lt;br /&gt;Your comments and questions would be welcome and valued. &amp;nbsp;Contact the author at:&lt;br /&gt;Ken Kleinman&lt;br /&gt;Harvard Medical School and Harvard Pilgrim Health Care&lt;br /&gt;133 Brookline Ave.&lt;br /&gt;Boston, MA 02215&lt;br /&gt;ken.kleinman@gmail.com&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-3460027840021288645?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/3460027840021288645/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=3460027840021288645&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/3460027840021288645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/3460027840021288645'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/07/mcpower-flexible-macro-suite-for.html' title='MCPOWER: a Flexible Macro Suite for Generating Monte Carlo Power Estimates for Linear, Logistic, and Poisson Regression Models'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-5Ej8iN6EYls/TgSzAaHF43I/AAAAAAAAF80/RrFo2WMS5Y0/s72-c/1308930817870.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-5552643391491270112</id><published>2011-07-02T10:57:00.001-04:00</published><updated>2011-07-02T10:57:00.164-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>Fundamental Diagnostics for Two-Level Mixed Models: The SAS ®  Macro MIXED_DX</title><content type='html'>原文載點：http://support.sas.com/resources/papers/proceedings10/201-2010.pdf&lt;br /&gt;&lt;br /&gt;在進行 mixed model 分析時，模型的檢定是相當重要但也是相當煩人的一環。幾位南卡大和南佛大的學者寫了一個巨集程式來簡化相關程式的寫作，雖然目前這個程式只能使用在 2-level model，但也是具有相當貢獻。&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;這個名叫 %mixed_dx 的巨集程式如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%mixed_dx (ModelI = ,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Dims = ,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; solnF = ,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; solnR =,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Level1 = ,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Influence = ,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; min_nj = ,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pr = ,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; GroupVar = );&lt;/code&gt;&lt;/pre&gt;每個參數的設定如下：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ModelI：讀取由ODS OUTPUT的ModelInfo選項所生成的包含所有模型資訊的資料&lt;/li&gt;&lt;li&gt;Dims：讀取由ODS OUTPUT的Dimensions選項所生成的資料維度數據&lt;/li&gt;&lt;li&gt;solnF：讀取由ODS OUTPUT的SolutionF選項所生成的固定效應參數估計值&lt;/li&gt;&lt;li&gt;solnR：讀取由ODS OUTPUT的SolutionR選項所生成的隨機效應參數估計值&lt;/li&gt;&lt;li&gt;Level1：讀取由model statement的outp選項所生成的Level-1殘差值資料&lt;/li&gt;&lt;li&gt;Influence：讀取由model statement的influence選項所生成的模型檢定數據&lt;/li&gt;&lt;li&gt;min_nj：設定Level-2 unit的最小組內樣本數&lt;/li&gt;&lt;li&gt;pr：定義檢定內所需要用到的threshold percentile rank(預設值=90)&lt;/li&gt;&lt;li&gt;GroupVar：若有使用名義(nominal)類別的Level-2 unit的因子，則必須要把每個名義類別的定義另存一個新檔並用此巨集變數來呼叫。&lt;/li&gt;&lt;/ul&gt;首先，利用PROC MIXED程序去估計一個模型，並且利用ODS OUTPUT的功能把%mixed_dx要用到的資料給另存出來：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ods exclude influence SolutionR;&lt;br /&gt;title;&lt;br /&gt;proc mixed data = temp covtest noclprint NAMELEN=32;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;class schoolid;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;model mathach = SIZE FEMALE SES MEANSES SES*MEANSES SES*SIZE&amp;nbsp;FEMALE*SIZE/ solution &lt;span class="Apple-style-span" style="color: blue;"&gt;outp=L1Resid&lt;/span&gt; &lt;span class="Apple-style-span" style="background-color: orange;"&gt;influence(effect=schoolid iter=5)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;random &amp;nbsp;intercept FEMALE SES / sub=schoolid solution type=un;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-style-span" style="color: red;"&gt;ods output SolutionR=L2Resid SolutionF=Fixed ModelInfo=ModelStuff&amp;nbsp;Dimensions=DatStuff Influence=influence&lt;/span&gt;;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;其中，outp選項所輸出的資料L1Resid是level 1的殘差值，這是要用在Level1參數裡面的。橘色高亮部分即為原始PROC MIXED內定的模型檢定指令，若配合ODS HTML的話可以輸出高解析度的圖表，但就是因為裡面包含太多圖了，所以才需要使用%mixed_dx來把幾個重要的圖整理出來。而紅色部分即為ODS OUTPUT輸出的指令。此處是缺一不可，即為重要。&lt;br /&gt;&lt;br /&gt;接下來就來執行巨集程式：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%mixed_dx (ModelI = modelstuff, Dims = datstuff, solnF = Fixed, solnR =&amp;nbsp;L2Resid, Level1 = L1Resid, Influence = influence, min_nj = 5, pr = 90,&amp;nbsp;GroupVar = None);&lt;/code&gt;&lt;/pre&gt;在生成的圖形當中，主要以殘差的箱型圖、柱狀分布圖以及散布圖為主。另外也有殘差變異數的散布圖（用來檢定同質性）還有離群值的柱狀分布圖。如下所示：&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-lL4QzLw2xsU/Tfjg1GbcEzI/AAAAAAAAF7A/-x5y8CBngjo/s1600/1308156116691.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-lL4QzLw2xsU/Tfjg1GbcEzI/AAAAAAAAF7A/-x5y8CBngjo/s320/1308156116691.png" width="232" /&gt;&lt;/a&gt;&lt;a href="http://3.bp.blogspot.com/-mVZs_x8oTl4/Tfjg6ZvR9SI/AAAAAAAAF7E/r2dkR4E1k48/s1600/1308156138323.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-mVZs_x8oTl4/Tfjg6ZvR9SI/AAAAAAAAF7E/r2dkR4E1k48/s320/1308156138323.png" style="cursor: move;" width="249" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;表格方面，會整理出level-2 unit的常態統計量表、Levene’s同質性檢定表、離群值檢定和各種檢定統計量：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ZES6TXJgcXc/TfjgaVouX1I/AAAAAAAAF60/viVUNfhBK4s/s1600/1308156009762.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-ZES6TXJgcXc/TfjgaVouX1I/AAAAAAAAF60/viVUNfhBK4s/s320/1308156009762.png" width="245" /&gt;&lt;/a&gt;&lt;a href="http://1.bp.blogspot.com/-dZXo-rf_LAY/Tfjgj5mauHI/AAAAAAAAF64/oMkZRo0U2a8/s1600/1308156047388.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-dZXo-rf_LAY/Tfjgj5mauHI/AAAAAAAAF64/oMkZRo0U2a8/s320/1308156047388.png" style="cursor: move;" width="212" /&gt;&lt;/a&gt;&lt;a href="http://1.bp.blogspot.com/-TAcTIX-wMNA/TfjgqLcoTxI/AAAAAAAAF68/2BuBcu5Lgpc/s1600/1308156073149.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-TAcTIX-wMNA/TfjgqLcoTxI/AAAAAAAAF68/2BuBcu5Lgpc/s320/1308156073149.png" style="cursor: move;" width="250" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;目前這段程式碼可以在他們的校方網站上面下載：&lt;a href="http://www.ed.sc.edu/bell/"&gt;http://www.ed.sc.edu/bell/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION &amp;nbsp;&lt;/b&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. &amp;nbsp;Contact the author at:&lt;br /&gt;Bethany A. Bell&lt;br /&gt;University of South Carolina&lt;br /&gt;College of Education, Wardlaw 133&lt;br /&gt;Columbia, SC 29208&lt;br /&gt;Work Phone: 803-777-2387&lt;br /&gt;E-mail:babell@sc.edu&lt;br /&gt;Web: http://www.ed.sc.edu/bell/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-5552643391491270112?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/5552643391491270112/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=5552643391491270112&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/5552643391491270112'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/5552643391491270112'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/07/fundamental-diagnostics-for-two-level.html' title='Fundamental Diagnostics for Two-Level Mixed Models: The SAS ®  Macro MIXED_DX'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-lL4QzLw2xsU/Tfjg1GbcEzI/AAAAAAAAF7A/-x5y8CBngjo/s72-c/1308156116691.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-1616952410225347325</id><published>2011-06-25T10:35:00.000-04:00</published><updated>2011-06-25T10:35:01.257-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程序語法'/><title type='text'>Expanding PROC EXPAND</title><content type='html'>原文載點：&lt;a href="http://support.sas.com/resources/papers/proceedings11/417-2011.pdf"&gt;http://support.sas.com/resources/papers/proceedings11/417-2011.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;PROC EXPAND 程序是 SAS/ETS 裡面其中一個語法，提供許多跟時間相關資料的簡便處理。比方說，將日資料累加成月資料，月資料累加成季資料或年資料，也可以倒過來把季/年資料變成月資料，月資料變成日資料。若遇到缺漏值，該程序可用內插法將資料補齊。也可進行諸如moving average的資料轉換。Bruce Gilsen 在 2011 年的 SAS Global Forum 發表了一篇技術文件，介紹了兩個用 PROC EXPAND 運作的例子。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;b&gt;Calculate an un-weighted quarterly average from monthly data&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;第一個例子介紹如何將月資料轉成季資料。使用的範例資料如下(部分)：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;nbsp; Obs &amp;nbsp; &amp;nbsp; date &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; id &amp;nbsp; income&lt;br /&gt;&amp;nbsp; &amp;nbsp; 1 &amp;nbsp; &amp;nbsp;20070101 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp;1&lt;br /&gt;&amp;nbsp; &amp;nbsp; 2 &amp;nbsp; &amp;nbsp;20070201 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp;2&lt;br /&gt;&amp;nbsp; &amp;nbsp; 3 &amp;nbsp; &amp;nbsp;20070301 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 15&lt;br /&gt;&amp;nbsp; &amp;nbsp; 4 &amp;nbsp; &amp;nbsp;20070401 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp;4&lt;br /&gt;&amp;nbsp; &amp;nbsp; 5 &amp;nbsp; &amp;nbsp;20070501 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp;5&lt;br /&gt;&amp;nbsp; &amp;nbsp; 6 &amp;nbsp; &amp;nbsp;20070601 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 12&lt;br /&gt;&amp;nbsp; &amp;nbsp; 7 &amp;nbsp; &amp;nbsp;20070701 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp;7&lt;br /&gt;&amp;nbsp; &amp;nbsp; 8 &amp;nbsp; &amp;nbsp;20070801 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp;8&lt;br /&gt;&amp;nbsp; &amp;nbsp; 9 &amp;nbsp; &amp;nbsp;20070901 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp;9&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc expand data=one out=two &lt;span class="Apple-style-span" style="color: red;"&gt;from=month to=quarter&lt;/span&gt; ;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; id date;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; by id;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class="Apple-style-span" style="color: blue;"&gt;convert income / method=aggregate observed=average&lt;/span&gt;;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;紅色部分的 from=month to=quarter 顧名思義就是把資料從月(month)轉成季(quarter)。藍色部分表示轉換的變數為 income，方法為累加(aggregate)，最後求出"非加權"平均值(average)。結果如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp;Obs &amp;nbsp; &amp;nbsp;id &amp;nbsp; &amp;nbsp; &amp;nbsp;date &amp;nbsp; &amp;nbsp; income &amp;nbsp; &amp;nbsp;income&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(expected result)&lt;br /&gt;&amp;nbsp; &amp;nbsp; 1 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp;2007:1 &amp;nbsp; &amp;nbsp; 6.1333 &amp;nbsp; &amp;nbsp; &amp;nbsp; 6&lt;br /&gt;&amp;nbsp; &amp;nbsp; 2 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp;2007:2 &amp;nbsp; &amp;nbsp; 6.9780 &amp;nbsp; &amp;nbsp; &amp;nbsp; 7&lt;br /&gt;&amp;nbsp; &amp;nbsp; 3 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp;2007:3 &amp;nbsp; &amp;nbsp; 7.9891 &amp;nbsp; &amp;nbsp; &amp;nbsp; 8&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;最後一欄income(expected result)便是所求，不過程式也會把加權後的結果一併列出，即為倒數第二欄的結果。加權的方式是用天數為基準。以第三季(七～九月)結果來看，前三個月的天數分別是31, 31, 30。總計為92天，因此加權平均後的結果是&lt;br /&gt;&lt;pre&gt;&lt;code&gt;((31 * 7) + (31 * 8) + (30 * 9)) / 92 = 7.9891&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Convert weekly data to a monthly average when the weekly values represent values for seven days&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;先看一下範例：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp;Obs &amp;nbsp; date &amp;nbsp; &amp;nbsp; &amp;nbsp; id &amp;nbsp; income&lt;br /&gt;&amp;nbsp; &amp;nbsp; 1 &amp;nbsp; &amp;nbsp;20070530 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 11&lt;br /&gt;&amp;nbsp; &amp;nbsp; 2 &amp;nbsp; &amp;nbsp;20070606 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 30&lt;br /&gt;&amp;nbsp; &amp;nbsp; 3 &amp;nbsp; &amp;nbsp;20070613 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 50&lt;br /&gt;&amp;nbsp; &amp;nbsp; 4 &amp;nbsp; &amp;nbsp;20070620 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 70&lt;br /&gt;&amp;nbsp; &amp;nbsp; 5 &amp;nbsp; &amp;nbsp;20070627 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 90&lt;br /&gt;&amp;nbsp; &amp;nbsp; 6 &amp;nbsp; &amp;nbsp;20070704 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 50&lt;br /&gt;&amp;nbsp; &amp;nbsp; 7 &amp;nbsp; &amp;nbsp;20070711 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 40&lt;br /&gt;&amp;nbsp; &amp;nbsp; 8 &amp;nbsp; &amp;nbsp;20070718 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp;120&lt;br /&gt;&amp;nbsp; &amp;nbsp; 9 &amp;nbsp; &amp;nbsp;20070725 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 80&lt;br /&gt;&amp;nbsp; &amp;nbsp;10 &amp;nbsp; &amp;nbsp;20070801 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp;100&lt;br /&gt;&amp;nbsp; &amp;nbsp;11 &amp;nbsp; &amp;nbsp;20070808 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp;5&lt;br /&gt;&amp;nbsp; &amp;nbsp;12 &amp;nbsp; &amp;nbsp;20070815 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp;7&lt;br /&gt;&amp;nbsp; &amp;nbsp;13 &amp;nbsp; &amp;nbsp;20070822 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp;9&lt;br /&gt;&amp;nbsp; &amp;nbsp;14 &amp;nbsp; &amp;nbsp;20070829 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 11&lt;br /&gt;&amp;nbsp; &amp;nbsp;15 &amp;nbsp; &amp;nbsp;20070905 &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 24&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;將週資料轉成月資料的方法同第一個範例：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc expand data=one out=two from=&lt;span class="Apple-style-span" style="color: red;"&gt;week &lt;/span&gt;to=&lt;span class="Apple-style-span" style="color: red;"&gt;month &lt;/span&gt;;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; id date;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; by id;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; convert income / observed=average;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;結果如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp;Obs &amp;nbsp; &amp;nbsp;id &amp;nbsp; &amp;nbsp; &amp;nbsp;date &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;income &amp;nbsp; &amp;nbsp;income&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(expected result)&lt;br /&gt;&amp;nbsp; &amp;nbsp; 1 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp;JUN2007 &amp;nbsp; &amp;nbsp; &amp;nbsp;57.093 &amp;nbsp; &amp;nbsp; 60&lt;br /&gt;&amp;nbsp; &amp;nbsp; 2 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp;JUL2007 &amp;nbsp; &amp;nbsp; &amp;nbsp; 75.905 &amp;nbsp; &amp;nbsp; 80&lt;br /&gt;&amp;nbsp; &amp;nbsp; 3 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp;AUG2007 &amp;nbsp; &amp;nbsp; 18.852 &amp;nbsp; &amp;nbsp; 12&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;只要把 from=quarter 改成 from=week 即可。但是加權平均income的數據，是用插補法先將週四至下週二的數據進行插補，然後再做平均。作者提供另一種作法：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data two;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;set one;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;do dailydate = date-6 to date;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;output; &amp;nbsp;/* transform each weekly observation to 7 daily observations */&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;end;&lt;br /&gt;&amp;nbsp; &amp;nbsp;run;&lt;br /&gt;proc expand data=two out=three from=day to=month ;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; id dailydate;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; by id;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; convert income / observed=average;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;這個作法是先將原始的週資料用複製的方法將沒有數字的天數補齊，如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp;Obs &amp;nbsp; dailydate &amp;nbsp; &amp;nbsp;id &amp;nbsp; &amp;nbsp; income&lt;br /&gt;&amp;nbsp; &amp;nbsp; 1 &amp;nbsp; &amp;nbsp;20070524 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 11&lt;br /&gt;&amp;nbsp; &amp;nbsp; 2 &amp;nbsp; &amp;nbsp;20070525 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 11&lt;br /&gt;&amp;nbsp; &amp;nbsp; 3 &amp;nbsp; &amp;nbsp;20070526 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 11&lt;br /&gt;&amp;nbsp; &amp;nbsp; 4 &amp;nbsp; &amp;nbsp;20070527 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 11&lt;br /&gt;&amp;nbsp; &amp;nbsp; 5 &amp;nbsp; &amp;nbsp;20070528 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 11&lt;br /&gt;&amp;nbsp; &amp;nbsp; 6 &amp;nbsp; &amp;nbsp;20070529 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 11&lt;br /&gt;&amp;nbsp; &amp;nbsp; 7 &amp;nbsp; &amp;nbsp;20070530 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 11&lt;br /&gt;&amp;nbsp; &amp;nbsp; 8 &amp;nbsp; &amp;nbsp;20070531 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 30&lt;br /&gt;&amp;nbsp; &amp;nbsp; 9 &amp;nbsp; &amp;nbsp;20070601 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 30&lt;br /&gt;&amp;nbsp; &amp;nbsp;10 &amp;nbsp; &amp;nbsp;20070602 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 30&lt;br /&gt;&amp;nbsp; &amp;nbsp;11 &amp;nbsp; &amp;nbsp;20070603 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 30&lt;br /&gt;&amp;nbsp; &amp;nbsp;12 &amp;nbsp; &amp;nbsp;20070604 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 30&lt;br /&gt;&amp;nbsp; &amp;nbsp;13 &amp;nbsp; &amp;nbsp;20070605 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 30&lt;br /&gt;&amp;nbsp; &amp;nbsp;14 &amp;nbsp; &amp;nbsp;20070606 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 30&lt;br /&gt;&amp;nbsp; &amp;nbsp;15 &amp;nbsp; &amp;nbsp;20070607 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 50&lt;br /&gt;&amp;nbsp; &amp;nbsp;16 &amp;nbsp; &amp;nbsp;20070608 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 50&lt;br /&gt;&amp;nbsp; &amp;nbsp;17 &amp;nbsp; &amp;nbsp;20070609 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 50&lt;br /&gt;&amp;nbsp; &amp;nbsp;18 &amp;nbsp; &amp;nbsp;20070610 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 50&lt;br /&gt;&amp;nbsp; &amp;nbsp;19 &amp;nbsp; &amp;nbsp;20070611 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 50&lt;br /&gt;&amp;nbsp; &amp;nbsp;20 &amp;nbsp; &amp;nbsp;20070612 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 50&lt;br /&gt;&amp;nbsp; &amp;nbsp;21 &amp;nbsp; &amp;nbsp;20070613 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 50&lt;br /&gt;&amp;nbsp; &amp;nbsp;22 &amp;nbsp; &amp;nbsp;20070614 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 70&lt;br /&gt;&amp;nbsp; &amp;nbsp;23 &amp;nbsp; &amp;nbsp;20070615 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 70&lt;br /&gt;&amp;nbsp; &amp;nbsp;24 &amp;nbsp; &amp;nbsp;20070616 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 70&lt;br /&gt;&amp;nbsp; &amp;nbsp;25 &amp;nbsp; &amp;nbsp;20070617 &amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp; &amp;nbsp; &amp;nbsp; 70&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;然後再把這個日資料換算成月資料即可。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Contact information&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Bruce Gilsen&lt;br /&gt;Federal Reserve Board&lt;br /&gt;Mail Stop 157&lt;br /&gt;Washington, DC&amp;nbsp;20551&lt;br /&gt;e-mail: bruce.gilsen@frb.gov&lt;br /&gt;phone: 202-452-2494.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-1616952410225347325?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/1616952410225347325/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=1616952410225347325&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/1616952410225347325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/1616952410225347325'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/06/expanding-proc-expand.html' title='Expanding PROC EXPAND'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-2086101820374400309</id><published>2011-06-18T10:49:00.001-04:00</published><updated>2011-06-18T10:49:00.763-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='報表輸出'/><title type='text'>MORE CUSTOMIZATION?: CREATING SYMBOLS IN RTF FILES USING ODS</title><content type='html'>原文載點：&lt;a href="http://www.lexjansen.com/pharmasug/2004/technicaltechniques/tt12.pdf"&gt;http://www.lexjansen.com/pharmasug/2004/technicaltechniques/tt12.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;有時候想要在 SAS 輸出報表裡面寫一些標題或註解，需要加上一些科學符號、希臘字母、甚至是邏輯運算子等特殊符號時，得使用特別的方法顯示出來。這一篇 2004 年的 PHARMASUG 技術文件可供參考。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;首先必須先去查這些特殊符號的 Unicode decimal number，因為 SAS 必須藉由這些代碼才能對應到特殊符號。查詢的網址如下：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.alanwood.net/unicode/index.html"&gt;http://www.alanwood.net/unicode/index.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.unicode.org/"&gt;http://www.unicode.org/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;以"alpha"這個希臘字母當做範例，程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ods escapechar="^";&lt;br /&gt;%let symbol_alpha=%bquote(^R/RTF"\u&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;945&lt;/span&gt;&lt;/b&gt;\") ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;第一行用ods escapechar來定義一個轉義字母，在此設定為"^"。SAS 看到轉義字母才知道後面的 Unicode 代碼是要轉成什麼特殊符號。接著用 %bquote 函式來把特殊符號做出來。把上面的程式複製到 SAS，再把紅色的 Unicode 換成你想要的 Unicode 即可。&lt;br /&gt;&lt;br /&gt;一些常用的特殊符號的 Unicode 代碼：&lt;br /&gt;希臘字母：&lt;a href="http://www.alanwood.net/unicode/greek.html"&gt;http://www.alanwood.net/unicode/greek.html&lt;/a&gt;&lt;br /&gt;數學符號運算子：&lt;a href="http://www.alanwood.net/unicode/mathematical_operators.html"&gt;http://www.alanwood.net/unicode/mathematical_operators.html&lt;/a&gt;&lt;br /&gt;箭頭：&lt;a href="http://www.alanwood.net/unicode/arrows.html"&gt;http://www.alanwood.net/unicode/arrows.html&lt;/a&gt;&lt;br /&gt;羅馬數字和分數：&lt;a href="http://www.alanwood.net/unicode/number_forms.html"&gt;http://www.alanwood.net/unicode/number_forms.html&lt;/a&gt;&lt;br /&gt;上標與下標：&lt;a href="http://www.alanwood.net/unicode/superscripts_and_subscripts.html"&gt;http://www.alanwood.net/unicode/superscripts_and_subscripts.html&lt;/a&gt;&lt;br /&gt;其他：&lt;a href="http://www.alanwood.net/unicode/letterlike_symbols.html"&gt;http://www.alanwood.net/unicode/letterlike_symbols.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;原文提供一個範例。假設要製作下列表格的註解：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-ww361cGKeNw/TfUmAD1S6sI/AAAAAAAAF6M/0jAz1SCVBbo/s1600/tt12.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="363" src="http://3.bp.blogspot.com/-ww361cGKeNw/TfUmAD1S6sI/AAAAAAAAF6M/0jAz1SCVBbo/s640/tt12.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;footer f1 ;&lt;br /&gt;define f1 ;&lt;br /&gt;text&lt;br /&gt;&amp;nbsp; &amp;nbsp;" +Above Normal Range" "^1n"&lt;br /&gt;&amp;nbsp; &amp;nbsp;"-Below Normal Range" "^1n"&lt;br /&gt;&amp;nbsp; &amp;nbsp;"A reading &amp;amp;symbol_ge 40 for SGPT/ALT is considered Above Normal" &amp;nbsp;"^1n"&lt;br /&gt;&amp;nbsp; &amp;nbsp;"A reading &amp;amp;symbol_le 30 for SGPT/ALT is considered Below Normal" &amp;nbsp; "^1n" &lt;br /&gt;&amp;nbsp; &amp;nbsp;"An example of &amp;amp;symbol_alpha." "^2n "&lt;br /&gt;&amp;nbsp; &amp;nbsp;"&amp;amp;font9.Output:" " &amp;amp;tab.&amp;amp;outdir.\&amp;amp;pgmonly..rtf" "^1n"&lt;br /&gt;&amp;nbsp; &amp;nbsp; "Source:&amp;amp;tab.&amp;amp;source." &amp;nbsp;;&lt;br /&gt;&amp;nbsp; &amp;nbsp;style={font_face=Arial font_size=2.5 font_weight=medium background=white} ;&lt;br /&gt;&amp;nbsp; &amp;nbsp;just=left ;&lt;br /&gt;end ; &lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;如果覺得這樣太麻煩，就送去Word編輯吧！&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Richard Rowell&lt;br /&gt;Connetics Corporation&lt;br /&gt;3290 West Bayshore Road&lt;br /&gt;Work: (650) 843-2876&lt;br /&gt;rrowell@connetics.com&lt;br /&gt;Jim Lenihan&lt;br /&gt;15 Moonlight Ct&lt;br /&gt;South San Francisco, CA 94080&lt;br /&gt;Work: (650) 742-0131&lt;br /&gt;jameslenihan@sbcglobal.net&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-2086101820374400309?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/2086101820374400309/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=2086101820374400309&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/2086101820374400309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/2086101820374400309'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/06/more-customization-creating-symbols-in.html' title='MORE CUSTOMIZATION?: CREATING SYMBOLS IN RTF FILES USING ODS'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-ww361cGKeNw/TfUmAD1S6sI/AAAAAAAAF6M/0jAz1SCVBbo/s72-c/tt12.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-5994434975514089344</id><published>2011-06-04T00:53:00.000-04:00</published><updated>2011-06-04T00:53:00.422-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程序語法'/><category scheme='http://www.blogger.com/atom/ns#' term='繪圖技巧'/><title type='text'>Creating Forest Plots from Pre-computed Data using PROC SGPLOT and Graph Template Language</title><content type='html'>原文載點：http://support.sas.com/resources/papers/proceedings10/195-2010.pdf&lt;br /&gt;&lt;br /&gt;Forest plot 是研究環境流行病學的人經常會用到的一種圖表，主要是可以將許多變數或樣本的參數估計值以及信賴區間畫成一條一條的橫線，以供其他人易於判讀相對大小以及有無顯著。我在自己的博士論文裡面也放了相當多這種圖型，但之前我都是自己用 R 寫程式畫的，過程挺複雜的，沒想到 SAS 裡面有現成的語法可以畫這種圖。&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;假設用 PROC LOGISTIC 來估計一個模型，如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ods output "Odds Ratios"=orci;&amp;nbsp;&lt;br /&gt;proc logistic data=uis descending;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;model dfree=age beck ivhx ndrugtx race treat site ;&amp;nbsp;&lt;br /&gt;run;&amp;nbsp;&lt;/code&gt;&lt;/pre&gt;估計好後把所有參數的 Odds Ratio 另存成 orci 這個新資料集，內容如下所示：&lt;br /&gt;&lt;a href="http://farm6.static.flickr.com/5026/5691756612_b4f105fc98.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="190" src="http://farm6.static.flickr.com/5026/5691756612_b4f105fc98.jpg" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;然後用 PROC SGPLOT 直接來畫 Forest plot：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;title "SGPLOT: Forest Plot"; &lt;br /&gt;proc sgplot data=orci; &lt;br /&gt;  scatter x=oddsratioest y=effect / xerrorlower=lowercl                &lt;br /&gt;                                    xerrorupper=uppercl  &lt;br /&gt;                                    markerattrs=or(symbol=DiamondFilled size=8); &lt;br /&gt;  refline 1 / axis=x;   &lt;br /&gt;  xaxis label="OR and 95% CI " min=0; &lt;br /&gt;  yaxis label="Covariates"; &lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;陽春一點的圖型只需要四個語法：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;scatter：後面的 x= 放估計參數變數名稱，y= 放參數本身變數的名稱。後面三個選項分別是：&lt;/li&gt;&lt;ul&gt;&lt;li&gt;xerrorlower = 信賴區間下限&lt;/li&gt;&lt;li&gt;xerrorupper = 信賴區間上限&lt;/li&gt;&lt;li&gt;markerattrs = 設定估計量的符號形式及大小&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;refine：設定在哪一個軸畫基準線&lt;/li&gt;&lt;li&gt;xaxis：設定 x 軸&lt;/li&gt;&lt;li&gt;yaxis：設定 y 軸&lt;/li&gt;&lt;/ol&gt;做出來的圖型如下所示：&lt;br /&gt;&lt;a href="http://farm6.static.flickr.com/5265/5691781140_ae315412a1_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm6.static.flickr.com/5265/5691781140_ae315412a1_z.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;原文內還有其他的教學，主要著重於如何調整圖型品質，但根據自己的經驗是上述這種圖就差不多可以拿去放在 paper 裡面了，所以就不多做介紹。有興趣的人可以再去參閱原文後段的進階內容。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&lt;/b&gt;&lt;br /&gt;Zoran Bursac, PhD, MPH&lt;br /&gt;Associate Professor&lt;br /&gt;Biostatistics&lt;br /&gt;Fay W. Boozman College of Public Health&lt;br /&gt;University of Arkansas for Medical Sciences&lt;br /&gt;4301 W. Markham, Slot 781&lt;br /&gt;Little Rock, AR 72205&lt;br /&gt;Work Phone: &lt;span class="gc-cs-link" id="gc-number-6" title="Call with Google Voice"&gt;(501) 526-6723&lt;/span&gt;&lt;br /&gt;Fax: &lt;span class="gc-cs-link" id="gc-number-7" title="Call with Google Voice"&gt;(501) 526-6729&lt;/span&gt;&lt;br /&gt;E-mail: zbursac@uams.edu&lt;br /&gt;Web: www.uams.edu/biostat/bursac/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-5994434975514089344?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/5994434975514089344/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=5994434975514089344&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/5994434975514089344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/5994434975514089344'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/06/creating-forest-plots-from-pre-computed.html' title='Creating Forest Plots from Pre-computed Data using PROC SGPLOT and Graph Template Language'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5026/5691756612_b4f105fc98_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-5591453922128755407</id><published>2011-05-28T06:00:00.001-04:00</published><updated>2011-10-11T12:53:25.122-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='資料整理'/><title type='text'>Automagically Copying and Pasting Variable Names</title><content type='html'>原文載點：&lt;a href="http://support.sas.com/resources/papers/proceedings10/046-2010.pdf"&gt;http://support.sas.com/resources/papers/proceedings10/046-2010.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;如果使用者從第三處拿到一筆資料，想要建立coding book或目錄，或者需要寫新的程式必且在keep或drop指令輸入大量變數名稱，因而需要大量複製和貼上變數名稱的話，有什麼比較好的方法呢？Arthur S. Tabachneck 等人提供了一個方法讓使用者能夠一次複製且貼上全部的變數名稱。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;首先，執行下面這段程式碼：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;FILENAME _cb CLIPBRD;&lt;br /&gt;DATA _NULL_;&lt;br /&gt;&amp;nbsp;&amp;nbsp; WINDOW DSN rows=8 columns=80&lt;br /&gt;&amp;nbsp;&amp;nbsp; irow=1 &amp;nbsp;icolumn=2 color=black&lt;br /&gt;&amp;nbsp;&amp;nbsp; #2 &amp;nbsp;@3 &amp;nbsp;'Enter 1 or 2 level data set name: ' &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;color=gray dsn $41. &amp;nbsp;required=yes&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;attr=underline &amp;nbsp; &amp;nbsp; &amp;nbsp; color=yellow;&lt;br /&gt;&amp;nbsp;&amp;nbsp; DISPLAY DSN blank;&lt;br /&gt;&amp;nbsp;&amp;nbsp; FILE _cb;&lt;br /&gt;&amp;nbsp;&amp;nbsp; length name $32;&lt;br /&gt;&amp;nbsp;&amp;nbsp; do dsid = open(dsn,'I') while(dsid ne 0);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; do i = 1 to attrn(dsid,'NVARS');&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; name = varname(dsid,i);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; put name @;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; end;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; dsid = close(dsid);&lt;br /&gt;&amp;nbsp;&amp;nbsp; end;&lt;br /&gt;RUN;&lt;br /&gt;FILENAME _cb CLEAR;&lt;/code&gt;&lt;/pre&gt;切記裡面一個指令都不用改，執行完後 SAS 裡面會跳出一個黑色的視窗，如下所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm6.static.flickr.com/5150/5691085923_efa14099a8_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm6.static.flickr.com/5150/5691085923_efa14099a8_z.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;裡面有一個空行，是要你輸入資料所在的 library 名稱還有資料本身名稱，如：「Orz.wahaha」，亦即表示你要複製 Orz library 裡面的 wahaha 資料內的所有變數名稱。如果沒有指定 library，則程式會自行去 Work library 裡面搜尋。輸入好後按 Enter，&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;要進行最後"關掉DSN視窗"的動作，這時程式才會將你指定的資料集裡面的所有變數名稱複製好&lt;/span&gt;&lt;/b&gt;，然後你就可以用 Ctrl + v 的熱鍵把複製好的變數名稱任意地貼到任何地方或任何軟體裡面。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&amp;nbsp;&lt;/b&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. &amp;nbsp;Contact the authors at:&lt;br /&gt;Arthur Tabachneck, Ph.D. Randy Herbison,&lt;br /&gt;Director, Data Management Senior Systems Analyst&lt;br /&gt;Insurance Bureau of Canada Westat&lt;br /&gt;2235 Sheppard Ave. East 1650 Research Boulevard&lt;br /&gt;Toronto, ON L3T 5K9 Canada Rockville, MD 20850&lt;br /&gt;E-mail: atabachneck@ibc.ca E-mail: RandyHerbison@westat.com&lt;br /&gt;John King Andrew Clapson&lt;br /&gt;Ouachita Clinical Data Services, Inc. Ottawa, ON Canada&lt;br /&gt;Mount Ida, AR E-mail: andy_clapson@hotmail.com&lt;br /&gt;ouachitaclinicaldataservices@gmail.com &lt;br /&gt;Roger DeAngelis Tom Abernathy&lt;br /&gt;CompuCraft Inc Pfizer, Inc.&lt;br /&gt;1770 Via Petirrojo Apt A 235 E. 42nd Street&lt;br /&gt;Newbury Park CA 91320 New York, NY 1001&lt;br /&gt;E-mail: xlr82sas@aol.com E-mail: tom.abernathy@pfizer.com&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-5591453922128755407?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/5591453922128755407/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=5591453922128755407&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/5591453922128755407'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/5591453922128755407'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/05/automagically-copying-and-pasting.html' title='Automagically Copying and Pasting Variable Names'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5150/5691085923_efa14099a8_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-7162730863602825583</id><published>2011-05-21T20:57:00.003-04:00</published><updated>2011-05-21T20:57:51.457-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='其他'/><title type='text'>Top Ten SAS® Sites for Programmers: A Review</title><content type='html'>原文載點:&amp;nbsp;&lt;a href="http://support.sas.com/resources/papers/proceedings11/055-2011.pdf"&gt;http://support.sas.com/resources/papers/proceedings11/055-2011.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;一位相當資深的 SAS 程式設計師在 SAS Global Forum 2011 發表了一篇文章推薦了十個值得瀏覽的 SAS 技術網站。這十個網站是根據三百位SAS使用者的抽樣調查而來，並非原作者主觀意見，所以算是滿客觀的一個結論。雖然不是說每個我都很喜歡，但在此分享給大家。&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://support.sas.com/"&gt;Support.SAS.com&lt;/a&gt;&lt;br /&gt;SAS 客服網站。SAS 的線上手冊也在裡面。我個人也推薦這個網站是因為除了程式上的技術問題外，使用者有時候也會遇到軟體上的問題，通常這些問題都可以透過 SAS 客服來解決。我以前經常寫信去請教 SAS 客服解決一些怪異的 error message 或記憶體問題，而對方總是相當快速地給我回覆。當然，前提是你用的 SAS 必須是正版的&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://lexjansen.com/"&gt;LexJansen.com&lt;/a&gt;&lt;br /&gt;相當老牌的一個 SAS 教學網站，裡面集合了所有 SAS 官方或非官方的論壇文章，本站側欄的 Good Sites 就是參考這個網站而設計的。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://sascommunity.org/"&gt;sasCommunity.org&lt;/a&gt;&lt;br /&gt;類似 SAS 版的維基百科，不過我沒用過所以不熟。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.listserv.uga.edu/archives/sas-l.html"&gt;SAS-L archive&lt;/a&gt;&lt;br /&gt;也是相當老牌的 SAS 討論群組，可以在上面發問或回答別人的問題。缺點是介面老舊，彷彿像 90 年代的風格，也不是很人性化。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://sas.com/"&gt;SAS.com&lt;/a&gt;&lt;br /&gt;SAS 官方網站，裡面有相當多 SAS 官方提供的巨集程式可以使用。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://nesug.org/"&gt;NESUG.org&lt;/a&gt;&lt;br /&gt;北美東 SAS 使用者論壇，我投過一次 poster 被接受但因為生病所以就放棄沒參加了。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blogs.sas.com/"&gt;blogs.SAS.com&lt;/a&gt;&lt;br /&gt;一堆 SAS 大頭在裡面寫的部落格，個人是覺得沒有甚麼用處。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://sesug.org/"&gt;SESUG.org&lt;/a&gt;&lt;br /&gt;南美東 SAS 使用者論壇。我曾經發表過一篇技術文件在那邊。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://support.sas.com/events/sasglobalforum/previous/online.html"&gt;SAS Global Forum&lt;/a&gt;&lt;br /&gt;本站參考文獻主要來源，&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;強力推薦&lt;/span&gt;&lt;/b&gt;!!!&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://google.com/"&gt;Google.com&lt;/a&gt;&lt;br /&gt;估狗大神，無須多言。&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Comments and suggestions can be sent to:&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Charles Edwin Shipp&lt;/div&gt;&lt;div&gt;JMP 2 Consulting, Inc.&lt;/div&gt;&lt;div&gt;E-mail: CharlieShipp@aol.com&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Kirk Paul Lafler&lt;/div&gt;&lt;div&gt;Software Intelligence Corporation&lt;/div&gt;&lt;div&gt;E-mail: KirkLafler@cs.com&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-7162730863602825583?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/7162730863602825583/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=7162730863602825583&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/7162730863602825583'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/7162730863602825583'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/05/top-ten-sas-sites-for-programmers_21.html' title='Top Ten SAS® Sites for Programmers: A Review'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-3555906576014195085</id><published>2011-05-21T01:26:00.001-04:00</published><updated>2011-05-21T01:26:00.994-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程序語法'/><title type='text'>Practicalities of Using ESTIMATE and CONTRAST Statements</title><content type='html'>原文載點：http://support.sas.com/resources/papers/proceedings10/269-2010.pdf&lt;br /&gt;&lt;br /&gt;在 PROC GLM 和 PROC MIXED 裡面，最令一般 SAS 使用者感到頭痛的不是模型的檢定而是事後分析(post hoc test)。這牽涉到 contrast 和 estimate 兩個語法。在我接觸過所有非統計科班出身但需要用到線性模型以及事後分析的人，沒有人不對這兩個語法感到聞風喪膽。多年人我曾經試圖用各種方法來教人如何使用這兩種語法，但效果都不怎麼顯著。簡單來講，Contrast 和 estimate 無論是在 PROC GLM 還是 PROC MIXED 裡面，功能完全一樣，語法內的選項也一樣，而兩者之間唯一的差別是，contrast 可以只能算出 p-value，而 estimate 可以把指定的點估計量及其 p-value 一次輸出。David J. Pasta 在 SAS Global Forum 2010 發表了一篇技術文件將這兩種語法做一個詳盡的介紹，堪稱一大貢獻。在本文中，我會介紹幾個比較實用的範例。&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;原文作者套用一個醫學資料並詳述其背景，但為了簡化初學者的時間，我將會以程式來主。第一個範例資料只有三個變數，分別是作為應變數的離散型變數 sex (兩層) 和 race (五層)，而依變數則為一個連續型變數 y1。有了對資料的基本概念，首先來看一個最簡單的例子：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc glm data=anal;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;class sex;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;model y1 = sex / solution;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;lsmeans sex / stderr tdiff e;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;這個例子只單獨分析 sex 對 y1 的影響，而 lsmeans 是用來算出每個性別對 y1 的最小平方估計量。後面的 tdiff 則是去求兩個性別的差異。這段程式會跟用 PROC TTEST 做出來的結果一模一樣。如果不用 lsmeans 而改用 estimate 語法，則可以這樣寫：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc glm data=anal;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;class sex;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;model y1 = sex / solution;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'male' intercept 1 sex 0 1;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female' intercept 1 sex 1 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female-male' sex 1 -1;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;頭兩個 estimate 語法可算出不同性別在 y1 上的平均值，後面接著 intercept 和 sex 是為了要告訴 SAS 估計值是從哪些變數來的。一般使用者最常忘記的就是把 intercept 1 加上去，因為除非在 model 的選項上面加上 noint 抑制掉截距項的計算，否則一切用 estimate 求算的點估計量都要加上 intercept 1。不過你也不用擔心不加會怎麼樣，因為 log 視窗裡面自然會出現紅色的錯誤訊號提醒你加上。而 sex 後面跟著「0 &amp;nbsp;1」和「1 &amp;nbsp;0」則是要準確地將要計算的性別定位出來，當然你也要對自己如何將 sex 編碼要非常了解，而不是亂安插一通。在本例中，女性的編碼順位是排在男生前面（若真的不清楚編碼順位，看一下輸出報表一開始的 Class Level Information 裡面就會清清楚楚地把所有類別變數的編碼順位列出來），所以當 sex 後面寫「1 &amp;nbsp;0」時，自然是去算女生的值，反之則是算男生的值。&lt;br /&gt;&lt;br /&gt;而當要比較女生和男生的差異時，則有兩點要注意。一是 intercept 可以不用寫了，因為兩兩相減的情況下，截距項自然就被減掉了。二是 sex 後面要改成「1 &amp;nbsp;-1」，很明顯地這就是指用女生的估計值去減男生的估計值。如果要算男生的估計值減女生的估計值，把「1 &amp;nbsp;-1」改成「-1 &amp;nbsp;1」即可。偷懶的方法是不改，但把 output 輸出的估計值變號即可，至於 p-value 是不會改變的。&lt;br /&gt;&lt;br /&gt;當考慮兩個應變數時，程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc glm data=anal;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;class race sex;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;model y1 = race sex / solution e;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;lsmeans race sex / stderr tdiff e;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;lsmeans race sex / stderr tdiff e om;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;第一個 lsmeans 語法會一次把兩個變數的最小平方估計量通通算出來，並且會把成對比較的結果也列印出來。第二個 lsmeans 語法和第一個的不同是後面多了 om 這個選項。它的功用是去計算不同類別的權重，並在計算平均數的時候考量到權重大小。簡單來講就是去計算加權的估計量。以 sex 為例，在沒有考量加權的情況下，每個 race 的權重都會是 0.2。而考量權重的話，每個 race 的權重則等於每個種族在全部樣本裡面所佔的比例。&lt;br /&gt;&lt;br /&gt;若用 estimate 語法則程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc glm data=anal;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;class race sex;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;model y1 = race sex / solution e;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'male' intercept 1 sex 0 1;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female' intercept 1 sex 1 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female-male' sex 1 -1;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;寫法跟第一個程式範例一樣，但我會習慣加上「race 0.2 0.2 0.2 0.2 0.2」，只是說不加的話也沒關係，因為程式會自動用等同的權重去平均。寫到這邊只有兩點要強調：一是類別變數有幾層，estimate 語法內變數後面要跟的數字就有幾個。有人習慣將 1 後面可能還會出現的 0 都省略掉，但我強烈建議補上，因為多寫幾個 0 不會花太多時間，而且有可好處是可以把所有的 estimate 語法排列的工工整整，要 debug 也比較方便。二是腦筋一定要清楚知道變數的編碼順位，在寫之前最好再去對一下 Class Level Information 表格內的訊息。&lt;br /&gt;&lt;br /&gt;當考慮交互作用項時，estimate 語法就沒有辦法簡化了：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc glm data=anal;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;class sex race;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;model y1 = race sex race*sex / solution;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'male' &amp;nbsp; intercept 1 sex 0 1 race .2 .2 .2 .2 .2 &amp;nbsp;race*sex 0 0 0 0 0 &amp;nbsp;.2 .2 .2 .2 .2;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female' intercept 1 sex 1 0 race .2 .2 .2 .2 .2 &amp;nbsp;race*sex .2 .2 .2 .2 .2 &amp;nbsp;0 0 0 0 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female-male' sex 1 -1 race*sex .2 .2 .2 .2 .2 &amp;nbsp;-.2 -.2 -.2 -.2 -.2;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;在 sex 的點估計中，除了「race 0.2 0.2 0.2 0.2 0.2」一定要加上外，交互作用項 race*sex 後面要寫的數字向量變將整個程式複雜程度提昇了許多。由於 race 有五層，sex 有兩層，所以交互作用項就會是 5X2 = 10 層。因此開始寫這段數字向量時，先要知道到底該寫幾個數字進去，這是第一個要注意的事情。其次，將 sex 的向量和 race 的向量用&amp;nbsp;Kronecker&amp;nbsp;product 的方式去算。如果不清楚&amp;nbsp;Kronecker product，我在這邊提供一個小程式碼：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc iml;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;a = {0 1};&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;b = {0.2 0.2 0.2 0.2 0.2};&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;ab = a@b;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;print ab;&lt;br /&gt;quit;&lt;/code&gt;&lt;/pre&gt;自行替換 a 和 b 裡面的數字就可以算出兩個變數的交互作用項的向量。然後就直接從 output 視窗裡面複製貼上即可。在成對比較上面，交互作用的數字向量寫法也是一樣可以用這個小程式去算，只要把{0 1}改成{1 -1}即可。但在寫程式時，「race 0.2 0.2 0.2 0.2 0.2」因為在相減的過程中被扣掉了，所以不用寫上去。一個比較白痴的方法是把第一個 estimate 和 第二個 estimate 排好，然後下面減上面，自然就得到最後一個的數字向量。只是當你有大量變數要比較時，這種作法就有點慢了。&lt;br /&gt;&lt;br /&gt;可是當考慮權重時，程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc glm data=anal;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;class sex race;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;model y1 = race sex race*sex / solution e;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'male' intercept 1 &amp;nbsp;sex 0 1 &amp;nbsp;race &amp;nbsp;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;.104 .142 .128 .047 .579&lt;/span&gt;&lt;/b&gt;&amp;nbsp;race*sex 0 0 0 0 0 &amp;nbsp;.104 .142 .128 .047 .579;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female' intercept 1 &amp;nbsp;sex 1 0 race &amp;nbsp;&lt;span class="Apple-style-span" style="color: red;"&gt;&lt;b&gt;.104 .142 .128 .047 .579&lt;/b&gt;&lt;/span&gt;&amp;nbsp;race*sex .104 .142 .128 .047 .579 &amp;nbsp;0 0 0 0 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female-male' sex 1 -1 race*sex .104 .142 .128 .047 .579&amp;nbsp;-.104 -.142 -.128 -.047 -.579;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female-male (off)' sex 1 -1 race*sex &lt;b&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;.105 .142 .128 .047 .579&amp;nbsp;-.105 -.142 -.128 -.047 -.579&lt;/span&gt;&lt;/b&gt;;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;紅色部分就是 race 在五個不同總族下的權重，這可以用 PROC FREQ 額外算出來。只要這個部分解決，後面交互作用項就簡單了，因為可以直接套用上面我提供的小程式，之後便是一連串的剪貼。兩兩比較的技巧也如同之前所述。最後一個標記為 'female-male (off)' 的程式，只是要提醒，在計算權重時，我們可能會使用到進位的權重，但進位後可能會造成無法估計的結果。本例中，由於進位的關係，race*sex 後面的數字總和雖然還是零，但是 race 權重的總和變成 1.001 而不是 1.000 了。因此你就會看到一段紅色錯誤訊息出現在 log 視窗告訴你這個事後比較無法估計。解決的方法沒有特別，就是手動去微調裡面的數據，東加一點西減一點，調到總合是 1 即可。&lt;br /&gt;有時候事後比較的目的是要看某離散型的變數是否有線性趨勢，則程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc glm data=anal;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;class sex educat;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;model y1 = sex educat / solution;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;lsmeans sex educat / stderr e;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;lsmeans sex educat / stderr e om;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'educat linear (no divisor)' educat -2 -1 0 1 2;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'educat linear (divisor=10)' educat -2 -1 0 1 2 / divisor=10;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'educat linear (divisor=40)' educat -4 -2 0 2 4 / divisor=40;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'educat by year (not centered)' educat 8 12 14 16 20;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'educat by year (centered)' educat -6 -2 0 2 6 / divisor=80;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;此程式把 race 換成 educat，但一樣是五層。線性趨勢的事後檢定所使用的數字向量為「-2 -1 0 1 2」，這個比例大致上是不會改變的，當然不同數目的層次有不同的寫法，請自行孤狗。有時會有比較特殊的寫法，就比方'educat by year (not centered)'的寫法，不過情況比較少。大部分還是會寫成像'educat by year (centered)'所示，也就是讓數字向量內的數字是對秤的，而不是單調遞升或遞減的。至於 divisor 的用法，在此例沒有特殊意義，只是當做是分母把要用來估計的數字向量一次全部除掉，換句話說，以第二個'educat linear (divisor=10)'為例，你也可以寫成&lt;br /&gt;&lt;pre&gt;&lt;code&gt;estimate 'educat linear (divisor=10)' educat -0.2 -0.1 0 0.1 0.2;&lt;/code&gt;&lt;/pre&gt;但是 divisor 的真正威力，是在下面這個範例：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc glm data=anal;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;class sex race;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;model y1 = race sex race*sex / solution e;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-style-span" style="color: #e69138;"&gt;estimate 'male (333)' intercept 1 &amp;nbsp;sex 0 1 &amp;nbsp;race &amp;nbsp;.333 .333 .333&amp;nbsp;race*sex 0 0 0 &amp;nbsp;.333 .333 .333;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #e69138;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female (333)' intercept 1 &amp;nbsp;sex 1 0 race &amp;nbsp;.333 .333 .333&amp;nbsp;race*sex &amp;nbsp;.333 .333 .333 &amp;nbsp;0 0 0;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #e69138;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female-male (333)' sex 1 -1 race*sex &amp;nbsp;.333 .333 .333 &amp;nbsp;-.333 -.333 -.333;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'male (334)' intercept 1 &amp;nbsp;sex 0 1 &amp;nbsp;race &amp;nbsp;.333 .333 .334 race*sex 0 0 0 &amp;nbsp;.333 .333 .334;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female (334)' intercept 1 &amp;nbsp;sex 1 0 race &amp;nbsp;.333 .333 .334&amp;nbsp;race*sex &amp;nbsp;.333 .333 .334 &amp;nbsp;0 0 0;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female-male (334)' sex 1 -1 race*sex &amp;nbsp;.333 .333 .334 &amp;nbsp;-.333 -.333 -.334;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'male (d)' intercept 3 &amp;nbsp;sex 0 3 &amp;nbsp;race &amp;nbsp;1 1 1 &amp;nbsp;race*sex 0 0 0 &amp;nbsp;1 1 1 / divisor=3;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female (d)' intercept 3 &amp;nbsp;sex 3 0 race &amp;nbsp;1 1 1 &amp;nbsp;race*sex 1 1 1 &amp;nbsp;0 0 0 / divisor=3;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female-male (d)' sex 3 -3 race*sex 1 1 1 &amp;nbsp; -1 -1 -1 / divisor=3;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-style-span" style="color: #351c75;"&gt;estimate 'male (o)' intercept 849 &amp;nbsp;sex 0 849 &amp;nbsp;race &amp;nbsp;142 128 579&amp;nbsp;race*sex 0 0 0 &amp;nbsp;142 128 579 / divisor=849;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #351c75;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female (o)' intercept 849 &amp;nbsp;sex 849 0 race &amp;nbsp;142 128 579&amp;nbsp;race*sex 142 128 579 &amp;nbsp;0 0 0 / divisor=849;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #351c75;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;estimate 'female-male (o)' sex 849 -849 race*sex 142 128 579 -142 -128 -579 / divisor=849;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;此例中，race 不再是五層，而是三層！所以當要計算 sex 內男女分別的點估計量，SAS 裡面是不允許寫分數而是得直接寫小數上去，造成 race 後面的數字向量不能是{1/3 &amp;nbsp;1/3 &amp;nbsp;1/3}而是{0.333 &amp;nbsp;0.333 &amp;nbsp;0.333}。這種情況使得三個數字的總和變成 0.999 而不是 1.000，然後就會看到 SAS 的 log 視窗給你錯誤的訊息了。有一種解決方法是改成{0.333 &amp;nbsp;0.333 &amp;nbsp;0.334}，但一旦層數變多了，如七層、九層、十一層、二十一層....，則不但整條 estimate 又臭又長，每次都要去微調裡面的數字也很麻煩，所以此時就要靠 divisor 這個選項幫我們一次除盡所有數。首先，先把原本每個變數後面的數字都乘上 3，接著在最後面加上 / divisor = 3 即可。如果考量到 race 的權重，請回憶國小國中學過的最小公倍數。你可能會問，一對小數點怎麼去求最小公倍數呢？在此額外提供一個 SAS 小程式方便你的計算：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data _null_;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;x = lcm(a1,a2,....,aN);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;put x;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;把你算出來的權重全部丟到 lcm function 裡面，這個函數顧名思義就是最小公倍數 least common multiple 的縮寫，馬上就可以算出 divisor 該填什麼數字進去了。&lt;br /&gt;&lt;br /&gt;以上就是很基本但卻很實用的 estimate 寫法。contrast 的用法一模一樣，所以沒有多做介紹。原文後面還有一些更進階的語法，但我個人的經驗是極少數的情況會使用到，因此大家熟練以上的程式就夠了。不過有時候離散變數內的層數很多，在建立 estimate 語法的時候，後面會跟著一長串的數字向量，非常驚人（恐怖）。原文作者建議將一些會一直重複用到的數字向量用 %let 先定義好，等到要用的時候再呼叫即可，比方說：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%let S_1 &amp;nbsp; &amp;nbsp;= 1 0 0 0 0 0 0 0 0 0;&lt;br /&gt;%let S_2 &amp;nbsp; &amp;nbsp;= 0 1 0 0 0 0 0 0 0 0;&lt;br /&gt;%let S_3 &amp;nbsp; &amp;nbsp;= 0 0 1 0 0 0 0 0 0 0;&lt;br /&gt;%let S_4 &amp;nbsp; &amp;nbsp;= 0 0 0 1 0 0 0 0 0 0;&lt;br /&gt;%let S_5 &amp;nbsp; &amp;nbsp;= 0 0 0 0 1 0 0 0 0 0;&lt;br /&gt;%let S_6 &amp;nbsp; &amp;nbsp;= 0 0 0 0 0 1 0 0 0 0;&lt;br /&gt;%let S_7 &amp;nbsp; &amp;nbsp;= 0 0 0 0 0 0 1 0 0 0;&lt;br /&gt;%let S_8 &amp;nbsp; &amp;nbsp;= 0 0 0 0 0 0 0 1 0 0;&lt;br /&gt;%let S_9 &amp;nbsp; &amp;nbsp;= 0 0 0 0 0 0 0 0 1 0;&lt;br /&gt;%let S_10 &amp;nbsp; = 0 0 0 0 0 0 0 0 0 1;&lt;br /&gt;%let S_none = 0 0 0 0 0 0 0 0 0 0;&lt;br /&gt;%let P_U &amp;nbsp; &amp;nbsp;= .1 .1 .1 .1 .1 .1 .1 .1 .1 .1;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;%let P_O &amp;nbsp; &amp;nbsp;= 0.0666048524 0.0776077886 0.0888270746&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0.0955339206 0.1017462525 0.1059496214&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0.1124710246 0.1164580436 0.1168907433&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0.1179106784 ;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;*** Intercept at the end of the BEFORE and at the beginning of the AFTER ***;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate 'LS:1_Before' &amp;nbsp; intercept &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;amp;S_1.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile*tafter &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;amp;S_none.; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate 'LS:1_After' &amp;nbsp; &amp;nbsp;intercept &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;amp;S_1.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile*tafter &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;amp;S_1.; &amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate 'LS:2_Before' &amp;nbsp; intercept &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;amp;S_2.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile*tafter &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;amp;S_none.; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate 'LS:2_After' &amp;nbsp; &amp;nbsp;intercept &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;amp;S_2.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile*tafter &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;amp;S_2.; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp;. . . &lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate 'LS:10_Before' &amp;nbsp;intercept &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;amp;S_10. &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile*tafter &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;amp;S_none.; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate 'LS:10_After' &amp;nbsp; intercept &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;amp;S_10.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile*tafter &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;amp;S_10.; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate 'LS:Before_U' &amp;nbsp; intercept &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;amp;P_U.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile*tafter &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;amp;S_none.; &lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate 'LS:After_U' &amp;nbsp; &amp;nbsp;intercept &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;amp;P_U.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile*tafter &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;amp;P_U.; &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate 'LS:Before_O' &amp;nbsp; intercept &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;amp;P_O.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile*tafter &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;amp;S_none.; &amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate 'LS:After_O' &amp;nbsp; &amp;nbsp;intercept &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;amp;P_O.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; decile*tafter &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;amp;P_O.;&lt;/code&gt;&lt;/pre&gt;試想，如果不用 %let 去額外定義巨集變數，而把那些 0 和 1 或 -1 等數字全部填回到 estimate 後面，則整串程式碼絕對會讓人暈眩。因此，我強烈建議使用 %let 來定義好 estimate 後面該用到的數字向量。此外，當要考量權重時，雖然可以自行算好寫上，但當層數多的時候（如本例），一個個複製貼上也是很麻煩，所以原文作者提供了一段程式碼讓 SAS 自動幫你把把這些權重貼到巨集變數裡面。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sort data=temp01(keep=patid_age decile) out=temp02 nodupkey;&lt;br /&gt;&amp;nbsp;&amp;nbsp;by patid_age decile;&lt;br /&gt;run;&lt;br /&gt;data _null_;&lt;br /&gt;&amp;nbsp;&amp;nbsp;set temp02;&lt;br /&gt;&amp;nbsp;&amp;nbsp;by patid_age decile;&lt;br /&gt;&amp;nbsp;&amp;nbsp;if not(first.patid_age and last.patid_age) &lt;br /&gt;then error 'ERROR: decile varies within patid_age';&lt;br /&gt;run;&lt;br /&gt;ods listing close;&lt;br /&gt;ods output onewayfreqs = temp03(keep=decile frequency cumfrequency);&lt;br /&gt;proc freq data = temp02;&lt;br /&gt;&amp;nbsp;&amp;nbsp;tables decile;&lt;br /&gt;run;&lt;br /&gt;ods listing;&lt;br /&gt;data _null_;&lt;br /&gt;&amp;nbsp;&amp;nbsp;set temp03;&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symput('N_'||left(trim(put(decile,2.))),frequency);&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;data _null_;&lt;br /&gt;&amp;nbsp;&amp;nbsp;set temp03;&lt;br /&gt;&amp;nbsp;&amp;nbsp;if (decile eq 10) then call symput('Ntot',cumfrequency);&lt;br /&gt;run;&lt;br /&gt;data _null_;&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symput('P_1', &amp;amp;N_1. / &amp;amp;Ntot.));&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symput('P_2', &amp;amp;N_2. / &amp;amp;Ntot.);&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symput('P_3', &amp;amp;N_3. / &amp;amp;Ntot.);&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symput('P_4', &amp;amp;N_4. / &amp;amp;Ntot.);&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symput('P_5', &amp;amp;N_5. / &amp;amp;Ntot.);&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symput('P_6', &amp;amp;N_6. / &amp;amp;Ntot.);&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symput('P_7', &amp;amp;N_7. / &amp;amp;Ntot.);&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symput('P_8', &amp;amp;N_8. / &amp;amp;Ntot.);&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symput('P_9', &amp;amp;N_9. / &amp;amp;Ntot.);&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symput('P_10', &amp;amp;N_10. / &amp;amp;Ntot.);&lt;br /&gt;run;&lt;br /&gt;*** Macro variable for model specifications ***;&lt;br /&gt;%let P_O = &amp;amp;P_1. &amp;amp;P_2. &amp;amp;P_3. &amp;amp;P_4. &amp;amp;P_5. &amp;amp;P_6. &amp;amp;P_7. &amp;amp;P_8. &amp;amp;P_9. &amp;amp;P_10.;&lt;/code&gt;&lt;/pre&gt;這段程式碼簡而言之，就是先用 PROC FREQ 把次數分配表的結果算出來，然後把這必要的變數（也就是 frequency 和 cumfrequency）存出來計算每一層的比例，再把這比例結果用 symput 函數存成不同的巨集變數，然後一次丟進 %let 裡面整合成一個巨集變數供 estimate 語法使用。不過我覺得原文作者寫的這段程式稍嫌複雜些，可能因為他用的資料結構比較複雜的因素。在一般的情況下，用 PROC FREQ 可以立刻求出類別變數內各層的比例：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc freq data=xxx;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;tables varcat;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;ods output onewayfreqs = temp(keep=&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;percent&lt;/span&gt;&lt;/b&gt;);&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;用 ods output 另存的資料裡面有個 percent 變數就是每一層的比例。然後用 proc transpose 轉置：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc transpose data=temp out=temp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;var percent;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;假設有十層的話，轉置後的 percent 會被存在 COL1~COL10 裡面。然後用 symput 函數分別將他們存成不同的巨集變數：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data _null_;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;set temp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;call symput('P_1', COL1);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;call symput('P_2', COL2);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;call symput('P_3', COL3);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;call symput('P_4', COL4);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;call symput('P_5', COL5);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;call symput('P_6', COL6);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;call symput('P_7', COL7);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;call symput('P_8', COL8);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;call symput('P_9', COL9);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;call symput('P_10', COL10); &lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;最後再全部丟到 %let 後面用一個巨集變數整合他們：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%let P = &amp;amp;P_1 &amp;amp;P_2 &amp;amp;P_3;&lt;/code&gt;&lt;/pre&gt;如此一來，在寫 estimate 時需要用到這串數字向量時，輕鬆填上&amp;amp;P 即可！&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&amp;nbsp;&lt;/b&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. &amp;nbsp;Contact the author at:&lt;br /&gt;&amp;nbsp;David J. Pasta &lt;br /&gt;&amp;nbsp;Vice President, Statistics &amp;amp; Data Operations&lt;br /&gt;ICON Clinical Research &lt;br /&gt;&amp;nbsp;188 Embarcadero, Suite 200&lt;br /&gt;&amp;nbsp;San Francisco, CA 94105&lt;br /&gt;&amp;nbsp;+1.415.371.2111 &amp;nbsp; &lt;br /&gt;&amp;nbsp;david.pasta@iconplc.com &lt;br /&gt;&amp;nbsp;www.iconplc.com&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-3555906576014195085?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/3555906576014195085/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=3555906576014195085&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/3555906576014195085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/3555906576014195085'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/05/practicalities-of-using-estimate-and.html' title='Practicalities of Using ESTIMATE and CONTRAST Statements'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-5646856717479538395</id><published>2011-05-14T00:43:00.000-04:00</published><updated>2011-05-14T00:43:00.885-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程序語法'/><title type='text'>Updates to SAS® Power and Sample Size Software in SAS/STAT® 9.2</title><content type='html'>Link:&amp;nbsp;&lt;a href="http://www2.sas.com/proceedings/forum2008/368-2008.pdf"&gt;http://www2.sas.com/proceedings/forum2008/368-2008.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;PROC POWER程序從SAS 9.1版發表出來後，讓許多power和樣本計算的過程不需要靠使用者自行寫程式才能完成。但一開始的功能並不完備，不過在SAS 9.2版釋出後，PROC POWER 內建的功能就逐漸被補齊了。Wayne Watson 於 SAS Global Forum 2008 發表了一份技術文件，整理了 SAS 9.2版的 PROC POWER 一些新增的功能。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;(1)&amp;nbsp;LOGISTIC REGRESSION&lt;/b&gt;&lt;br /&gt;羅吉斯迴歸的 power analysis 在此已經可以進行了。使用前要先寫 logistic 告知 SAS 要跑這種模型的 power analysis，並把要檢定的預測變數、勝算比以及反應變數 Y=1 的機率都寫上去，重點是要把檢定的預測變數的分配設定好（藍色部分）。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc power;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span class="Apple-style-span" style="color: red;"&gt;logistic&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;alpha = 0.05&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-style-span" style="color: blue;"&gt;vardist(’Duration’) = normal(4, 1.5)&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;testpredictor = ’Duration’&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;testoddsratio = 1.7&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;responseprob = 0.65&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ntotal = 50 60 70&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;power = . ;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm5.static.flickr.com/4111/5090414047_1fa6084d3d_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;(2) CONFIDENCE INTERVAL FOR ONE PROPORTION&lt;/b&gt;&lt;br /&gt;二項變數的信賴區間也可以算了，但這結果其實跟用 PROC FREQ 算出來的結果是一樣的，所以如果你已經會用 PROC FREQ 來算二項變數的信賴區間的話，就不用多學這一段了。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc power;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;onesamplefreq ci = Wilson&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;alpha = 0.05&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;proportion = 0.3&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;halfwidth = 0.1&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ntotal = 70&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;probwidth = .;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm5.static.flickr.com/4152/5090427997_40719ea898_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;(3) EQUIVALENCE TESTS FOR ONE PROPORTION&lt;/b&gt;&lt;br /&gt;假設檢定中的比例檢定的 power analysis 也可以做了。重點就是要把紅色那段程式碼寫上去，其餘的參數設定跟以往都差不多。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc power;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span class="Apple-style-span" style="color: red;"&gt;onesamplefreq test = equiv_exact&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;alpha = 0.05&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;proportion = 0.35&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;lower = 0.2&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;upper = 0.4&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ntotal = 500&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;power = .;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm5.static.flickr.com/4144/5090433565_6548feeb34_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;(4)&amp;nbsp;WILCOXON MANN-WHITNEY TEST FOR TWO INDEPENDENT GROUPS&lt;/b&gt;&lt;br /&gt;無母數 Wilcoxon Mann-Whitney 檢定的 power analysis 可以用 twosamplewilcoxon 呼叫出。比較麻煩的是類別變數的分配要自己將每一層的 coding 和機率值打上去（藍色部分），注意後面機率值的總和要等於一。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc power;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span class="Apple-style-span" style="color: red;"&gt;twosamplewilcoxon&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;alpha = 0.05&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span class="Apple-style-span" style="color: blue;"&gt;vardist(’lidocaine’) =ordinal( (-3 -2 -1 0 1 2 3): (.01 .04 .20 .50 .20 .04 .01) )&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;vardist(’mironel plus lidocaine’) =ordinal( (-3 -2 -1 0 1 2 3): (.01 .03 .15 .35 .30 .10 .06) )&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;variables = ’lidocaine’ | ’mironel plus lidocaine’&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sides = u&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ntotal = .&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;power = 0.85;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm5.static.flickr.com/4152/5091035958_1b0d85e685_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;最後原文有介紹一個SAS專門拿來做 Power analysis 的副產品Power and Sample Size 3.1，簡稱 PSS。不過這個軟體並沒有附在 SAS/STAT 裡面，需要另外安裝。我自己的 SAS 9.2 光碟片裡面好像也沒有這個附加軟體，研判應該是需要另外付費才有。我想應該也不會有很多人有 PSS，所以在此略過不提。把 PROC POWER 熟用應該就可以應付大部分的 Power analysis 以及相關繪圖。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&lt;/b&gt;&lt;br /&gt;Wayne Watson&lt;br /&gt;Building S, Room 3040&lt;br /&gt;SAS Institute, Inc.&lt;br /&gt;SAS Campus Drive&lt;br /&gt;Cary, NC 27513&lt;br /&gt;Work Phone: 919-531-6770&lt;br /&gt;E-mail: wayne.watson@sas.com&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-5646856717479538395?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/5646856717479538395/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=5646856717479538395&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/5646856717479538395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/5646856717479538395'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/05/updates-to-sas-power-and-sample-size.html' title='Updates to SAS® Power and Sample Size Software in SAS/STAT® 9.2'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4111/5090414047_1fa6084d3d_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-6688406305376006917</id><published>2011-05-07T06:03:00.003-04:00</published><updated>2011-05-07T06:03:00.306-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='繪圖技巧'/><title type='text'>Creating High-Quality Scatter Plots: An Old Story Told by the New SGSCATTER PROCEDURE</title><content type='html'>原文載點：&lt;a href="http://support.sas.com/resources/papers/proceedings10/057-2010.pdf"&gt;http://support.sas.com/resources/papers/proceedings10/057-2010.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;散佈圖算是統計圖表裡面一個很基本的呈現資料分布型態的表示方法，但是用 PROC GPLOT 畫出來的散佈圖不甚美觀。一位辛辛那提大學數學系的中國學生寫了這一篇技術文件，採用了 PROC SGSCATTER 程序，將單純的散佈圖的品質提昇到另一個境地。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;資料來源是採用 SAS 裡面現成的資料檔 sashelp.cars，但作者只採用部分的內容：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ods html style=harvest;&lt;br /&gt;data cars;&lt;br /&gt;&amp;nbsp;&amp;nbsp;set sashelp.cars;&lt;br /&gt;&amp;nbsp;&amp;nbsp;where make in ('Jeep' 'Chevrolet' 'Ford' 'Chrysler');&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;變數的定義如下：&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;img height="153" src="http://farm6.static.flickr.com/5190/5665240480_7c67e59022_b.jpg" width="400" /&gt;&lt;/div&gt;&lt;br /&gt;接下來所有的範例都會被 ODS 輸出成 html 的格式，採用了 harvest 的風格。如果你不喜歡 harvest 的風格，還有其他三種可以選：&lt;br /&gt;&lt;br /&gt;&lt;img height="531" src="http://farm6.static.flickr.com/5266/5665250128_c395797cd6_b.jpg" width="640" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;範例一&lt;/b&gt;&lt;br /&gt;以往用 PROC GPLOT 要畫 Y*(X1 X2) 的圖時，會產生兩張獨立的圖給你。現在用 PROC SGSCATTER 會自動給你合併成一張的圖。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sgscatter data=cars;&lt;br /&gt;&amp;nbsp;&amp;nbsp;plot invoice*(weight length); &lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm6.static.flickr.com/5185/5665282390_f5b5b396c3_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;範例二&lt;/b&gt;&lt;br /&gt;如果想共用同一條軸，只要把 y= 和 x= 加上去就可以了。這樣可以讓散佈圖可視面積稍大一些。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sgscatter data=cars;&lt;br /&gt;&amp;nbsp;&amp;nbsp;compare &lt;span class="Apple-style-span" style="color: red;"&gt;y=&lt;/span&gt;invoice &lt;span class="Apple-style-span" style="color: red;"&gt;x=&lt;/span&gt;(weight length);&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm6.static.flickr.com/5021/5664722017_c8bd529fb4_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;範例三&lt;/b&gt;&lt;br /&gt;以前介紹過的散佈矩陣圖。在 PROC SGSCATTER 裡面用 matrix 語法來執行。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sgscatter data=cars;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;span class="Apple-style-span" style="color: red;"&gt;matrix &lt;/span&gt;invoice weight length;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm6.static.flickr.com/5225/5665288368_7a0c888aca_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;範例四&lt;/b&gt;&lt;br /&gt;用 rows= 和 columns= 來指定合併圖時的行列數目。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sgscatter data=cars;&lt;br /&gt;&amp;nbsp;&amp;nbsp;plot invoice*(weight length) / rows=2 columns=1;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm6.static.flickr.com/5221/5664741877_c281da23a9_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;範例五&lt;/b&gt;&lt;br /&gt;想要知道不同汽車製造商的散佈位置，首先在 plot 語法後面加上一個 group = 的選項，把汽車製造商的變數名稱 make 放入，這樣 PROC SGSCATTER 就會知道要針對那個變數做分組，並且自動替不同的製造商加上不同的顏色和點型。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sgscatter data=cars;&lt;br /&gt;&amp;nbsp;&amp;nbsp;plot MPG_city*weight / &lt;span class="Apple-style-span" style="color: red;"&gt;group=make&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;where make in ('Ford' 'Chrysler' 'Chevrolet');&lt;br /&gt;&amp;nbsp;&amp;nbsp;title 'Scatter Plot by Make';&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm6.static.flickr.com/5068/5665307742_c84f3530c1_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;範例六&lt;/b&gt;&lt;br /&gt;想要在散佈圖上加上廠商的名稱，則是用 datalabel= 這個選項來處理。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sql;&lt;br /&gt;&amp;nbsp;&amp;nbsp;create table cars2 as&lt;br /&gt;select origin, make, mean(MSRP) as MSRP,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; mean(MPG_city) as MPG_city,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; mean(MPG_highway) as MPG_highway&lt;br /&gt;from sashelp.cars&lt;br /&gt;group by origin, make&lt;br /&gt;order by origin, make;&lt;br /&gt;quit;&lt;br /&gt;proc sgscatter data=cars2;&lt;br /&gt;&amp;nbsp;&amp;nbsp;plot MSRP*MPG_highway / &lt;span class="Apple-style-span" style="color: red;"&gt;datalabel=make&lt;/span&gt; group=origin grid;&lt;br /&gt;&amp;nbsp;&amp;nbsp;title 'Averaged MSRP vs. Highway MPG for Car Makers by Origin';&lt;br /&gt;&amp;nbsp;&amp;nbsp;format MSRP dollar6.0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;label MSRP='Manufacturer Suggested Retail Price' MPG_highway='Highway MPG'; &amp;nbsp;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm6.static.flickr.com/5103/5664742869_3953e069d8_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;範例七&lt;/b&gt;&lt;br /&gt;若要加上一條迴歸線以及信賴區間，則用 reg= 的選項來畫。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sgscatter data=cars2;&lt;br /&gt;&amp;nbsp;&amp;nbsp;plot MSRP*MPG_highway / datalabel=make group=origin grid &lt;span class="Apple-style-span" style="color: red;"&gt;reg=(degree=2 clm nogroup)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;title 'Averaged MSRP vs. Highway MPG for Car Makers by Origin';&lt;br /&gt;&amp;nbsp;&amp;nbsp;title2 '-- with quadratic regression fitting and conf. intervals --';&lt;br /&gt;&amp;nbsp;&amp;nbsp;format MSRP dollar6.0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;label MSRP='Manufacturer Suggested Retail Price' MPG_highway='Highway MPG'; &amp;nbsp;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm6.static.flickr.com/5189/5664743243_8b70a18a20_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;範例八&lt;/b&gt;&lt;br /&gt;要話95%的預測橢圓，則用 ellipse = 的選項來畫。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sgscatter data=cars2;&lt;br /&gt;&amp;nbsp;&amp;nbsp;compare y=MSRP x=(MPG_highway MPG_city) / group=origin &lt;span class="Apple-style-span" style="color: red;"&gt;ellipse=(alpha=0.05 type=predicted)&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;title 'Averaged MSRP vs. Highway/City MPG for car makers by Origin';&lt;br /&gt;&amp;nbsp;&amp;nbsp;title2 '-- with 95% prediction ellipse --';&lt;br /&gt;&amp;nbsp;&amp;nbsp;format MSRP dollar6.0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;label MSRP='Manufacturer Suggested Retail Price'&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;MPG_highway='Highway MPG' MPG_city='CITY MPG'; &amp;nbsp;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm6.static.flickr.com/5223/5665309356_af429163f5_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;範例九&lt;/b&gt;&lt;br /&gt;回到散佈矩陣圖，如果想要在圖的對角線畫上每個變數的次數分配柱狀圖以及常態曲線，則可用 diagnoal = 的選項處理。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;title 'Scatter Plot Matrix with&amp;nbsp;Histograms and Normal Fitting Curves';&lt;br /&gt;proc sgscatter data=cars;&lt;br /&gt;&amp;nbsp;&amp;nbsp;matrix invoice weight length / &lt;span class="Apple-style-span" style="color: red;"&gt;diagonal=(histogram normal)&lt;/span&gt;;&lt;br /&gt;run; quit;&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://farm6.static.flickr.com/5143/5664743805_fbce6809a5_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;範例十&lt;/b&gt;&lt;br /&gt;最後，用 ODS GRAPHICS 設定圖型內部的參數，然後在 ODS HTML 後面加上路徑來讓生出來的圖存到指定位置去。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;ods html gpath='C:\' style=harvest;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;ods graphics / reset=all width=12in height=6in border=off&amp;nbsp;imagename='example' imagefmt=png;&lt;/span&gt;&lt;br /&gt;proc sgscatter data=cars2;&lt;br /&gt;&amp;nbsp;&amp;nbsp;plot MSRP*(MPG_highway MPG_city) &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; / datalabel=make group=origin &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; grid reg=(degree=2 clm nogroup);&lt;br /&gt;&amp;nbsp;&amp;nbsp;title 'Averaged MSRP vs. Highway/City MPG for Car Makers by Origin';&lt;br /&gt;&amp;nbsp;&amp;nbsp;title2 '-- with quadratic regression fitting and conf. intervals --';&lt;br /&gt;&amp;nbsp;&amp;nbsp;format MSRP dollar6.0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;label MSRP='Manufacturer Suggested Retail Price'&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;MPG_highway='Highway MPG'&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;MPG_city='City MPG'; &amp;nbsp;&lt;br /&gt;run; &lt;br /&gt;ods html close;&lt;/code&gt;&lt;/pre&gt;幾個重要的 ODS GRAPHICS 參數在此介紹一下：&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;WIDTH=, HEIGHT= &amp;nbsp;：設定圖型的長度和寬度&lt;/li&gt;&lt;li&gt;IMAGENAME=, IMAGEFMT=&amp;nbsp;&amp;nbsp;：設定圖型的名稱和格式&lt;/li&gt;&lt;li&gt;BORDER=ON|OFF&amp;nbsp;&amp;nbsp;：設定要不要畫圖型的邊界&lt;/li&gt;&lt;li&gt;RESET=ALL&amp;nbsp;&amp;nbsp;&amp;nbsp;：繪圖結束後重設所有參數&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://farm6.static.flickr.com/5101/5664744051_6e299a1c76_z.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&lt;/b&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. Contact the author at:&lt;br /&gt;Xiangxiang Meng&lt;br /&gt;Department of Mathematical Science University of Cincinnati&lt;br /&gt;mengxa@mail.uc.edu&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-6688406305376006917?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/6688406305376006917/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=6688406305376006917&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6688406305376006917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6688406305376006917'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/05/creating-high-quality-scatter-plots-old.html' title='Creating High-Quality Scatter Plots: An Old Story Told by the New SGSCATTER PROCEDURE'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5190/5665240480_7c67e59022_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-6567097650628863902</id><published>2011-04-30T01:28:00.001-04:00</published><updated>2011-04-30T01:28:00.131-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='繪圖技巧'/><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>A Grad Student ‘How-To’ Paper on Grant Prep: Preliminary Data, Power Analysis, and Presentation</title><content type='html'>原文載點：http://support.sas.com/resources/papers/proceedings10/274-2010.pdf&lt;br /&gt;&lt;br /&gt;SAS 語法百百種，身為研究生的你/妳，有沒有想過有什麼是一定要學起來並且用在報告或論文上面？這篇技術文件整合了許多你一定得用在報告和論文的SAS程式！&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;b&gt;1. PRELIMINARY ANALYSIS I &amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code1.1：將變數製作成聚集變數&lt;/b&gt;&lt;br /&gt;這一步驟是用於一次要算幾百個變數的平均數的研究，讓使用者免去一個個輸入變數名稱的痛苦。但如果你只要算兩三個變數，那這段可以跳過。此程式所有的變數會被 PROC SQL 程序定義在一個名為 LIST 的巨集變數裡面。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;PROC SQL noprint;&lt;br /&gt;&amp;nbsp;select distinct NAME&lt;br /&gt;&amp;nbsp;into :LIST&lt;br /&gt;&amp;nbsp;separated by " "&lt;br /&gt;&amp;nbsp;from work.cells_1;&lt;br /&gt;quit;&lt;/code&gt;&lt;/pre&gt;&lt;b&gt;Code1.2：計算平均數並用ODS OUTPUT輸出&lt;/b&gt;&lt;br /&gt;此例的變數名稱就直接用 &amp;amp;LIST 把上面整合好的變數名稱一次叫進來。同樣地，如果你只有少量變數，那直接輸入即可。此程式會將算好的基本統計量另存在 basic_measures 的新資料集裡面。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ODS OUTPUT BASICMEASURES=work.basic_measures;&lt;br /&gt;proc univariate data=work.&amp;amp;input.;&lt;br /&gt;class day;&lt;br /&gt;var &amp;amp;LIST.;&lt;br /&gt;run;&lt;br /&gt;ODS OUTPUT CLOSE;&lt;/code&gt;&lt;/pre&gt;&lt;b&gt;Code1.3：重整結果以生成繪圖所需的資料&lt;/b&gt;&lt;br /&gt;重新編輯資料集 basic_measures 以算出額外兩個新變數 High 和 Low。這兩個變數被定義為平均數正負一個變異數的大小。但我建議正規的作法應該要去算 95% 信賴區間比較好。這部份各位可以自行修改。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data work.basic_measures_all;&lt;br /&gt;set work.basic_measures (rename=( LocValue=Mean));&lt;br /&gt;if LOCMEASURE in ("Mean");&lt;br /&gt;High=mean+varvalue;&lt;br /&gt;Low=mean-varvalue;&lt;br /&gt;Keep varname day mean high low;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;做出來的繪圖資料如下圖所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/418/1911325897.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/418/1911325897.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;Code1.4：將變數和標籤製作成聚集變數&lt;/b&gt;&lt;br /&gt;這一段是要將剛剛做出來的繪圖資料裡面的變數以及標籤製作成巨集變數以用於繪圖程式當中。如果你打算手動輸入，此段也可以省略。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sql noprint;&lt;br /&gt;&amp;nbsp;&amp;nbsp;select NAME as VAR into:VAR1- :VAR&amp;amp;SYSMAXLONG.&lt;br /&gt;&amp;nbsp;&amp;nbsp;from work.cells_1;&lt;br /&gt;&amp;nbsp;&amp;nbsp;quit;&lt;br /&gt;proc sql noprint;&lt;br /&gt;&amp;nbsp;&amp;nbsp;select LABEL as LABEL into:LABEL1- :LABEL&amp;amp;SYSMAXLONG.&lt;br /&gt;&amp;nbsp;&amp;nbsp;from work.cells_1;&lt;br /&gt;&amp;nbsp;&amp;nbsp;quit;&lt;/code&gt;&lt;/pre&gt;&lt;b&gt;Code1.5：繪圖並輸出&lt;/b&gt;&lt;br /&gt;用 PROC SGPLOT 進行曲線圖的製作，並將結果用 ODS RTF 輸出到外部文件檔案。如果你想要製作別種圖，那就需要對 PROC SGPLOT 部分進行調整。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ods output;&lt;br /&gt;ods RTF file="C:\documents and settings\desktop\GRAPHS_MEANS.RTF" &amp;nbsp;;&lt;br /&gt;%do j=1 %to &amp;amp;SQLOBS.;&lt;br /&gt;data work.values;&lt;br /&gt;set work.basic_measures_all;&lt;br /&gt;if varname="&amp;amp;&amp;amp;VAR&amp;amp;J.";&lt;br /&gt;run;&lt;br /&gt;proc sgplot data=work.values noautolegend;&lt;br /&gt;&amp;nbsp;xaxis type=discrete;&lt;br /&gt;&amp;nbsp;series x=day y=mean;&lt;br /&gt;&amp;nbsp;scatter x=day y=mean /&lt;br /&gt;&amp;nbsp;markerattrs=(size=0)&lt;br /&gt;&amp;nbsp;yerrorlower=low&lt;br /&gt;&amp;nbsp;yerrorupper=high;&lt;br /&gt;run;&lt;br /&gt;%end;&lt;/code&gt;&lt;/pre&gt;製作出來的圖型如下：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/418/0461979911.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/418/0461979911.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;Code1.6：用 PROC MIXED 程序進行分析並估計所需的組間差異&lt;/b&gt;&lt;br /&gt;此例由於是在做重複觀測值的模型估計，所以用到 PROC MIXED 程序。這部份可視使用者的情況來調整。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ods proclabel "&amp;amp;&amp;amp;VAR&amp;amp;K. &amp;amp;&amp;amp;LABEL&amp;amp;K.";&lt;br /&gt;ods output &amp;nbsp;Estimates=work.est &amp;nbsp;SolutionF=work.sol tests3=work.tests3 ;&lt;br /&gt;proc mixed data=work.mixed1 COVTEST cl NOCLPRINT NOITPRINT ;&lt;br /&gt;&amp;nbsp;&amp;nbsp;class patient_id day_numeric;&lt;br /&gt;&amp;nbsp;&amp;nbsp;model &amp;amp;&amp;amp;var&amp;amp;k. =day_numeric /solution noint cl residual ;&lt;br /&gt;&amp;nbsp;&amp;nbsp;repeated day_numeric / subject=patient_id type=ar(1) rcorr r;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate '-4 vs 0' &amp;nbsp; &amp;nbsp; &amp;nbsp;day_numeric &amp;nbsp; -1 1 0 0 0 0 0 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate '-4 &amp;amp; 0 vs 4' &amp;nbsp;day_numeric &amp;nbsp; -0.5 -0.5 1 0 0 0 0 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate '-4 &amp;amp; 0 vs 8' &amp;nbsp;day_numeric &amp;nbsp; -0.5 -0.5 0 1 0 0 0 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate '-4 &amp;amp; 0 vs 12' day_numeric &amp;nbsp; -0.5 -0.5 0 0 1 0 0 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate '-4 &amp;amp; 0 vs 15' day_numeric &amp;nbsp; -0.5 -0.5 0 0 0 1 0 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate '-4 &amp;amp; 0 vs 16' day_numeric &amp;nbsp; -0.5 -0.5 0 0 0 0 1 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;estimate '-4 &amp;amp; 0 vs 22' day_numeric &amp;nbsp; -0.5 -0.5 0 0 0 0 0 1;&lt;br /&gt;run;&lt;br /&gt;quit;&lt;br /&gt;ods output close;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Code1.7：格式化結果&lt;/b&gt;&lt;br /&gt;這段只是單純把上面用 PROC MIXED 跑出來的結果整理一下。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data work.est;&lt;br /&gt;length variable $32 variable_label $32 variable_subset $32;&lt;br /&gt;set work.est;&lt;br /&gt;variable="&amp;amp;&amp;amp;var&amp;amp;k.";&lt;br /&gt;run;&lt;br /&gt;PROC APPEND BASE=work.est_all_&amp;amp;source. DATA=work.est force;&lt;br /&gt;RUN;&lt;/code&gt;&lt;/pre&gt;最後的表格就可以直接輸出到報告和論文上，如下所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/418/0261622099.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/418/0261622099.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. PRELIMINARY ANALYSIS II &amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code2.1：繪製個人曲線圖&lt;/b&gt;&lt;br /&gt;注意此處的巨集變數都是從 Code1.4 生成出來的。如果跳過那步驟的人，就自己手動輸入變數名稱吧！&lt;br /&gt;&lt;pre&gt;&lt;code&gt;axis1 label=(angle=90);&lt;br /&gt;symbol i=j repeat=100 w=5;&lt;br /&gt;proc gplot data=work.mixed2;&lt;br /&gt;&amp;nbsp;&amp;nbsp; plot &amp;amp;&amp;amp;var&amp;amp;i.*week_numeric=patient_id/vaxis=axis1 nolegend;&lt;br /&gt;run;&lt;br /&gt;quit;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;圖型如下所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/418/9198697077.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/418/9198697077.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;Code2.2：PROC SGPANAL&lt;/b&gt;&lt;br /&gt;這段是在畫另一種圖，但我覺得不是很重要，可以省略。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sgpanel data=work.data_transpose_2;&lt;br /&gt;&amp;nbsp;&amp;nbsp;where _NAME_ in ("&amp;amp;&amp;amp;VAR&amp;amp;I.");&lt;br /&gt;&amp;nbsp;&amp;nbsp;panelby _LABEL_/novarname ;&lt;br /&gt;&amp;nbsp;&amp;nbsp;colaxis type=discrete values=(-7,0,1,3,7,10,14,21,28);&lt;br /&gt;&amp;nbsp;&amp;nbsp;rowaxis label="log (Count)";&lt;br /&gt;&amp;nbsp;&amp;nbsp;series x=day y=_1 /markers LINEATTRS = (THICKNESS = 3);&lt;br /&gt;&amp;nbsp;&amp;nbsp;series x=day y=_2 /markers LINEATTRS = (THICKNESS = 3);&lt;br /&gt;&amp;nbsp;&amp;nbsp;series x=day y=_3 /markers LINEATTRS = (THICKNESS = 3);&lt;br /&gt;&amp;nbsp;&amp;nbsp;series x=day y=_4 /markers LINEATTRS = (THICKNESS = 3);&lt;br /&gt;&amp;nbsp;&amp;nbsp;series x=day y=_5 /markers LINEATTRS = (THICKNESS = 3);&lt;br /&gt;&amp;nbsp;&amp;nbsp;series x=day y=_6 /markers LINEATTRS = (THICKNESS = 3);&lt;br /&gt;run;&lt;br /&gt;quit;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;圖型如下：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/418/3080925228.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/418/3080925228.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;Code2.3：用 PROC MIXED 估計參數並用 ODS OUTPUT 輸出共變異數矩陣裡的參數&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ODS OUTPUT "Covariance Parameter Estimates"=work.parameters;&lt;br /&gt;&lt;br /&gt;proc mixed data=mixed2 COVTEST cl NOCLPRINT NOITPRINT ;&lt;br /&gt;&amp;nbsp;&amp;nbsp;class patient_id ;&lt;br /&gt;&amp;nbsp;&amp;nbsp;model &amp;amp;&amp;amp;var&amp;amp;i. =day_numeric /solution cl ;&lt;br /&gt;&amp;nbsp;&amp;nbsp;random intercept / subject=patient_id ;&lt;br /&gt;&amp;nbsp;&amp;nbsp;run;&lt;br /&gt;&amp;nbsp;&amp;nbsp;quit;&lt;br /&gt;ODS OUTPUT CLOSE;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/418/2304240514.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/418/2304240514.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt;Code2.4：整理共變異數並計算 ICC&lt;/b&gt;&lt;br /&gt;這段程式看起來非常冗長，但其實簡單來講就是把 Code2.3 做出來的資料整理後算出 ICC（藍色部分），不過原作者還算了很多其他的估計值。如果你只是想要求出 ICC，那綠色的程式碼可以不用寫。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data work.parameters_between;&lt;br /&gt;&amp;nbsp;set work.parameters;&lt;br /&gt;if covparm="Intercept" then do;&lt;br /&gt;&amp;nbsp;&amp;nbsp; Between_Subject_Variance=Estimate;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&amp;nbsp;&amp;nbsp; Between_p_value=ProbZ;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&amp;nbsp;&amp;nbsp; Between_Lower=Lower;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&amp;nbsp;&amp;nbsp; Between_Upper=Upper;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;end;&lt;br /&gt;&amp;nbsp;if covparm="Intercept" ;&lt;br /&gt;&amp;nbsp;keep Between_Subject_Variance &lt;span class="Apple-style-span" style="color: #38761d;"&gt;Between_P_Value Between_Lower Between_Upper&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;run;&lt;br /&gt;&amp;nbsp;data work.parameters_within;&lt;br /&gt;&amp;nbsp;set work.parameters;&lt;br /&gt;&amp;nbsp;if covparm="Residual" then do;&lt;br /&gt;&amp;nbsp;&amp;nbsp; Within_Subject_Variance=Estimate;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&amp;nbsp;&amp;nbsp; Within_p_value=ProbZ;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&amp;nbsp;&amp;nbsp; Within_Lower=Lower;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&amp;nbsp;&amp;nbsp; Within_Upper=Upper;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; end;&lt;br /&gt;&amp;nbsp;if covparm="Residual" ;&lt;br /&gt;&amp;nbsp;keep Within_Subject_Variance &lt;span class="Apple-style-span" style="color: #38761d;"&gt;WITHIN_P_VALUE Within_Lower Within_Upper&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;run;&lt;br /&gt;&amp;nbsp;data work.parameters_all;&lt;br /&gt;&amp;nbsp;merge work.parameters_between work.parameters_within;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;ICC=between_subject_variance/(within_subject_variance+between_subject_variance);&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;variable="&amp;amp;&amp;amp;var&amp;amp;i."; variable_label="&amp;amp;&amp;amp;label&amp;amp;i."; data_source="&amp;amp;source.";&lt;br /&gt;&amp;nbsp;run;&lt;br /&gt;&amp;nbsp;quit;&lt;br /&gt;&amp;nbsp;proc print data=work.parameters_all noobs;&lt;br /&gt;&amp;nbsp;run;&lt;/code&gt;&lt;/pre&gt;最後用 PROC PRINT 列印出來的結果如下：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/418/3454488330.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/418/3454488330.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. POWER SIMULATION&lt;/b&gt;&lt;br /&gt;最後重頭戲是 power analysis。不過此處用到模擬的原因是因為，作者想要做 power analysis 的對象是 ICC 和組間變異數，而非我們一般常看到的假設檢定。而由於 ICC 和組間變異數的 power 計算並沒有封閉形式(close form)的解，所以必須用模擬的方式來算出。&lt;br /&gt;&lt;b&gt;Code3.1：生成種子(seed)&lt;/b&gt;&lt;br /&gt;用亂數去生成種子讓每一次的模擬都能隨機。種子的數量取得於母體大小乘上需要模擬的次數。本例的種子數目高達一千五百萬。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%MACRO INITIALIZE ();&lt;br /&gt;%Global Initial; &amp;nbsp;&lt;br /&gt;%Let Initial=0;&lt;br /&gt;data Initialseed (keep=id InitialSeed);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;do I = 1 to 15000000; &amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;InitialSeed =int(10000*(ranuni(0)));&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;id=I;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;output;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;end;&lt;br /&gt;run;&lt;br /&gt;data SIM.InitialSeed;&lt;br /&gt;&amp;nbsp;set work.InitialSeed;&lt;br /&gt;run;&lt;br /&gt;%MEND INITIALIZE;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Code3.2：製作依序取得種子的巨集程式&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%LET Initial=35;&lt;br /&gt;%MACRO SEED ();&lt;br /&gt;%let Initial=%EVAL(&amp;amp;Initial. +1);&lt;br /&gt;&amp;nbsp;data work.seed ;&lt;br /&gt;&amp;nbsp;&amp;nbsp;set sim.initialseed (Firstobs=&amp;amp;Initial. obs=&amp;amp;Initial.);;&lt;br /&gt;&amp;nbsp;run;&lt;br /&gt;&amp;nbsp;data _null_;&lt;br /&gt;&amp;nbsp;&amp;nbsp;set work.seed;&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symputx ('InitialSeed',InitialSeed);&lt;br /&gt;&amp;nbsp;run;&lt;br /&gt;%put Seed is # &amp;amp;Initial. and is valued &amp;amp;InitialSeed. ;&lt;br /&gt;%MEND SEED;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Code3.3：模擬資料的巨集程式&lt;/b&gt;&lt;br /&gt;原文中 Code3.3~Code3.9 都是在講資料的生成。我將他們放在一起。簡單來講，先生成 baseline 資料(work.test)，再生成其他時間點的資料(work.test_2)，然後用 PROC TRANSPOSE 把生成好的結果轉置(直的變成橫的)，接著就是用 PROC MIXED 不斷重複地去估計共變異數矩陣的參數，把這重複估計出來的參數存成一個新檔案(work.mixed)，然後去算有多少顯著的比例。最後把結果整理成報表。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%MACRO TEST(mean=,between_var=,within_var=,simulation=,population=,timecount=);&lt;br /&gt;&lt;br /&gt;data work.test;&lt;br /&gt;*first loop defines the simulation number*;&lt;br /&gt;do i= 1 to &amp;amp;simulation.;&lt;br /&gt;*second loop defines the number of people in the study*;&lt;br /&gt;&amp;nbsp;do j=1 to &amp;amp;population.;&lt;br /&gt;&amp;nbsp;&amp;nbsp; TIME_0=&amp;amp;mean.+sqrt(&amp;amp;between_var.)*rannor(&amp;amp;initialseed.);&lt;br /&gt;&amp;nbsp;&amp;nbsp;Simulation_ID=i;&lt;br /&gt;&amp;nbsp;&amp;nbsp;Person_ID=J; &lt;br /&gt;&amp;nbsp;&amp;nbsp;output;&lt;br /&gt;&amp;nbsp;end;&lt;br /&gt;end;&lt;br /&gt;drop I j;&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;data work.test_2;&lt;br /&gt;set work.test;&lt;br /&gt;array time (*) TIME_1-TIME_&amp;amp;timecount.;&lt;br /&gt;&amp;nbsp;&amp;nbsp;do k=1 to &amp;amp;timecount.;&lt;br /&gt;&amp;nbsp;&amp;nbsp; Time[k]=TIME_0 + sqrt(&amp;amp;within_var.)*rannor(&amp;amp;initialseed.);&lt;br /&gt;&amp;nbsp;end;&lt;br /&gt;&amp;nbsp;&amp;nbsp;output;&lt;br /&gt;drop k;&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;proc transpose data=work.test_2 out=work.test_3 prefix=value;&lt;br /&gt;&amp;nbsp;by simulation_ID person_id;&lt;br /&gt;run;&lt;br /&gt;data work.test_3;&lt;br /&gt;set work.test_3;&lt;br /&gt;&amp;nbsp;TIME= input(scan(_NAME_,2,'_'),2.);&lt;br /&gt;&amp;nbsp;TIME2=TIME;&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;ODS LISTING CLOSE;&lt;br /&gt;ODS OUTPUT COVPARMS=work.mixed;&lt;br /&gt;proc mixed data=work.test_3 covtest;&lt;br /&gt;&amp;nbsp;&amp;nbsp;by simulation_ID;&lt;br /&gt;&amp;nbsp;&amp;nbsp;model value1=time;&lt;br /&gt;&amp;nbsp;&amp;nbsp;random intercept/ sub=person_id;&lt;br /&gt;run;&lt;br /&gt;ODS OUTPUT CLOSE;&lt;br /&gt;&lt;br /&gt;data work.mixed_1;&lt;br /&gt;set work.mixed;&lt;br /&gt;if Covparm="Intercept";&lt;br /&gt;if probz&amp;lt;0.1 then P_point1=1;&lt;br /&gt;if probz&amp;lt;0.05 then P_point05=1;&lt;br /&gt;if probz&amp;lt;0.01 then P_point01=1;&lt;br /&gt;if probz&amp;lt;0.001 then P_point001=1;&lt;br /&gt;if probz=. then do;&lt;br /&gt;&amp;nbsp;p_point1=.;&lt;br /&gt;&amp;nbsp;p_point05=.;&lt;br /&gt;&amp;nbsp;p_point01=.;&lt;br /&gt;&amp;nbsp;p_point001=.;&lt;br /&gt;&amp;nbsp;&amp;nbsp;end;&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;ODS OUTPUT onewayfreqs=work.mixed_freqs_1;&lt;br /&gt;ODS LISTING;&lt;br /&gt;proc freq data=work.mixed_1 ;&lt;br /&gt;table p_point1 p_point05 p_point01 &amp;nbsp;p_point001/missing;&lt;br /&gt;run;&lt;br /&gt;ODS LISTING CLOSE;&lt;br /&gt;ODS OUTPUT CLOSE;&lt;br /&gt;&lt;br /&gt;proc append Base=work._mixed_freqs_all data=work._mixed_freqs_all_&amp;amp;initial. FORCE;&lt;br /&gt;run;&lt;br /&gt;%MEND;&lt;/code&gt;&lt;/pre&gt;&lt;b&gt;Code3.10：開始模擬&lt;/b&gt;&lt;br /&gt;最後就是呼叫前面寫好的巨集程式，輸入不同的組間變異數和組內變異數的數值，定義總共要模擬的次數、樣本大小、時間點數量以及平均數。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%test(mean=-0.2740, between_var=0.01,within_var=0.67,simulation=1000,population=20,timecount=12);&lt;br /&gt;%test(mean=-0.2740, between_var=0.02,within_var=0.66,simulation=1000,population=20,timecount=12);&lt;br /&gt;%test(mean=-0.2740, between_var=0.03,within_var=0.65,simulation=1000,population=20,timecount=12);&lt;br /&gt;%test(mean=-0.2740, between_var=0.04,within_var=0.64,simulation=1000,population=20,timecount=12);&lt;br /&gt;%test(mean=-0.2740, between_var=0.05,within_var=0.63,simulation=1000,population=20,timecount=12);&lt;br /&gt;%test(mean=-0.2740, between_var=0.06,within_var=0.62,simulation=1000,population=20,timecount=12);&lt;br /&gt;%test(mean=-0.2740, between_var=0.50,within_var=0.16,simulation=1000,population=20,timecount=12);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Code3.11：整理繪圖資料&lt;/b&gt;&lt;br /&gt;模擬完後的資料存在 work._mixed_freqs_all 裡面，把不同組間變異數相對應的 ICC 放進去，並且把變數的標籤寫好。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data work.plots ;&lt;br /&gt;set work._mixed_freqs_all;&lt;br /&gt;&amp;nbsp;if between_var= &amp;nbsp;0.01 then ICC = &amp;nbsp;0.01 ;&lt;br /&gt;&amp;nbsp;if between_var= &amp;nbsp;0.06 then ICC = &amp;nbsp;0.09 ;&lt;br /&gt;&amp;nbsp;if between_var= &amp;nbsp;0.11 then ICC = &amp;nbsp;0.16 ;&lt;br /&gt;&amp;nbsp;.……&lt;br /&gt;label percent="Power" population="Number of Subjects" timecount="Number of Time &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Points:";&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Code3.12：繪圖&lt;/b&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sort data=work.plots;&lt;br /&gt;&amp;nbsp;by population;&lt;br /&gt;run;&lt;br /&gt;symbol i=j width=5;&lt;br /&gt;ODS LISTING;&lt;br /&gt;proc gplot data=work.plots;&lt;br /&gt;&amp;nbsp;by population ;&lt;br /&gt;&amp;nbsp;where table ="P_point01" and mixed=2;&lt;br /&gt;&amp;nbsp;plot percent*ICC=timecount;&lt;br /&gt;run;&lt;br /&gt;quit;&lt;/code&gt;&lt;/pre&gt;最後圖型如下：&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/418/4177901899.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="348" src="http://easycaptures.com/fs/uploaded/418/4177901899.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. Contact the author at:&lt;br /&gt;Elisa L. Priest, MPH &lt;br /&gt;elisapriest@hotmail.com&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-6567097650628863902?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/6567097650628863902/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=6567097650628863902&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6567097650628863902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6567097650628863902'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/04/grad-student-how-to-paper-on-grant-prep.html' title='A Grad Student ‘How-To’ Paper on Grant Prep: Preliminary Data, Power Analysis, and Presentation'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-3245684446823300171</id><published>2011-04-09T15:56:00.002-04:00</published><updated>2011-04-11T11:59:37.443-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='其他'/><title type='text'>Improving Your Statistical Consulting Prowess by Adding R to Your SAS® Repertoire</title><content type='html'>原文載點：http://support.sas.com/resources/papers/proceedings10/290-2010.pdf&lt;br /&gt;&lt;br /&gt;我不清楚有多少人和我一樣，用SAS分析資料，但是用R來做圖。其實我一開始堅持資料分析和做圖都在SAS內一次完成，但後來我終於明白SAS/GRAPH要做出等同用R畫出來的圖形品質，需要花費更多時間，於是我終於將做圖的工作完全交付給R，也展開了我要一直切換兩個軟體視窗的日子。但我一直相信可以在SAS裡面呼叫R來完成畫圖的工作，終於讓我在SAS Global Forum 2010上面發現到一篇技術文件，在此跟大家分享。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;首先要讓SAS執行R的程式所需的第一件事情，是要去SAS官網下載SAS/IML Studio 3.2，這是一套龐大但免費的軟體，總容量是整整1GB，下載前需要去SAS官網註冊帳號，註冊好就可以直接下載了。網址是&amp;nbsp;&lt;a href="http://support.sas.com/rnd/app/da/workshop.html"&gt;http://support.sas.com/rnd/app/da/workshop.html&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;/div&gt;&lt;div style="text-align: -webkit-auto;"&gt;&lt;br /&gt;&lt;/div&gt;原文內雖然是說用SAS/IML Workshop 2.2，但我實際去官網查詢的結果，發現只有 SAS/IML Workshop 2.1的連結，而且沒有辦法用在最新的SAS 9.2版上面。所以請直接去下載SAS/IML Studio 3.2版即可。經過我的測試是可以執行以下的範例的。&lt;br /&gt;&lt;br /&gt;下載完畢並安裝好後，就可以在SAS裡面寫R的程式並呼叫R來執行，而結果會顯示在SAS的視窗裡面。不過根據本人的經驗，事情沒有那麼簡單，因為當我裝好並執行一段官網上的範例時，視窗一直彈跳出軟體找不到R的錯誤訊息，經過與SAS官網客服人員的聯繫，才知道SAS/IML Studio 3.2目前只能與R的2.9.1和2.11.1這兩個版本相容。如果你已經安裝了最新的R 2.12.2版，目前唯一的解決方法就是移除最新版然後降級安裝成2.11.1版。如果你有某些特殊的函式比需要在R 2.12.2版才能執行，則必須再次安裝最新版的R才行。&lt;br /&gt;&lt;br /&gt;所有的R程式，必須要用"submit /R;"開頭，用"endsubmit;"結尾。而以往在SAS裡面常用的注解符號"*"也必須換成井字符號"#"。在進行資料分析前，得先將SAS資料轉成R可以用的資料格式，可利用下面這段程式碼進行轉檔；&lt;br /&gt;&lt;pre&gt;&lt;code&gt;run ExportDataSetToR("libname.dataname", "R_dataname");&lt;/code&gt;&lt;/pre&gt;其中libname是寫SAS library的名稱，而dataname自然就是SAS資料的名稱。R_dataname則是填入資料集在R裡面所用的名稱。作者建議儘量少用底線當做用在R裡面的資料名稱，因為有可能會出問題。此外，如果是用自定的library，則必須照舊先在一開始用libname語法宣告自定library的路徑。底下的範例因為都是用SAS內部已經建好的Sashelp，所以沒有必要在一開始用libname來宣告。在此需特別注意這一點。以下用幾個範例來說明：&lt;br /&gt;&lt;br /&gt;範例一；表格&lt;br /&gt;這個範例是教如何在SAS裡面使用一些R的指令來整理表格，雖然我覺得SAS在這方面就比R強太多了，但這就是一個範例，程式如下；&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;run ExportDataSetToR("Sashelp.cars",&amp;nbsp;"cars");&lt;br /&gt;submit /R;&lt;br /&gt;library(Hmisc, T); &lt;br /&gt;sink("c/sugi2010/car_summaries.txt");&lt;br /&gt;car.sum &amp;lt;- summary.formula(DriveTrain ~ Type + Origin + MPG_City + MPG_Highway + Weight + Wheelbase + Length, data = cars, method = "reverse", overall = FALSE, test = TRUE,digits = 3, prmsd=TRUE, exclude1 = FALSE, long = TRUE);&lt;br /&gt;print(car.sum, test = TRUE,digits = 3, prmsd=TRUE, exclude1 = FALSE, long = TRUE);&lt;br /&gt;sink();&lt;br /&gt;endsubmit;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;為了顧及一些人不懂R的語法，所以在此稍微解釋一下，之後的範例會省略對R的介紹，有需要的人請自行參照R的線上手冊。&lt;br /&gt;&lt;br /&gt;第一行就是作資料轉檔的語法，剛剛已經介紹過了。本例是拿Sashelp裡面的一個cars的檔案來做表格。"submit /R;"之後開始就全部都是R的語法了，裡面不會有任何SAS程式，直到最後用"endsubmit;"才是回到SAS語法。library()&amp;nbsp;是R裡面呼叫某個package的語法，Hmisc就是專門拿來做summary table的package。sink("....txt") 是先定義接下來所有的報表是要輸出到某txt文件裡面，記得結束要補上"sink();"在最後面才會完成存檔動作。summary.formula()就是製作的函數，裡面要放很多參數，在此就不一一介紹了，總之做完的結果是放在car.sum這個物件裡面。而print()是把car.sum這個物件印進剛剛用sink函數建立的純文字檔。而那個純文字檔打開後如下所示；&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm6.static.flickr.com/5304/5610404074_214cda7e30.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm6.static.flickr.com/5304/5610404074_214cda7e30.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;br /&gt;R繪製出來的圖形相當漂亮，但表格就很陽春，非常像古早PE2打出來的效果。因此這個時候就是SAS展現威能的時候了。用一個data step把那個純文字檔叫進來；&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data cars2;&lt;br /&gt;&amp;nbsp;&amp;nbsp;infile "("c/sugi2010/car_summaries.txt"" dsd dlm="|" &amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; lrecl=1024 firstobs=5 truncover;&lt;br /&gt;&amp;nbsp;&amp;nbsp;format junk $20. label $34. all $34. front $35. rear $35. test $35. ;&lt;br /&gt;&amp;nbsp;&amp;nbsp;input junk $ label $ all $ front $ rear $ test $ ; &lt;br /&gt;&amp;nbsp;&amp;nbsp;if substr(junk,1,1)="+" then delete;&lt;br /&gt;&amp;nbsp;&amp;nbsp;drop junk;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;其中：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;用infile把純文字檔呼叫進SAS，用dlm="|"將每一行分段，用lrecl來定義整行最大長度，並用firstobs指定SAS從第五行開始讀。&lt;/li&gt;&lt;li&gt;用format把剛剛用"|"將每一行切成數段，所以每一段就變成一個變數，因此需要定義變數的格式。在此將所有變數定義成文字格式，因為接下來不用再做分析了，所以只要能列印出及可。&lt;/li&gt;&lt;li&gt;用input設定各變數的名稱，這些名稱要和format裡面所寫的變數名稱一樣。&lt;/li&gt;&lt;li&gt;用junk變數把不必要的隔線刪除掉。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;把不要的內容清乾淨後，用ods和proc report把結果印出來；&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ods rtf file="c:\sugi2010\sas_r\car_summaries2_09oct20b.rtf" ;&lt;br /&gt;title "Summaries by treatment group";&lt;br /&gt;proc report data=cars2 nowindows;&lt;br /&gt;&amp;nbsp;&amp;nbsp;columns label all front rear test;&lt;br /&gt;run; ods rtf close;&lt;/code&gt;&lt;/pre&gt;結果如下；&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm6.static.flickr.com/5108/5610410874_f770aec30c_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm6.static.flickr.com/5108/5610410874_f770aec30c_z.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;br /&gt;範例二；繪圖&lt;br /&gt;在SAS裡面用R畫圖是我比較關心的，但和上面這個範例比起來並沒有太多不同。程式如下；&lt;br /&gt;&lt;pre&gt;&lt;code&gt;run ExportDataSetToR("Sashelp.CARS", "cars");&lt;br /&gt;submit /R;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;library(Hmisc, T); &amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;## Create data frame – cars2 – dropping cars with 3, missing, and 5 cylinders;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;cars2 &amp;lt;- cars[cars$Cylinders&amp;gt;3 &amp;amp; !is.na(cars$Cylinders) &amp;amp; cars$Cylinders != 5,]&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;## place cars2 in search path&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;attach(cars2);&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;## Create summary data sets for Highway and city gas mileage MPG by number of&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;cylinders and origin. &amp;nbsp;;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;## Bootstrap resampling used to calculate 95% confidence intervals of mean;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;mean.hw &amp;lt;- summarize(MPG_Highway, llist(Cylinders, Origin), smean.cl.boot);&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;mean.city &amp;lt;- summarize(MPG_City, llist(Cylinders, Origin), smean.cl.boot);&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;## rename MPG_Highway and MPG_City to common name: &amp;nbsp;mean.mpg.;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;mean.hw2 &amp;lt;- upData(mean.hw, rename=list(MPG_Highway="mean.mpg"));&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;mean.city2 &amp;lt;- upData(mean.city, rename=list(MPG_City="mean.mpg"));&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;##create new variable type to label type of mean.mpg;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;mean.hw2$type[mean.hw2$mean.mpg&amp;gt;0]&amp;lt;- "Highway"&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;mean.city2$type[mean.city2$mean.mpg&amp;gt;0]&amp;lt;- "City"&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;## Vertical combine of the 2 data frames – new dataframe is named all;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;all &amp;lt;- rbind(mean.hw2, mean.city2);&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;## &amp;nbsp;Use Hmisc function xYplot to plot mean gas mileage and 95% confidence intervals;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;## by cylinders with separate panels for each of 3 origins. &amp;nbsp;;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;## groups – separate curves by type within each panel.;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;## col = c(1,2) sets colors for 2 groups (1=black, 2=red). Lty sets line types;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;## layout=c(3,1) &amp;nbsp;determines number of rows and columns – c(3,1) is 3 columns and 1&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;row;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;xYplot(Cbind(mean.mpg, Lower, Upper) ~ Cylinders | Origin, data=all, groups=type,&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;col=c(1,2), lty=c(1,2), layout=c(3,1), type='o');&amp;nbsp;&lt;/span&gt;&lt;br /&gt;endsubmit;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;基本上你只要把前兩行和最後一行先在SAS裡面寫好，然後在第三行前面貼上R的程式即可。不過上面這段用R繪圖的語法，其實在SAS裡面是可以直接做的，下面是兩個軟體畫出來的圖形的比較；&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm6.static.flickr.com/5022/5609833345_ee0e342efd_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm6.static.flickr.com/5022/5609833345_ee0e342efd_z.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;左圖是用R畫出來的圖，右邊是用SAS畫的。乍看之下好像右圖比較好，但那是因為新版的SAS剛好有PROC SGPANEL這個程序把所有繪圖參數都最佳化了，如果遇到PROC SGPANEL沒有支援的圖形，那就不要太指望SAS能給你甚麼好圖了。而根據本人實際測試的結果，其實還是R做的圖比較好看，所以就大膽地在SAS/IML Studio底下執行R的程式吧！&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION &amp;nbsp;&lt;/b&gt;&lt;br /&gt;Name: Jeff Gossett&lt;br /&gt;University of Arkansas for Medical Sciences. Department of Pediatrics.&lt;br /&gt;One Children's Way &lt;br /&gt;Little Rock, AR 72202&lt;br /&gt;Work Phone: 501-364-6631&lt;br /&gt;Fax: 501-364-1431&lt;br /&gt;E-mail: GossettJeffreyM@uams.edu&lt;br /&gt;Web: http://www.arpediatrics.org/research/biostatistics&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-3245684446823300171?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/3245684446823300171/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=3245684446823300171&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/3245684446823300171'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/3245684446823300171'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/04/improving-your-statistical-consulting.html' title='Improving Your Statistical Consulting Prowess by Adding R to Your SAS® Repertoire'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5304/5610404074_214cda7e30_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-7497945167349595128</id><published>2011-04-03T01:23:00.001-04:00</published><updated>2011-04-03T01:39:07.777-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='資料整理'/><title type='text'>So Many Variables; Too Many Labels, Moving Labels from One Variable to Another</title><content type='html'>原文載點：&lt;a href="http://support.sas.com/resources/papers/proceedings10/047-2010.pdf"&gt;http://support.sas.com/resources/papers/proceedings10/047-2010.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;在 SAS 資料處理的過程中，使用者會發現，當複製一個變數並給予新的變數名稱時，舊變數的格式雖然會一併複製到新變數裡面，但舊變數的 label 卻沒有辦法複製過去。若只有一兩個變數時還可以用手動的方式在 data step 裡面重打，但若變數過多時，這就會成為一個相當棘手的問題。John Ladds 提供了一個簡易的方式來解決這個 label 複製的問題。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;以下面這個資料集當作範例：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc format;&lt;br /&gt;&amp;nbsp;&amp;nbsp; value OriginalOrderAgree&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; 1 = 'Strongly agree'&lt;br /&gt;2 = 'Somewhat agree'&lt;br /&gt;3 = 'Neither agree nor disagree'&lt;br /&gt;4 = 'Somewhat disagree'&lt;br /&gt;5 = 'Strongly disagree'&lt;br /&gt;6 = 'Not applicable'&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;97 = "Don't know"&lt;br /&gt;99 = 'Not stated';&lt;br /&gt;&amp;nbsp;&amp;nbsp; value ReverseOrderAgree&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; 5 = 'Strongly agree'&lt;br /&gt;4 = 'Somewhat agree'&lt;br /&gt;3 = 'Neither agree nor disagree'&lt;br /&gt;2 = 'Somewhat disagree'&lt;br /&gt;1 = 'Strongly disagree'&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; other='Missing';&lt;br /&gt;run;&lt;br /&gt;** Create some test data;&lt;br /&gt;data work.theData;&lt;br /&gt;&amp;nbsp;&amp;nbsp; input @01 id &amp;nbsp; &amp;nbsp;$10.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @11 Q001 &amp;nbsp; &amp;nbsp;2.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @13 Q002 &amp;nbsp; &amp;nbsp;2.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @15 Q003 &amp;nbsp; &amp;nbsp;2.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @17 Q004 &amp;nbsp; &amp;nbsp;2.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @19 Q005 &amp;nbsp; &amp;nbsp;2.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @21 Q006 &amp;nbsp; &amp;nbsp;2.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @23 Q007 &amp;nbsp; &amp;nbsp;2.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @25 Q008 &amp;nbsp; &amp;nbsp;2.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @27 Q009 &amp;nbsp; &amp;nbsp;2.&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @29 Q010 &amp;nbsp; &amp;nbsp;2.;&lt;br /&gt;&amp;nbsp;&amp;nbsp; label Q001 = "Have material's and equipment I need";&lt;br /&gt;&amp;nbsp;&amp;nbsp; label Q002 = "Material and tools avail in lang choice";&lt;br /&gt;&amp;nbsp;&amp;nbsp; label Q003 = "I use the language of my choice";&lt;br /&gt;&amp;nbsp;&amp;nbsp; label Q004 = "My jobs fits my interests.";&lt;br /&gt;&amp;nbsp;&amp;nbsp; label Q005 = "I have support at work.";&lt;br /&gt;&amp;nbsp;&amp;nbsp; label Q006 = "I am satisfied, current work arrangement";&lt;br /&gt;&amp;nbsp;&amp;nbsp; label Q007 = "I can claim overtime";&lt;br /&gt;&amp;nbsp;&amp;nbsp; label Q008 = "Overall, I like my job.";&lt;br /&gt;&amp;nbsp;&amp;nbsp; label Q009 = "I get satisfaction from my work.";&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;label Q010 = "I know how my work contributes";&lt;br /&gt;format Q001-Q010 OriginalOrderAgree.;&lt;br /&gt;datalines4;&lt;br /&gt;1234567890 1 2 3 4 5 6 1 2 3 4;&lt;br /&gt;1234567892 2 3 4 5 1 1 2 3 4 5;&lt;br /&gt;1234567893 3 4 5 1 2 2 2 3 5 1;&lt;br /&gt;1234567894 4 5 1 2 3 3 3 3 1 2;&lt;br /&gt;1234567895 5 1 2 3 4 4 4 4 2 3;&lt;br /&gt;1234567896 1 2 3 4 5 5 5 5 3 4;&lt;br /&gt;1234567897 2 3 4 5 1 1 1 1 4 5;&lt;br /&gt;1234567898 3 4 5 1 2 2 2 2 5 1;&lt;br /&gt;1234567899 4 598 2 3 3 3 3 1 2;&lt;br /&gt;123456781099 199 3 4 4 4 5 2 3;&lt;br /&gt;;;;;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;根據這個資料集，裡面有十個變數，從Q001~Q010，每個變數為數據「1,2,3,4,5」。現在假設要製造新變數R_Q001~R_Q010，而這些新變數是將就舊變數的數據倒轉過來，也就是 1 變成 5，2 變成 4，...，5 變成 1。於是作者利用下面這個 macro 來處理這段：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro reverseValueOrder(Q=,Qfmt=);&lt;br /&gt;&amp;nbsp;&amp;nbsp; select(&amp;amp;Q.);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; when(1) &amp;nbsp; R_&amp;amp;Q.=5;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; when(2) &amp;nbsp; R_&amp;amp;Q.=4;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; when(3) &amp;nbsp; R_&amp;amp;Q.=3;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; when(4) &amp;nbsp; R_&amp;amp;Q.=2;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; when(5) &amp;nbsp; R_&amp;amp;Q.=1;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; otherwise R_&amp;amp;Q.=.;&lt;br /&gt;&amp;nbsp;&amp;nbsp; end;&lt;br /&gt;&amp;nbsp;&amp;nbsp; ** Transfer the questions label to the new variable;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;if eof then call execute("label R_&amp;amp;Q.="||'"'||strip(vlabel(&amp;amp;Q.))||'";');&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; ** Add the new value labels to the new variable;&lt;br /&gt;&amp;nbsp;&amp;nbsp; format R_&amp;amp;Q. &amp;amp;Qfmt..;&lt;br /&gt;%mend reverseValueOrder;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;其中，「select(&amp;amp;Q);.....end;」主要就是在做變數倒轉的工作，而下面有一行「if...then...」搭配「call execute」便是在處理 label 複製的動作。裡面的 vlabel 函數的作用是將舊變數裡面的 label 給列出來，放在 strip 函式後面主要是移除不必要的空格，並確保 vlabel 函式叫出來的 label 是字串形式。&lt;br /&gt;&lt;br /&gt;接著就可以在新的 data step 裡面一邊進行數據倒轉的工作，一邊進行搬移 label 的工作，如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data work.thedata;&lt;br /&gt;&amp;nbsp;&amp;nbsp; set work.theData &lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;end=eof&lt;/span&gt;&lt;/b&gt;;&lt;br /&gt;** Open the post DATA STEP Processing;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;if eof then call execute('data &amp;amp;syslast.; set &amp;amp;syslast.;');&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;**A. My Job World &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;;&lt;br /&gt;&amp;nbsp;&amp;nbsp; %reverseValueOrder(Q=Q001, Qfmt=ReverseOrderAgree);&lt;br /&gt;&amp;nbsp;&amp;nbsp; %reverseValueOrder(Q=Q002, Qfmt=ReverseOrderAgree);&lt;br /&gt;&amp;nbsp;&amp;nbsp; %reverseValueOrder(Q=Q003, Qfmt=ReverseOrderAgree);&lt;br /&gt;&amp;nbsp;&amp;nbsp; %reverseValueOrder(Q=Q004, Qfmt=ReverseOrderAgree);&lt;br /&gt;&amp;nbsp;&amp;nbsp; %reverseValueOrder(Q=Q005, Qfmt=ReverseOrderAgree);&lt;br /&gt;&amp;nbsp;&amp;nbsp; %reverseValueOrder(Q=Q006, Qfmt=ReverseOrderAgree);&lt;br /&gt;&amp;nbsp;&amp;nbsp; %reverseValueOrder(Q=Q007, Qfmt=ReverseOrderAgree);&lt;br /&gt;&amp;nbsp;&amp;nbsp; %reverseValueOrder(Q=Q008, Qfmt=ReverseOrderAgree);&lt;br /&gt;&amp;nbsp;&amp;nbsp; %reverseValueOrder(Q=Q009, Qfmt=ReverseOrderAgree);&lt;br /&gt;&amp;nbsp;&amp;nbsp; %reverseValueOrder(Q=Q010, Qfmt=ReverseOrderAgree);&lt;br /&gt;;... ... ... ... ... ... ... ... ... ... ... ** &amp;nbsp;&lt;br /&gt;** Close the post DATA STEP Processing;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: red;"&gt;if eof then call execute ('run;');&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;特別提醒的地方有三個。一是 set 後面一定要加上「end=eof」字樣。二是執行 macro 前加上「if eof then call execute('data &amp;amp;syslast.; set &amp;amp;syslast.;');&amp;nbsp;」，目的是確保程式執行的資料是當前資料。所以記得在運作此程式之前，別去跑其他不相干的資料。三是結束前加上「if eof then call execute ('run;');」，這樣就大功告成了。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&lt;/b&gt;&lt;br /&gt;Name: &amp;nbsp;John Ladds&lt;br /&gt;Enterprise: Statistics Canada – SDD SAS Technology Centre&lt;br /&gt;Address: &amp;nbsp;14-R-90 R.H. Coats Building,&lt;br /&gt;100 Tunney’s Pasture Driveway&lt;br /&gt;Ottawa, Ontario, Canada&lt;br /&gt;K1A 0T6&lt;br /&gt;Phone: &amp;nbsp;613 951-1767&lt;br /&gt;E-mail: John.Ladds@statcan.gc.ca&lt;br /&gt;Web: &amp;nbsp;www.statcan.ca&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-7497945167349595128?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/7497945167349595128/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=7497945167349595128&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/7497945167349595128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/7497945167349595128'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/03/so-many-variables-too-many-labels.html' title='So Many Variables; Too Many Labels, Moving Labels from One Variable to Another'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-5224678573494442305</id><published>2011-03-15T23:12:00.005-04:00</published><updated>2011-05-09T14:23:36.316-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程序語法'/><category scheme='http://www.blogger.com/atom/ns#' term='繪圖技巧'/><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>ROC Hard? No, ROC Made Easy!</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: left;"&gt;原文載點:&amp;nbsp;&lt;a href="http://support.sas.com/resources/papers/proceedings10/222-2010.pdf"&gt;http://support.sas.com/resources/papers/proceedings10/222-2010.pdf&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;SAS 裡面並沒有內建繪製 ROC 曲線的程序和語法，這和目前其他統計軟體都已經內建繪製 ROC 曲線的功能的情況比較起來，顯得相當奇怪。使用者在 SAS 的環境底下，必須先用 PROC LOGISTIC 程序將模型估計出來，再將一些報表另存新的檔案，然後才能根據這些新的資料來繪製 ROC 曲線並且計算 AUC 面積。SAS 官網有一段教學，詳情可參照&amp;nbsp;&lt;a href="http://support.sas.com/kb/25/018.html"&gt;http://support.sas.com/kb/25/018.html&lt;/a&gt;，但繪製出來的圖形不甚美觀。Kriss Harris 在 SAS Global Forum 2010 發表了一篇技術文件，提供了一個相當實用的巨集程式 %ROC_CUTOFF 讓使用者可以在 SAS 裡面迅速且美觀地畫出 ROC 曲線。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;首先，利用一段模擬的資料來當作本篇的範例：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data blood_for_roc;&lt;br /&gt;CALL STREAMINIT(400);  &lt;br /&gt;do i = 1 to 40;&lt;br /&gt;Sputum_Eosinophils = RAND('NORMAL',3, 1); &lt;br /&gt;cht = 1;&lt;br /&gt;output;&lt;br /&gt;end;&lt;br /&gt;do i = 41 to 80;&lt;br /&gt;Sputum_Eosinophils = RAND('NORMAL',10, 5);  &lt;br /&gt;cht = 2;&lt;br /&gt;output;&lt;br /&gt;end;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;%ROC_CUTOFF 的格式如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro roc_cutoff(DATASET = blood_for_roc ,&lt;br /&gt;                  OUTCOME = cht , &lt;br /&gt;                  OUTCOME_LEV = 2 /* Number */ , &lt;br /&gt;                  XVAR = Sputum_Eosinophils,&lt;br /&gt;                  XVAR_LABEL = Sputum Eosinophils,&lt;br /&gt;                  AUC_TABLE = Y,&lt;br /&gt;                  CONFUSION = N,&lt;br /&gt;                  CUTOFF = );&lt;/code&gt;&lt;/pre&gt;每個參數的定義如下：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;DATASET = SAS 資料集名稱&lt;/li&gt;&lt;li&gt;OUTCOME = 類別型的依變數名稱&lt;/li&gt;&lt;li&gt;OUTCOME_LEV = 依變數內的類別數&lt;/li&gt;&lt;li&gt;XVAR = 連續型的應變數名稱&lt;/li&gt;&lt;li&gt;XVAR_LABEL = 應變數的標籤&lt;/li&gt;&lt;li&gt;AUC_TABLE = &amp;nbsp;要不要顯示 AUC 表 (Y/N)&lt;/li&gt;&lt;li&gt;CONFUSION = &amp;nbsp;要不要顯示 confusion 表 (Y/N)&lt;/li&gt;&lt;li&gt;CUTOFF = 指定 cutoff 的數字(可留空白不填)&lt;/li&gt;&lt;/ul&gt;以模擬的資料來跑 ROC：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro roc_cutoff(DATASET = blood_for_roc ,&lt;br /&gt;                  OUTCOME = cht , &lt;br /&gt;                  OUTCOME_LEV = 2 /* Number */ , &lt;br /&gt;                  XVAR = Sputum_Eosinophils,&lt;br /&gt;                  XVAR_LABEL = Sputum Eosinophils,&lt;br /&gt;                  AUC_TABLE = Y,&lt;br /&gt;                  CONFUSION = N,&lt;br /&gt;                  CUTOFF = );&lt;/code&gt;&lt;/pre&gt;結果如下所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm6.static.flickr.com/5022/5703805381_6ca8a50d56_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm6.static.flickr.com/5022/5703805381_6ca8a50d56_z.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;若將CUTOFF 設定成 5，結果如下所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm4.static.flickr.com/3545/5704376612_8956f7776c_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm4.static.flickr.com/3545/5704376612_8956f7776c_z.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;若將 AUC_TABLE 和 CONFUSION 都設定為 N，則一開頭的兩個表格就不會被秀出來：&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm3.static.flickr.com/2169/5704379314_0c6eb771d0_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm3.static.flickr.com/2169/5704379314_0c6eb771d0_z.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;原始碼如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro roc_cutoff(DATASET = blood_for_roc ,&lt;br /&gt;                  OUTCOME = cht , &lt;br /&gt;                  OUTCOME_LEV = 2 /* Number */ , &lt;br /&gt;                  XVAR = Sputum_Eosinophils,&lt;br /&gt;                  XVAR_LABEL = Sputum Eosinophils,&lt;br /&gt;                  AUC_TABLE = Y,&lt;br /&gt;                  CONFUSION = N,&lt;br /&gt;                  CUTOFF = );&lt;br /&gt;;*****************************************************************%&lt;br /&gt;%* GETTING ROC OUTPUT FROM MODEL *;&lt;br /&gt;;*****************************************************************%&lt;br /&gt;%LET OUTCOME_LEV = %SYSFUNC(TRANWRD(&amp;amp;OUTCOME_LEV,%STR(%"),));&lt;br /&gt;%LET OUTCOME_LEV = %SYSFUNC(TRANWRD(&amp;amp;OUTCOME_LEV,%STR(%'),)); &lt;br /&gt;ods output Association = roc_association (WHERE = (UPCASE(LABEL2) = "C"));&lt;br /&gt;proc logistic data=&amp;amp;dataset outest = outest;&lt;br /&gt;model &amp;amp;OUTCOME. (event = "&amp;amp;OUTCOME_LEV.") = &amp;amp;XVAR./EXPB outroc=ROCData;&lt;br /&gt;output out = roctest p = p ;&lt;br /&gt;run;&lt;br /&gt;DATA ROCData;&lt;br /&gt;SET ROCData; &lt;br /&gt;INDEX =1;&lt;br /&gt;RUN;&lt;br /&gt;DATA Outest (KEEP=INTERCEPT &amp;amp;XVAR. INDEX);&lt;br /&gt;SET Outest; &lt;br /&gt;INDEX =1;&lt;br /&gt;RUN;&lt;br /&gt;/* Calculating X value */&lt;br /&gt;DATA _merge;&lt;br /&gt;MERGE ROCData Outest;&lt;br /&gt;BY INDEX;&lt;br /&gt;SPEC = 1-_1MSPEC_;&lt;br /&gt;YI = (_SENSIT_ + SPEC) - 1;&lt;br /&gt;N = _POS_+ _NEG_+ _FALPOS_+ _FALNEG_;&lt;br /&gt;TA = (_POS_ + _NEG_)/N;&lt;br /&gt;X_VALUE = (LOG(_PROB_/(1-_PROB_))-INTERCEPT)/&amp;amp;XVAR.;&lt;br /&gt;IF (_NEG_+_FALNEG_) NE 0 THEN DO;&lt;br /&gt;NPV = _NEG_/(_NEG_ +_FALNEG_);&lt;br /&gt;END;&lt;br /&gt;IF (_POS_+_FALPOS_) NE 0 THEN DO;&lt;br /&gt;PPV = _POS_/(_POS_ +_FALPOS_);&lt;br /&gt;END;&lt;br /&gt;IF&lt;br /&gt;((_POS_+_FALPOS_)*(_POS_+_FALNEG_)*(_NEG_+_FALPOS_)*(_NEG_+_FALNEG_)) NE 0&lt;br /&gt;THEN DO;&lt;br /&gt;MCC = ((_POS_*_NEG_)-(_FALPOS_*_FALNEG_))/&lt;br /&gt;SQRT(((_POS_+_FALPOS_)*(_POS_+_FALNEG_)*(_NEG_+_FALPOS_)*(_NEG_+_FALNEG_)));&lt;br /&gt;END;&lt;br /&gt;RUN;&lt;br /&gt;/* Merging in the original data, so that this can be plotted to */&lt;br /&gt;proc sql;&lt;br /&gt;create table merge2 as&lt;br /&gt;select a.*, b.&amp;amp;XVAR. as XVAR1, b.&amp;amp;OUTCOME., b.p,&lt;br /&gt;case when b.&amp;amp;OUTCOME. = &amp;amp;OUTCOME_LEV. then 3&lt;br /&gt;else 4 end as Index1&lt;br /&gt;from _merge as a right join Roctest as b&lt;br /&gt;on a._PROB_ = b.p ;&lt;br /&gt;quit;&lt;br /&gt;data merge3;&lt;br /&gt;set merge2;&lt;br /&gt;string_check = anyalpha(&amp;amp;OUTCOME.);&lt;br /&gt;if string_check = 0 then &amp;amp;OUTCOME._char = strip(put(&amp;amp;OUTCOME., best.))&lt;br /&gt;;&lt;br /&gt;else &amp;amp;OUTCOME. = &amp;amp;OUTCOME._char;&lt;br /&gt;run;&lt;br /&gt;;*****************************************************************%&lt;br /&gt;%* CALCULATING X Value CUT-OFFS for Particular Specificities and &lt;br /&gt;Sensitivities and Vice Versa *;&lt;br /&gt;;*****************************************************************%&lt;br /&gt;proc sql;&lt;br /&gt;create table One_Hundred_PC_Sens as&lt;br /&gt;select max(X_VALUE) as max_x format 10.2&lt;br /&gt;from _merge&lt;br /&gt;where _SENSIT_ = 1;&lt;br /&gt;quit;&lt;br /&gt;proc sql;&lt;br /&gt;create table sens_spec as&lt;br /&gt;select *, abs(_SENSIT_ - SPEC) as abs_sens_spec, min(calculated abs_sens_spec) as min&lt;br /&gt;from _merge;&lt;br /&gt;quit;&lt;br /&gt;&lt;br /&gt;proc sql;&lt;br /&gt;create table sens_spec_intersection as&lt;br /&gt;select X_VALUE format 10.2&lt;br /&gt;from sens_spec &lt;br /&gt;where abs_sens_spec = min;&lt;br /&gt;quit;&lt;br /&gt;proc sql;&lt;br /&gt;create table One_Hundred_PC_Spec as&lt;br /&gt;select min(X_VALUE) as min_x format 10.2&lt;br /&gt;from _merge&lt;br /&gt;where spec = 1;&lt;br /&gt;quit;&lt;br /&gt;/* Fetching the values */&lt;br /&gt;%let dsid=%sysfunc(open(Roc_association,i));&lt;br /&gt;%let num_AUC=%sysfunc(varnum(&amp;amp;dsid,nValue2));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let AUC=%sysfunc(getvarn(&amp;amp;dsid,&amp;amp;num_AUC));&lt;br /&gt;%let AUC_format=%sysfunc(putn(&amp;amp;AUC,bestd10.2));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%let dsid=%sysfunc(open(One_Hundred_PC_Sens,i));&lt;br /&gt;%let num_Sens=%sysfunc(varnum(&amp;amp;dsid,max_x));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let Sens=%sysfunc(getvarn(&amp;amp;dsid,&amp;amp;num_Sens));&lt;br /&gt;%let Sens_format=%sysfunc(putn(&amp;amp;Sens,bestd10.2));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%let dsid=%sysfunc(open(One_Hundred_PC_Spec,i));&lt;br /&gt;%let num_Spec=%sysfunc(varnum(&amp;amp;dsid,min_x));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let Spec=%sysfunc(getvarn(&amp;amp;dsid,&amp;amp;num_Spec));&lt;br /&gt;%let Spec_format=%sysfunc(putn(&amp;amp;Spec,bestd10.2));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%let dsid=%sysfunc(open(sens_spec_intersection,i));&lt;br /&gt;%let num_section=%sysfunc(varnum(&amp;amp;dsid,X_VALUE));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let section=%sysfunc(getvarn(&amp;amp;dsid,&amp;amp;num_section));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%if &amp;amp;CUTOFF = %NRSTR() %then %do;&lt;br /&gt;%let section2 = §ion;&lt;br /&gt;%let section_format=%sysfunc(putn(§ion2,bestd10.2));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%end;&lt;br /&gt;%else %do;&lt;br /&gt;%let section2 = &amp;amp;CUTOFF;&lt;br /&gt;%let section_format = &amp;amp;CUTOFF;&lt;br /&gt;%end;&lt;br /&gt;;*****************************************************************%&lt;br /&gt;%* 2*2 Tables *;&lt;br /&gt;;*****************************************************************%&lt;br /&gt;data freq_input;&lt;br /&gt;set merge3;&lt;br /&gt;if XVAR1 ne .;&lt;br /&gt;if XVAR1 &amp;lt;=  §ion2 then new_result = 1;&lt;br /&gt;else new_result = 0;&lt;br /&gt;run;&lt;br /&gt;ods output  CrossTabFreqs =  CrossTabFreqs;&lt;br /&gt;proc freq data = freq_input;&lt;br /&gt;tables new_result * &amp;amp;OUTCOME._char / NOROW NOCOL;&lt;br /&gt;run;&lt;br /&gt;data crossTabFreqs_ref;&lt;br /&gt;set CrossTabFreqs;&lt;br /&gt;if &amp;amp;OUTCOME._char ne "";&lt;br /&gt;if new_result ne .;&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;data TP;&lt;br /&gt;set CrossTabFreqs_ref;&lt;br /&gt;if new_result = 0 and &amp;amp;OUTCOME._char = &amp;amp;OUTCOME_LEV.;&lt;br /&gt;run;&lt;br /&gt;data FP;&lt;br /&gt;set CrossTabFreqs_ref;&lt;br /&gt;if new_result = 0 and &amp;amp;OUTCOME._char ne &amp;amp;OUTCOME_LEV.;&lt;br /&gt;run;&lt;br /&gt;data FN;&lt;br /&gt;set CrossTabFreqs_ref;&lt;br /&gt;if new_result = 1 and &amp;amp;OUTCOME._char = &amp;amp;OUTCOME_LEV.;&lt;br /&gt;run;&lt;br /&gt;data TN;&lt;br /&gt;set CrossTabFreqs_ref;&lt;br /&gt;if new_result = 1 and &amp;amp;OUTCOME._char ne &amp;amp;OUTCOME_LEV.;&lt;br /&gt;run;&lt;br /&gt;/* Fetching the values */&lt;br /&gt;%let dsid=%sysfunc(open(TP,i));&lt;br /&gt;%let num_TP=%sysfunc(varnum(&amp;amp;dsid,Frequency));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let TP=%sysfunc(getvarn(&amp;amp;dsid,&amp;amp;num_TP));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%let dsid=%sysfunc(open(FP,i));&lt;br /&gt;%let num_FP=%sysfunc(varnum(&amp;amp;dsid,Frequency));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let FP=%sysfunc(getvarn(&amp;amp;dsid,&amp;amp;num_FP));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%let dsid=%sysfunc(open(FN,i));&lt;br /&gt;%let num_FN=%sysfunc(varnum(&amp;amp;dsid,Frequency));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let FN=%sysfunc(getvarn(&amp;amp;dsid,&amp;amp;num_FN));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%let dsid=%sysfunc(open(TN,i));&lt;br /&gt;%let num_TN=%sysfunc(varnum(&amp;amp;dsid,Frequency));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let TN=%sysfunc(getvarn(&amp;amp;dsid,&amp;amp;num_TN));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%let dsid=%sysfunc(open(TP,i));&lt;br /&gt;%let num_TP_per=%sysfunc(varnum(&amp;amp;dsid,Percent));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let TP_per=%sysfunc(getvarn(&amp;amp;dsid,&amp;amp;num_TP_per));&lt;br /&gt;%let TP_format=%sysfunc(putn(&amp;amp;TP_per,best3.0));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%let dsid=%sysfunc(open(FP,i));&lt;br /&gt;%let num_FP_per=%sysfunc(varnum(&amp;amp;dsid,Percent));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let FP_per=%sysfunc(getvarn(&amp;amp;dsid,&amp;amp;num_FP_per));&lt;br /&gt;%let FP_format=%sysfunc(putn(&amp;amp;FP_per,best3.0));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%let dsid=%sysfunc(open(FN,i));&lt;br /&gt;%let num_FN_per=%sysfunc(varnum(&amp;amp;dsid,Percent));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let FN_per=%sysfunc(getvarn(&amp;amp;dsid,&amp;amp;num_FN_per));&lt;br /&gt;%let FN_format=%sysfunc(putn(&amp;amp;FN_per,best3.0));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%let dsid=%sysfunc(open(TN,i));&lt;br /&gt;%let num_TN_per=%sysfunc(varnum(&amp;amp;dsid,Percent));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let TN_per=%sysfunc(getvarn(&amp;amp;dsid,&amp;amp;num_TN_per));&lt;br /&gt;%let TN_format=%sysfunc(putn(&amp;amp;TN_per,best3.0));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;/* Selecting distinct OUTCOME values */&lt;br /&gt;&lt;br /&gt;proc sql;&lt;br /&gt;create table distinct_values as&lt;br /&gt;select distinct &amp;amp;OUTCOME.&lt;br /&gt;from &amp;amp;dataset;&lt;br /&gt;quit; &lt;br /&gt;data LEVEL NOTLEVEL;&lt;br /&gt;  set distinct_values;&lt;br /&gt;   if  &amp;amp;OUTCOME. =  UPCASE(&amp;amp;OUTCOME_LEV.) then output LEVEL;&lt;br /&gt;else OUTPUT NOTLEVEL;   &lt;br /&gt;run;&lt;br /&gt;/* Turning it to character if it's not */&lt;br /&gt;data level_char;&lt;br /&gt;set level;&lt;br /&gt;string_check = anyalpha(&amp;amp;OUTCOME.);&lt;br /&gt;if string_check = 0 then &amp;amp;OUTCOME._char2 = strip(put(&amp;amp;OUTCOME., best.))&lt;br /&gt;;&lt;br /&gt;else &amp;amp;OUTCOME. = &amp;amp;OUTCOME._char2;&lt;br /&gt;run;&lt;br /&gt;data notlevel_char;&lt;br /&gt;set notlevel;&lt;br /&gt;string_check = anyalpha(&amp;amp;OUTCOME.);&lt;br /&gt;if string_check = 0 then &amp;amp;OUTCOME._char2 = strip(put(&amp;amp;OUTCOME., best.))&lt;br /&gt;;&lt;br /&gt;else &amp;amp;OUTCOME. = &amp;amp;OUTCOME._char2;&lt;br /&gt;run;&lt;br /&gt;/* Fetching the distinct levels */&lt;br /&gt;%let dsid=%sysfunc(open(level_char,i));&lt;br /&gt;%let num_level=%sysfunc(varnum(&amp;amp;dsid,&amp;amp;OUTCOME._char2));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let level=%sysfunc(getvarc(&amp;amp;dsid,&amp;amp;num_level));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;%let dsid=%sysfunc(open(notlevel_char,i));&lt;br /&gt;%let num_notlevel=%sysfunc(varnum(&amp;amp;dsid,&amp;amp;OUTCOME._char2));&lt;br /&gt;%let rc=%sysfunc(fetch(&amp;amp;dsid,1));&lt;br /&gt;%let notlevel=%sysfunc(getvarc(&amp;amp;dsid,&amp;amp;num_notlevel));&lt;br /&gt;%let rc=%sysfunc(close(&amp;amp;dsid));&lt;br /&gt;/* Plot */&lt;br /&gt;ods html style = statistical;&lt;br /&gt;proc template;&lt;br /&gt;define statgraph sgplot;&lt;br /&gt;mvar OUTCOME_TITLE OUTCOME_LEV OUTCOME AUC Sens Section2 Specif level notlevel confusion &lt;br /&gt;auc_table&lt;br /&gt;XVAR_LABEL  TP FP FN TN TP_per FP_per FN_per TN_per Sensitivity Specificity; &lt;br /&gt;dynamic XVAR1 YVAR1;&lt;br /&gt;begingraph;&lt;br /&gt;EntryTitle "Operating Characterisitcs for " OUTCOME_TITLE " = " OUTCOME_LEV /;&lt;br /&gt;if (confusion = "Y") &lt;br /&gt;EntryFootnote textattrs=(color = red )"*" textattrs=()"Confusion Matrix is for the "&lt;br /&gt;XVAR_LABEL " at the cutoff = " textattrs=(color = blue ) Section2 ; &lt;br /&gt;*EntryFootnote "At cutoff, Sensitivity = " textattrs=(color = blue ) Sensitivity " and &lt;br /&gt;Specificity = " textattrs=(color = blue ) Specificity  ;&lt;br /&gt;endif;&lt;br /&gt;layout lattice / columns=1 rows=2  rowgutter=2px columngutter=2px&lt;br /&gt;                        rowweights=(.7 .3 );&lt;br /&gt;       columnaxes;&lt;br /&gt;         columnaxis / label=XVAR_LABEL;&lt;br /&gt;endcolumnaxes;&lt;br /&gt;    sidebar / align=right; &lt;br /&gt;      layout gridded / border = false; &lt;br /&gt;layout overlay;&lt;br /&gt;&lt;br /&gt;DiscreteLegend "SERIES" "SERIES1" / location = outside ACROSS = 1 down &lt;br /&gt;= 2; &lt;br /&gt;endlayout; &lt;br /&gt;layout overlay;&lt;br /&gt;*DiscreteLegend "SERIES3" / location = outside;&lt;br /&gt;endlayout; &lt;br /&gt;endlayout; &lt;br /&gt;     &lt;br /&gt;    endsidebar; &lt;br /&gt;layout overlay / cycleattrs=true xaxisopts = (Label = XVAR_LABEL) yaxisopts=( &lt;br /&gt;Label="Proportion" type=linear linearopts=( tickvaluelist=( 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8&lt;br /&gt;0.9 1 ) viewmin=0 viewmax=1 ) );&lt;br /&gt;    StepPlot X=X_VALUE Y=SPEC / primary=true LegendLabel="Specificity" NAME="SERIES";&lt;br /&gt;StepPlot X=X_VALUE Y=_SENSIT_ / LegendLabel="Sensitivity" NAME="SERIES1";&lt;br /&gt;Referenceline x =  Section2 / LINEATTRS = (color = black pattern = 2);&lt;br /&gt;if (confusion = "Y") &lt;br /&gt;/* 2 by 2 */&lt;br /&gt;layout gridded /  columns=3 rows = 3&lt;br /&gt;         halign = CENTER valign = top border=true &lt;br /&gt;opaque=true backgroundcolor=GraphWalls:color location = outside; &lt;br /&gt;entry halign=center " " / textattrs=GraphValueText; &lt;br /&gt;       entry halign=center level  / textattrs=(WEIGHT=bold) /* Setting the titles to bold */  &lt;br /&gt; ;&lt;br /&gt;entry halign=center notlevel  / textattrs=(WEIGHT=bold); &lt;br /&gt;   entry halign=center "Event" / textattrs=(WEIGHT=bold) ; &lt;br /&gt;entry halign=center TP textattrs=(STYLE=ITALIC color = blue )"(" TP_per "%)" /* &lt;br /&gt;Formatting the percentages */ ; &lt;br /&gt;entry halign=center FP textattrs=(STYLE=ITALIC color = blue )"(" FP_per "%)" ; &lt;br /&gt;entry halign=center "Non Event" / textattrs=(WEIGHT=bold); &lt;br /&gt;      entry halign=center FN  textattrs=(STYLE=ITALIC color = blue )"(" FN_per "%)"; &lt;br /&gt;       entry halign=center TN textattrs=(STYLE=ITALIC color = blue )"(" TN_per "%)"; &lt;br /&gt;    &lt;br /&gt;endlayout;&lt;br /&gt;endif;&lt;br /&gt;if (auc_table = "Y") &lt;br /&gt;layout gridded / columns=4 rows = 1&lt;br /&gt;         halign = center valign = top border=true &lt;br /&gt;opaque=true backgroundcolor=GraphWalls:color location = outside; &lt;br /&gt;entry halign=center "AUC " / textattrs=(WEIGHT=bold); &lt;br /&gt;       entry halign=center "100% Sensitivity: " / textattrs=(WEIGHT=bold); &lt;br /&gt;entry halign=center "Intersection: "  / textattrs=(WEIGHT=bold); &lt;br /&gt;   entry halign=center "100% Specificity: " / textattrs=(WEIGHT=bold) ; &lt;br /&gt;entry halign=center AUC; &lt;br /&gt;      entry halign=center Sens; &lt;br /&gt;       entry halign=center Section2; &lt;br /&gt;entry halign=center Specif ; &lt;br /&gt;endlayout;&lt;br /&gt;&lt;br /&gt;endif;&lt;br /&gt;*DiscreteLegend "SERIES" "SERIES1" / location = outside;&lt;br /&gt;endlayout;&lt;br /&gt;layout lattice / columns=1 rows=2  rowgutter=2px columngutter=2px&lt;br /&gt;                        rowweights=(.5 .5 ) COLUMNDATARANGE = Union;&lt;br /&gt;columnaxes;&lt;br /&gt;         columnaxis / label=XVAR_LABEL;&lt;br /&gt;       endcolumnaxes;&lt;br /&gt;    layout gridded / AUTOALIGN=NONE  columns=3 rows = 3&lt;br /&gt;         halign = right valign = top border=true &lt;br /&gt;opaque=true backgroundcolor=GraphWalls:color location = outside; &lt;br /&gt;endlayout;&lt;br /&gt;layout overlay /   yaxisopts=( Label=" " );&lt;br /&gt;Scatterplot x=XVAR1 y = OUTCOME / group = OUTCOME INDEX = Index1 NAME = &lt;br /&gt;"SERIES3";&lt;br /&gt;Referenceline x =  Section2 / LINEATTRS = (color = black pattern = 2);&lt;br /&gt;endlayout;&lt;br /&gt;layout overlay /   yaxisopts=( Label=" " );&lt;br /&gt;Boxplot y = XVAR1 x = OUTCOME / ORIENT = horizontal;&lt;br /&gt;Referenceline x =  Section2 / LINEATTRS = (color = black pattern = 2);&lt;br /&gt;endlayout;&lt;br /&gt;endlayout;&lt;br /&gt;endlayout;&lt;br /&gt;endgraph;&lt;br /&gt;end;&lt;br /&gt;run;&lt;br /&gt;%let OUTCOME_TITLE = &amp;amp;OUTCOME;&lt;br /&gt;%let OUTCOME_LEV = &amp;amp;OUTCOME_LEV;&lt;br /&gt;%let OUTCOME =  &amp;amp;OUTCOME._char;&lt;br /&gt;%let AUC =  &amp;amp;AUC_format;&lt;br /&gt;%let Sens =  &amp;amp;Sens_format;&lt;br /&gt;%let Section2 = &amp;amp;Section_format;&lt;br /&gt;%let Specif =  &amp;amp;Spec_format;&lt;br /&gt;%let level = &amp;amp;level;&lt;br /&gt;%let notlevel = ¬level;&lt;br /&gt;%let confusion = &amp;amp;confusion;&lt;br /&gt;%let auc_table = &amp;amp;auc_table;&lt;br /&gt;%let XVAR_LABEL = &amp;amp;XVAR_LABEL;&lt;br /&gt;%let TP = &amp;amp;TP;&lt;br /&gt;%let FP = &amp;amp;FP;&lt;br /&gt;%let FN = &amp;amp;FN;&lt;br /&gt;%let TN = &amp;amp;TN;&lt;br /&gt;%let TP_per = &amp;amp;TP_format;&lt;br /&gt;%let FP_per = &amp;amp;FP_format;&lt;br /&gt;%let FN_per = &amp;amp;FN_format;&lt;br /&gt;%let TN_per = &amp;amp;TN_format;&lt;br /&gt;ods listing sge = on;&lt;br /&gt;proc sgrender data=merge3 template=sgplot;&lt;br /&gt;dynamic XVAR1 = "XVAR1" YVAR1 = "YVAR1";&lt;br /&gt;run;&lt;br /&gt;ods listing close;&lt;br /&gt;proc sql;&lt;br /&gt;drop table roc_association, Roctest, ROCData, Outest, _merge, merge2, merge3, &lt;br /&gt;One_Hundred_PC_Sens, &lt;br /&gt;sens_spec, sens_spec_intersection, One_Hundred_PC_Spec, freq_input,&lt;br /&gt;CrossTabFreqs, crossTabFreqs_ref, TP, FP, FN, TN, distinct_values, &lt;br /&gt;LEVEL, NOTLEVEL, level_char, notlevel_char;&lt;br /&gt;quit;&lt;br /&gt;%mend roc_cutoff;&lt;/code&gt;&lt;/pre&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Your comments and questions are valued and encouraged. Please contact the author at:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Kriss Harris&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;GlaxoSmithKline&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Mail Stop : 1B106003&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Gunnels Wood Road&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Stevenage SG1 2NY&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Phone: 01438 76 4904&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Email: Kriss.5.Harris@gsk.com&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Web: http://www.krissharris.co.uk&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-5224678573494442305?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/5224678573494442305/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=5224678573494442305&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/5224678573494442305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/5224678573494442305'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/03/roc-hard-no-roc-made-easy.html' title='ROC Hard? No, ROC Made Easy!'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5022/5703805381_6ca8a50d56_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-6043539532481275182</id><published>2011-03-07T12:09:00.006-04:00</published><updated>2011-04-09T15:46:55.607-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>A Macro to Create a Batch Submit SAS Program</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: left;"&gt;原文載點:&amp;nbsp;http://support.sas.com/resources/papers/proceedings10/092-2010.pdf&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;在一些很特殊的情況下，我們需要大量執行不同的 SAS 程式。若一個一個從 SAS 裡面開啟再執行，不但相當消耗時間，也不沒有太大的效率。Helen Sun 和 Cindy Wong 在 SAS Global Forum 2010 發表了一個簡易的巨集程式，讓 SAS 使用者在 PC 的視窗系統底下可以輕鬆批次地將同一個目錄底下的 SAS 程式碼給一次執行完畢。&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;a name='more'&gt;&lt;/a&gt;假設有一堆 SAS 程式被儲存在 C:\temp 的目錄底下，如下圖所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://s3.amazonaws.com/diigo/thumbnail_550/2043829_68736687_3115713.jpg?AWSAccessKeyId=0R7FMW7AXRVCYMAPTPR2&amp;amp;Expires=1302378632&amp;amp;Signature=jvtJKfcuZoXd8plzGWp6looVyOg%3D" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://s3.amazonaws.com/diigo/thumbnail_550/2043829_68736687_3115713.jpg?AWSAccessKeyId=0R7FMW7AXRVCYMAPTPR2&amp;amp;Expires=1302378632&amp;amp;Signature=jvtJKfcuZoXd8plzGWp6looVyOg%3D" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;先執行以下的巨集程式一次：&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;pre&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;%MACRO BATCH(dir=);&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;/*read in file names*/&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;FILENAME dirfile PIPE "dir ""&amp;amp;dir"" /b" LRECL=200;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;DATA in;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;INFILE dirfile LENGTH=len;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;INPUT char $varying200. len;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;RUN;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; /*only choose sas program names*/&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; DATA sasprg;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; SET in;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; IF INDEX(char,'.sas ');&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; RUN;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; /*create statement*/&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; DATA line;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; LENGTH name $200;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; SET sasprg;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; name="%include '"||trim(char)||"';";&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; DROP char;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; RUN;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; /*write out to a file*/&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; FILENAME fileref "&amp;amp;dir.batch.sas";&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; DATA _null_;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; SET line;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; FILE fileref;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; PUT name;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; RUN;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; FILENAME fileref clear;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;&amp;nbsp; %MEND;&amp;nbsp;&lt;/code&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;然後再把路徑輸進 %BATCH 裡面：&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;code&gt;&amp;nbsp;%BATCH(dir=C:\temp\);&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;接著就會在這個路徑看到一個名為 batch.sas 的程式，打開來一看如下所示：&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://s3.amazonaws.com/diigo/thumbnail_550/2043829_68736942_3115719.jpg?AWSAccessKeyId=0R7FMW7AXRVCYMAPTPR2&amp;amp;Expires=1302378691&amp;amp;Signature=vSQPxl7tuz2s2aEBZ3VhEseSvlM%3D" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://s3.amazonaws.com/diigo/thumbnail_550/2043829_68736942_3115719.jpg?AWSAccessKeyId=0R7FMW7AXRVCYMAPTPR2&amp;amp;Expires=1302378691&amp;amp;Signature=vSQPxl7tuz2s2aEBZ3VhEseSvlM%3D" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;也就是說 %BATCH 幫使用者把該路徑底下的程式名稱一一放進 %include 裡面，然後我們就可以直接執行 batch.sas 這個程式來批次執行該目錄底下所有 SAS 程式。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION &lt;/b&gt;&lt;br /&gt;Helen Sun&lt;br /&gt;SAS Programmer&lt;br /&gt;hsun@robarts.ca&lt;br /&gt;Robarts Clinical Trials&lt;br /&gt;Robarts Research Institute&lt;br /&gt;&amp;nbsp;P.O. Box 5015, 100 Perth Drive&lt;br /&gt;London, Ontario, Canada&lt;br /&gt;N6A 5K8&lt;br /&gt;Tel: 519-931-5700x24254&lt;br /&gt;Fax: &lt;span class="gc-cs-link" id="gc-number-3" title="Call with Google Voice"&gt;519-931-5284&lt;/span&gt;&lt;br /&gt;www.robartsclinicaltrials.ca&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-6043539532481275182?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/6043539532481275182/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=6043539532481275182&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6043539532481275182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6043539532481275182'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/03/macro-to-create-batch-submit-sas.html' title='A Macro to Create a Batch Submit SAS Program'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-3815342343925602042</id><published>2011-02-25T17:02:00.003-04:00</published><updated>2011-06-09T12:20:29.055-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>Disagreement on Agreement: Two Alternative Agreement Coefficients</title><content type='html'>原文載點：&lt;a href="http://www2.sas.com/proceedings/forum2007/186-2007.pdf"&gt;http://www2.sas.com/proceedings/forum2007/186-2007.pdf&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Kappa一致性係數是用來評量許多評分者對某一類別變數評分是否具有一致性的指標。根據公式，它是實際評定一致的次數百分比與評分者理論上評定的最大可能次數百分比的比率。但是近年來有越來越多的學者發現這個指標的不完美處。於是有許多替代性的指標被研究出來，以克服Kappa一致性係數的缺點。然而SAS並沒有對這些新的一致性指標的程式語法更新至新版的SAS中。也許我們可以期待新的一致性係數會在不久的將來被納入到SAS內建的語法，但畢竟SAS改版的頻率並沒有很高，所以還是用自製的巨集程式比較有效率。本篇教學文件主要是介紹由Kilem Gwet所發表的一階和二階一致性係數(first-order and second order agreement coefficient，簡稱AC1和AC2)在SAS裡面如何操作。其巨集程式由 Emily Blood 和 Kevin Spratt 編寫，並發表於 2007 SAS Global Forum 上。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;AC1和AC2的分別在於，AC1是使用任意的類別評分工具下的一致性係數，而AC2是使用已經排序好的類別平分工具下的一致性係數。其理論背景可參照原文。本文主要介紹巨集程式 %AC1AC2 的使用方式。&lt;br /&gt;&lt;br /&gt;巨集語法如下:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp;%AC1AC2(dataset=,numcategories=,betadata=)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;內含三個參數，分別為:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;dataset: 使用SAS資料檔的名稱&lt;/li&gt;&lt;li&gt;numcategories: 評量工具內的等級數量，假設評分標準是1,2,3,4,5，則此參數並須設定為"5"&lt;/li&gt;&lt;li&gt;betadata: 錯誤分類機率矩陣的SAS資料檔名稱，主要是拿來計算AC2之用&lt;/li&gt;&lt;/ol&gt;用一個範例來看執行結果:&lt;br /&gt;&lt;br /&gt;資料:&lt;br /&gt;&lt;br /&gt;&lt;pre style="white-space: pre-wrap; word-wrap: break-word;"&gt;&lt;code&gt;DATA work.one;&lt;br /&gt; INPUT r1 r2 r3 r4 r5 r6;&lt;br /&gt;CARDS;&lt;br /&gt; 4 4 4 4 4 4&lt;br /&gt; 2 2 5 2 5 5&lt;br /&gt; 3 3 5 2 3 3&lt;br /&gt; 5 5 5 5 5 5&lt;br /&gt; 2 4 2 4 4 2&lt;br /&gt; 1 3 3 3 1 3&lt;br /&gt; 3 5 3 3 5 3&lt;br /&gt; 1 1 3 3 3 4&lt;br /&gt; 4 4 4 4 1 1&lt;br /&gt; 5 5 5 5 5 5&lt;br /&gt; 1 4 4 4 4 4&lt;br /&gt; 1 4 2 4 4 4&lt;br /&gt; 2 3 2 2 3 3&lt;br /&gt; 4 1 4 4 4 4&lt;br /&gt; 2 2 4 4 4 5&lt;br /&gt; 3 3 5 3 3 3&lt;br /&gt; 5 5 1 1 1 4&lt;br /&gt; 1 1 1 1 2 1&lt;br /&gt; 2 2 4 4 4 4&lt;br /&gt; 1 3 3 5 5 5&lt;br /&gt; 5 5 5 5 5 5&lt;br /&gt; 4 4 2 4 4 4&lt;br /&gt; 5 2 5 5 4 2&lt;br /&gt; 1 4 4 4 1 4&lt;br /&gt; 5 4 4 4 4 1&lt;br /&gt; 2 4 2 2 2 2&lt;br /&gt; 1 5 1 1 1 5&lt;br /&gt; 4 2 4 4 4 2&lt;br /&gt; 1 3 3 3 3 3&lt;br /&gt; 5 5 5 5 5 5&lt;br /&gt;;&lt;br /&gt;RUN;&lt;br /&gt;&lt;br /&gt;data work.beta;&lt;br /&gt;input cat1 cat2 cat3 cat4 cat5 ;&lt;br /&gt;cards;&lt;br /&gt;.9  .9 .2 .1 0&lt;br /&gt;.05 .1 .8 .7 0&lt;br /&gt;.03  0  0 .1 0&lt;br /&gt;.01  0  0 .1 0&lt;br /&gt;.01  0  0  0 1&lt;br /&gt;;&lt;br /&gt;RUN;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;第一筆資料『one』為原始資料，包含六名心理學家對患有某種心理疾病的病人所做的評量，分數從1~5。第二筆資料『beta』裝有錯誤分類的機率資料，代表了不一致性發生時的嚴重程度。其矩陣表示法如下所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-5dXJXJlxl24/TfDyN-KQg_I/AAAAAAAAF6A/_2a63xmAdvw/s1600/www2.sas.com-proceedings-forum2007-186-2007.pdf.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-5dXJXJlxl24/TfDyN-KQg_I/AAAAAAAAF6A/_2a63xmAdvw/s1600/www2.sas.com-proceedings-forum2007-186-2007.pdf.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;其中『a|b』表示當原先評分為 b 時，之後評分變成 a 。因此，很明顯的，對角線的數據即表示具有一致評分的機率，而非對角線的數據即表示不一致評分的機率。特別要注意的是，設定這個矩陣的SAS資料集時，每一欄的總和一定要等於1。這個矩陣只有拿來運算AC2，在AC1的公式裡面並不包含這個矩陣。&lt;br /&gt;&lt;br /&gt;設定好參數並執行巨集，則會在SAS output視窗上面看到&amp;nbsp;AC1 和 AC2 各有五個數據出現，從左到右分別是一致性係數值(Agree Stat)、條件變異數(CondVar)、非條件變異數(UncondVar)、評分者評定一致的百分比(PA)以及評分者理論上評定一致的百分比(PE)。&lt;br /&gt;&lt;br /&gt;原始巨集碼可至這個網址下載：&lt;a href="http://mcrc.hitchcock.org/SASMacros/Agreement/AC1AC2.txt"&gt;http://mcrc.hitchcock.org/SASMacros/Agreement/AC1AC2.txt&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;CONTACT INFORMATION&lt;br /&gt;Your comments and questions are valued and encouraged. &amp;nbsp;Contact the authors at:&lt;br /&gt;Emily A. Blood or Kevin F. Spratt&lt;br /&gt;Department of Orthopedic Surgery&lt;br /&gt;Dartmouth Medical School&lt;br /&gt;One Medical Center Drive&lt;br /&gt;Hanover, NH 03756&lt;br /&gt;Work Phone: 603-653-6019&lt;br /&gt;E-mail: Emily.a.blood@dartmouth.edu or Kevin.F.Spratt@dartmouth.edu&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-3815342343925602042?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/3815342343925602042/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=3815342343925602042&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/3815342343925602042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/3815342343925602042'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2011/02/disagreement-on-agreement-two.html' title='Disagreement on Agreement: Two Alternative Agreement Coefficients'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-5dXJXJlxl24/TfDyN-KQg_I/AAAAAAAAF6A/_2a63xmAdvw/s72-c/www2.sas.com-proceedings-forum2007-186-2007.pdf.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-1413090291924213562</id><published>2010-08-02T10:06:00.001-04:00</published><updated>2010-08-02T10:52:15.509-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程序語法'/><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>Automatically Run Fisher's Exact Test When the Chi-square Test Might Not Be Valid</title><content type='html'>Link:&amp;nbsp;&lt;a href="https://docs.google.com/viewer?url=http%3A%2F%2Fsupport.sas.com%2Fresources%2Fpapers%2Fproceedings10%2F096-2010.pdf"&gt;http://support.sas.com/resources/papers/proceedings10/096-2010.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;在使用PROC FREQ執行卡方檢定時，如果看到列聯表下面出現warning的訊息，就表示這個列聯表有50%以上的期望值小於五，因此程式會建議使用Fisher's exact test。然後使用者必須回到程式裡面，在tables statement後面加上一個exact的選項，再重跑一次PROC FREQ才能得到Fisher's exact test的結果。Wei Xu於SAS GLOBAL FORUM 2010發表了一個macro程式，讓電腦自動幫使用者判斷要不要進行Fisher's exact test，若需要的話會順便把Fisher's exact test的結果跑出來，使用者不需再去重新執行PROC FREQ一次。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;這個macro名叫%RUN_FISHERS，裡面只有四個參數須要設定:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Data= 要進行卡方檢定的資料名稱&lt;/li&gt;&lt;li&gt;Row= 放在行的變數名稱&lt;/li&gt;&lt;li&gt;Col= 放在列的變數名稱&lt;/li&gt;&lt;li&gt;Count= 如果資料是已經整理好的列聯資料，則會多一個計數變數來表示某一欄位的個數，此時需要把這個變數定義在這個參數裡面。如果不是列聯資料的話，可在此留空白。&lt;/li&gt;&lt;/ul&gt;範例:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&amp;nbsp;data test;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; input r c ct;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; datalines;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; 1 1 12&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; 1 2 5&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; 1 3 6&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; 2 1 13&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; 2 2 2&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; 2 3 4&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; ;&amp;nbsp;&lt;br /&gt;&amp;nbsp;run; &amp;nbsp;&amp;nbsp;&lt;br /&gt;%run_fishers(data=test,&amp;nbsp;row=r,&amp;nbsp;col=c,&amp;nbsp;count=ct);&lt;/code&gt;&lt;/pre&gt;由於此資料會出現warning訊息，所以Fisher's exact test的結果就會直接顯示在報表最下方。如果今天資料變成:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data test;&amp;nbsp;&lt;br /&gt;input r c ct;&amp;nbsp;&lt;br /&gt;datalines;&amp;nbsp;&lt;br /&gt;1 1 12&amp;nbsp;&lt;br /&gt;1 2 50&amp;nbsp;&lt;br /&gt;1 3 60&amp;nbsp;&lt;br /&gt;2 1 13&amp;nbsp;&lt;br /&gt;2 2 20&amp;nbsp;&lt;br /&gt;2 3 40&amp;nbsp;&lt;br /&gt;;&amp;nbsp;&lt;br /&gt;run; &amp;nbsp;&amp;nbsp;&lt;br /&gt;%run_fishers(data=test,&amp;nbsp;row=r,&amp;nbsp;col=c,&amp;nbsp;count=ct);&lt;/code&gt;&lt;/pre&gt;報表最下方就不會出現Fisher's exact test的結果。&lt;br /&gt;&lt;br /&gt;最後是這個macro的原始碼:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro run_fishers (version, data=, row=, col=, count=);&amp;nbsp;&lt;br /&gt;%let _version=1.0;&amp;nbsp;&lt;br /&gt;%if &amp;amp;version ne %then %put RUN_FISHERS macro Version &amp;amp;_version;&amp;nbsp;&lt;br /&gt;%let opts = %sysfunc(getoption(notes)) &amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;_last_=%sysfunc(getoption(_last_));&amp;nbsp;&lt;br /&gt;%if &amp;amp;version ne debug %then %str(options nonotes;);&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;/* Check for newer version */&amp;nbsp;&lt;br /&gt;%if %sysevalf(&amp;amp;sysver &amp;gt;= 8.2) %then %do;&amp;nbsp;&lt;br /&gt;%let _notfound=0;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;filename ver url 'http://ftp.sas.com/techsup/download/stat/versions.dat' termstr=crlf;&amp;nbsp;&lt;br /&gt;&amp;nbsp;data _null_;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;infile ver end=_eof;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;input name:$15. ver;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if upcase(name)="&amp;amp;sysmacroname" then do;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; call symput("_newver",ver); stop;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;end;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if _eof then call symput("_notfound",1);&amp;nbsp;&lt;br /&gt;run;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;%if &amp;amp;syserr ne 0 or &amp;amp;_notfound=1 %then&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;%put &amp;amp;sysmacroname: Unable to check for newer version;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;%else %if %sysevalf(&amp;amp;_newver &amp;gt; &amp;amp;_version) %then %do;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;%put &amp;amp;sysmacroname: A newer version of the &amp;amp;sysmacroname macro is available.;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;%put %str( &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ) You can get the newer version at this location:;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;%put %str( &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ) http://support.sas.com/ctx/samples/index.jsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;%end;&amp;nbsp;&lt;br /&gt;&amp;nbsp;%end;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;proc freq data=&amp;amp;data noprint;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;%if &amp;amp;count ne %then %str(weight &amp;amp;count / zeros;);&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;tables &amp;amp;row*&amp;amp;col / sparse outexpect out=_out1;&amp;nbsp;&lt;br /&gt;run;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;proc means data=_out1 noprint;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;var count;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;output out=_out2;&amp;nbsp;&lt;br /&gt;run;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;data _null_;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;set _out1;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;if expected&amp;lt;=5 then warn+1;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;if _n_=1 then set _out2;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;pct_lt5=warn/_freq_;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;if _freq_=_n_;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;warning=(pct_lt5&amp;gt;=.2);&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;call symput('warning',warning);&amp;nbsp;&lt;br /&gt;run;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;options &amp;amp;opts;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;proc freq data=_out1;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;weight count / zeros;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;tables &amp;amp;row*&amp;amp;col / chisq;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;%if &amp;amp;warning=1 %then %do;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;exact fisher;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;%end;&amp;nbsp;&lt;br /&gt;run;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;%mend;&amp;nbsp;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&amp;nbsp;&lt;/b&gt;&lt;br /&gt;Wei Xu&lt;br /&gt;Boston Scientific&lt;br /&gt;100 Boston Scientific Way&lt;br /&gt;Marlborough, MA 01752-1234&lt;br /&gt;(508) 683-4264&lt;br /&gt;wei.xu@bsci.com&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-1413090291924213562?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/1413090291924213562/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=1413090291924213562&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/1413090291924213562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/1413090291924213562'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2010/08/automatically-run-fishers-exact-test.html' title='Automatically Run Fisher&apos;s Exact Test When the Chi-square Test Might Not Be Valid'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-2527293523266809738</id><published>2010-07-23T17:51:00.000-04:00</published><updated>2010-07-23T17:51:40.647-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程序語法'/><category scheme='http://www.blogger.com/atom/ns#' term='資料整理'/><title type='text'>Stupid Human Tricks with PROC EXPAND®</title><content type='html'>Link:&amp;nbsp;&lt;a href="http://support.sas.com/resources/papers/proceedings10/093-2010.pdf"&gt;http://support.sas.com/resources/papers/proceedings10/093-2010.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;鮮少有人知道 SAS/ETS 裡面有個叫做 PROC EXPAND 的程序。這個程序主要是用來整理時間序列資料，比方說可以自己定義時間區間後再來做一些次數量表的製作。David L. Cassell 利用這個程序進行了一些平常使用者可以用來做資料處理的功能，並發表了一篇教學文件在 SAS GLOBAL FORUM 2010 上。讓我們來看看如何用 PROC EXPAND 程序來取代一些複雜的資料操作。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;TRICK 1: LAGS AND LEADS&lt;/b&gt;&lt;br /&gt;在 data step 裡面，我們可用 LAG() 或 LAGn() 函數來求出某個變數的前1~n天的數據，但如果反過來要找某變數的後1~n天數據，雖然有許多方法可以做，但並沒有一個簡便的 call function 可以處理。但是，用 PROC EXPAND 可以輕鬆地製作出這兩種數據出來。範例程式如下:&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;proc expand data=YourData method=none;&lt;br /&gt;by pt;&lt;br /&gt;convert dosedt = lead1_dt / transformout = (lead 1);&lt;br /&gt;convert dosedt = lead2_dt / transformout = (lead 2);&lt;br /&gt;convert dosedt = lag1_dt / transformout = (lag 1);&lt;br /&gt;convert dosedt = lag2_dt / transformout = (lag 2);&lt;br /&gt;run;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;其中，我們打蘇案要轉換的變數是dosedt，而在 PROC EXPAND 裡面，只需要用 convert 指令，把新變數名稱定義好先(lead1_dt, lead2_dt, lag1_dt, lag2_dt)，然後在後面斜線後加上一個 transformout= 的選項，然後在等號括弧裡面寫上 lead n 或 lag n 便可以造出後 n 天或指是前 n 天的變數。&lt;br /&gt;&lt;b&gt;TRICK 2: MAX OR MIN OF THE LAST K RECORDS&lt;/b&gt;&lt;br /&gt;如果想要知道某一個變數在前n筆或後n筆資料的最大值或最小值，一般的做法是會在PROC MEANS或PROC SUMMARY後加上一個where statement來限制程序要讀取的資料範圍，但在PROC EXPAND裡面，可以直接指定前n筆或後n筆資料，如下所示:&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;proc expand data=YourData out=YourMax method=none;&lt;br /&gt;by factory;&lt;br /&gt;convert x = max_x / transformin=(movmax 50);&lt;br /&gt;convert x = min_x / transformin=(movmin 50);&lt;br /&gt;run;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;同樣利用convert statement，在後面加上transformin選項，並用"movmax n"或"movmin n"來讓SAS去讀前n筆或後n筆資料的最大值最小值。實際上SAS還是會從第一筆資料開始讀，每讀一筆資料就會算一次最大最小值，直到讀進來的資料數量大於movmax和movmin所指定的n值後，SAS才會開始去計算前n筆或後n筆資料的最大值最小值，而所有的結果都會完整呈現在新的資料裡面，我們只需要取最後一筆資料的x_max和x_min數據即為所求。&lt;br /&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;TRICK 3: AGGREGATING CHUNKS OF RECORDS&lt;/span&gt;&lt;br /&gt;我曾經在網路上看過很多人詢問過如何讓資料每跳幾筆資料算一個平均數，或者是每跳幾筆資料取一個數據。許多人用數個PROC程序和data step來完成這兩個動作，但在PROC EXPAND裡面，只需要兩個指令便可完成。&lt;br /&gt;&lt;br /&gt;假設資料如下:&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;data temp1;&lt;br /&gt;input obs vol price;&lt;br /&gt;datalines;&lt;br /&gt;1 2 11&lt;br /&gt;2 2 11&lt;br /&gt;3 2 12&lt;br /&gt;4 3 13&lt;br /&gt;5 3 11&lt;br /&gt;6 3 12&lt;br /&gt;7 4 14&lt;br /&gt;8 4 12&lt;br /&gt;9 4 12&lt;br /&gt;10 5 11&lt;br /&gt;11 5 16&lt;br /&gt;12 5 14&lt;br /&gt;13 6 10&lt;br /&gt;;&lt;br /&gt;run;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;總計十三筆資料，兩個變數(vol, price)。如果我們想要每三筆資料算一次vol的總值，以及每三筆資料抓出price的數據，則程式如下:&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;proc expand data=temp1 out=exp1 factor=(1:3);&lt;br /&gt;convert vol=aggrvol / observed=total;&lt;br /&gt;convert price=new_price / observed=end;&lt;br /&gt;run;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;結果如下:&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;TIME AGGRVOL NEW_PRICE&lt;br /&gt;0 6 12&lt;br /&gt;3 9 12&lt;br /&gt;6 12 12&lt;br /&gt;9 15 14&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;如何讓成是每三筆資料做一次運算，關鍵完全在PROC EXPAND後面的factor(n:m)選項。以此例來看，factor(1:3)便是要求SAS每三筆資料做一次運算。至於運算的方法，則是定義在convert statement後面的observed=選項。當observed=total時，則會求出每三筆資料的總合，當observed=end時，則會求出每三筆資料的最後一筆數據。實際上，observed=選項有許多參數可以設定，比方要算平均數就只要用observed=average即可。所有可使用的選項可以參考SAS線上手冊。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;TRICK 4: THE MOVING AVERAGE&lt;/b&gt;&lt;br /&gt;最後一個是算moving average，而這也是PROC EXPAND在處理時間序列資料時最常使用到的計算。假設我們要算每筆資料含前四筆資料的平均，程式如下:&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;proc expand data=temp1 out=YourOut method=none;&lt;br /&gt;convert number1=mean1 / transformout=(movave 5);&lt;br /&gt;run;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;如同前面所述，我們只要在convert statement後面加上一個transformout=的選項，並於括弧內寫上"moveave 5"便可輕鬆算出moving average。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&lt;/b&gt;&lt;br /&gt;David L. Cassell&lt;br /&gt;Design Pathways&lt;br /&gt;3115 NW Norwood Pl.&lt;br /&gt;Corvallis, OR 97330&lt;br /&gt;DavidLCassell@msn.com&lt;br /&gt;541-754-1304&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-2527293523266809738?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/2527293523266809738/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=2527293523266809738&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/2527293523266809738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/2527293523266809738'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2010/07/stupid-human-tricks-with-proc-expand.html' title='Stupid Human Tricks with PROC EXPAND®'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-6312028245537720713</id><published>2010-07-23T15:14:00.005-04:00</published><updated>2010-07-23T22:18:50.166-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='資料整理'/><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>Dropping Automatically Variables with Only Missing Values</title><content type='html'>Link:&amp;nbsp;&lt;a href="https://docs.google.com/viewer?url=http%3A%2F%2Fsupport.sas.com%2Fresources%2Fpapers%2Fproceedings10%2F048-2010.pdf"&gt;http://support.sas.com/resources/papers/proceedings10/048-2010.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;在進行資料分析前，有些人會習慣把一些含有missing data的樣本給清除掉，雖然這不會影響到分析結果，因為大部分的SAS程序都是用CCA(Complete Case Analysis)來處理含有missing data的數據，不過若要用手動的方法來清掉missing data的話，在遇到龐大數量的變數時，需要消耗很多時間在輸入遍數名稱上。美國人口普查局的Selvaratnam Sridharma發表了一個macro程序於SAS Global Forum 2010，讓這個程式撰寫的過程只需要幾秒鐘的時間就可以完成。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;這個macro如下所示:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%DROPMISS(DSIN, DSOUT, NODROP);&lt;/code&gt;&lt;/pre&gt;裡面只需要定義兩個macro參數:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;DSIN: 原始資料的名稱&lt;/li&gt;&lt;li&gt;DSOUT: 新資料的名稱&lt;/li&gt;&lt;li&gt;NODROP: 不要處理missing data的變數名稱，此為optional選項。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;其中，DSIN和DSOUT應該不用多做解釋。NODROP如果沒有指定特定的變數名稱的話，這個macro就會針對所有在DSIN所指定的資料裡面的變數進行missing data的處理。但如果想要讓這個macro不處理所有文字型變數或數值型變數，則可以用 __NUMERIC_ 或_CHARACTER_ 來限制。如下所示:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%DROPMISS (DSIN=olddata,DSOUT=newdata, nodrop= _NUMERIC_ );&lt;br /&gt;%DROPMISS (DSIN=oldedata,DSOUT=newdata, nodrop= _CHARACTER_ );&lt;/code&gt;&lt;/pre&gt;此macro的原始碼如下:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;/******************/&lt;br /&gt;options nomprint noSYMBOLGEN MLOGIC;&lt;br /&gt;/****************************/&lt;br /&gt;%macro DROPMISS( DSNIN /* name of input SAS dataset&lt;br /&gt;*/&lt;br /&gt;, DSNOUT /* name of output SAS dataset&lt;br /&gt;*/&lt;br /&gt;, NODROP= /* [optional] variables to be omitted from dropping even if&lt;br /&gt;they have only missing values */&lt;br /&gt;) ;&lt;br /&gt;/* PURPOSE: To find both Character and Numeric the variables that have only&lt;br /&gt;missing values and drop them if&lt;br /&gt;* they are not in &amp;amp;NONDROP&lt;br /&gt;*&lt;br /&gt;* NOTE: if there are no variables in the dataset, produce no variables&lt;br /&gt;processing code&lt;br /&gt;*&lt;br /&gt;*&lt;br /&gt;* EXAMPLE OF USE:&lt;br /&gt;* %DROPMISS( DSNIN, DSNOUT )&lt;br /&gt;* %DROPMISS( DSNIN, DSNOUT, NODROP=A B C D--H X1-X100 )&lt;br /&gt;* %DROPMISS( DSNIN, DSNOUT, NODROP=_numeric_ )&lt;br /&gt;* %DROPMISS( DSNIN, DSNOUT, NOdrop=_character_ )&lt;br /&gt;*/&lt;br /&gt;%local I ;&lt;br /&gt;%if "&amp;amp;DSNIN" = "&amp;amp;DSNOUT"&lt;br /&gt;%then %do ;&lt;br /&gt;%put /------------------------------------------------\ ;&lt;br /&gt;%put | ERROR from DROPMISS: | ;&lt;br /&gt;%put | Input Dataset has same name as Output Dataset. | ;&lt;br /&gt;%put | Execution terminating forthwith. | ;&lt;br /&gt;%put \------------------------------------------------/ ;&lt;br /&gt;%goto L9999 ;&lt;br /&gt;%end ;&lt;br /&gt;/*###################################################################*/&lt;br /&gt;/* begin executable code&lt;br /&gt;/*####################################################################/&lt;br /&gt;/*===================================================================*/&lt;br /&gt;/* Create dataset of variable names that have only missing values&lt;br /&gt;/* exclude from the computation all names in &amp;amp;NODROP&lt;br /&gt;/*===================================================================*/&lt;br /&gt;proc contents data=&amp;amp;DSNIN( drop=&amp;amp;NODROP ) memtype=data noprint out=_cntnts_( keep=&lt;br /&gt;name type ) ; run ;&lt;br /&gt;%let N_CHAR = 0 ;&lt;br /&gt;%let N_NUM = 0 ;&lt;br /&gt;data _null_ ;&lt;br /&gt;set _cntnts_ end=lastobs nobs=nobs ;&lt;br /&gt;&lt;br /&gt;if nobs = 0 then stop ;&lt;br /&gt;n_char + ( type = 2 ) ;&lt;br /&gt;n_num + ( type = 1 ) ;&lt;br /&gt;/* create macro vars containing final # of char, numeric variables */&lt;br /&gt;if lastobs&lt;br /&gt;then do ;&lt;br /&gt;call symput( 'N_CHAR', left( put( n_char, 5. ))) ;&lt;br /&gt;call symput( 'N_NUM' , left( put( n_num , 5. ))) ;&lt;br /&gt;end ;&lt;br /&gt;run ;&lt;br /&gt;/*===================================================================*/&lt;br /&gt;/* if there are no variables in dataset, stop further processing&lt;br /&gt;/*===================================================================*/&lt;br /&gt;%if %eval( &amp;amp;N_NUM + &amp;amp;N_CHAR ) = 0&lt;br /&gt;%then %do ;&lt;br /&gt;%put /----------------------------------\ ;&lt;br /&gt;%put | ERROR from DROPMISS: | ;&lt;br /&gt;%put | No variables in dataset. | ;&lt;br /&gt;%put | Execution terminating forthwith. | ;&lt;br /&gt;%put \----------------------------------/ ;&lt;br /&gt;%goto L9999 ;&lt;br /&gt;%end ;&lt;br /&gt;/*===================================================================*/&lt;br /&gt;/* put global macro names into global symbol table for later retrieval&lt;br /&gt;/*===================================================================*/&lt;br /&gt;%LET NUM0 =0;&lt;br /&gt;%LET CHAR0 = 0;&lt;br /&gt;%IF &amp;amp;N_NUM &amp;gt;0 %THEN %DO;&lt;br /&gt;%do I = 1 %to &amp;amp;N_NUM ;&lt;br /&gt;%global NUM&amp;amp;I ;&lt;br /&gt;%end ;&lt;br /&gt;%END;&lt;br /&gt;%if &amp;amp;N_CHAR &amp;gt; 0 %THEN %DO;&lt;br /&gt;%do I = 1 %to &amp;amp;N_CHAR ;&lt;br /&gt;%global CHAR&amp;amp;I ;&lt;br /&gt;%end ;&lt;br /&gt;%END;&lt;br /&gt;/*===================================================================*/&lt;br /&gt;/* create macro vars containing variable names&lt;br /&gt;/* efficiency note: could compute n_char, n_num here, but must declare macro names&lt;br /&gt;to be&lt;br /&gt;global b4 stuffing them&lt;br /&gt;/*&lt;br /&gt;/*===================================================================*/&lt;br /&gt;proc sql noprint ;&lt;br /&gt;%if &amp;amp;N_CHAR &amp;gt; 0 %then %str( select name into :CHAR1 - :CHAR&amp;amp;N_CHAR from&lt;br /&gt;_cntnts_ where type = 2 ; ) ;&lt;br /&gt;%if &amp;amp;N_NUM &amp;gt; 0 %then %str( select name into :NUM1 - :NUM&amp;amp;N_NUM from&lt;br /&gt;_cntnts_ where type = 1 ; ) ;&lt;br /&gt;quit ;&lt;br /&gt;/*===================================================================*/&lt;br /&gt;/* Determine the variables that are missing&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt;/*===================================================================*/&lt;br /&gt;%IF &amp;amp;N_CHAR &amp;gt; 1 %THEN %DO;&lt;br /&gt;%let N_CHAR_1 = %EVAL(&amp;amp;N_CHAR - 1);&lt;br /&gt;%END;&lt;br /&gt;Proc sql ;&lt;br /&gt;select %do I= 1 %to &amp;amp;N_NUM; max (&amp;amp;&amp;amp;NUM&amp;amp;I) , %end; %IF &amp;amp;N_CHAR &amp;gt; 1 %THEN %DO;&lt;br /&gt;%do I= 1 %to &amp;amp;N_CHAR_1; max(&amp;amp;&amp;amp;CHAR&amp;amp;I), %END; %end; MAX(&amp;amp;&amp;amp;CHAR&amp;amp;N_CHAR)&lt;br /&gt;into&lt;br /&gt;%do I= 1 %to &amp;amp;N_NUM; :NUMMAX&amp;amp;I , %END; %IF &amp;amp;N_CHAR &amp;gt; 1 %THEN %DO;&lt;br /&gt;%do I= 1 %to &amp;amp;N_CHAR_1; :CHARMAX&amp;amp;I,%END; %END; :CHARMAX&amp;amp;N_CHAR&lt;br /&gt;from &amp;amp;DSNIN;&lt;br /&gt;quit;&lt;br /&gt;/*===================================================================*/&lt;br /&gt;/* initialize DROP_NUM, DROP_CHAR global macro vars&lt;br /&gt;/*===================================================================*/&lt;br /&gt;%let DROP_NUM = ;&lt;br /&gt;%let DROP_CHAR = ;&lt;br /&gt;%if &amp;amp;N_NUM &amp;gt; 0 %THEN %DO;&lt;br /&gt;DATA _NULL_;&lt;br /&gt;%do I = 1 %to &amp;amp;N_NUM ;&lt;br /&gt;%IF &amp;amp;&amp;amp;NUMMAX&amp;amp;I =. %THEN %DO;&lt;br /&gt;%let DROP_NUM = &amp;amp;DROP_NUM %qtrim( &amp;amp;&amp;amp;NUM&amp;amp;I ) ;&lt;br /&gt;%END;&lt;br /&gt;%end ;&lt;br /&gt;RUN;&lt;br /&gt;%END;&lt;br /&gt;%IF &amp;amp;N_CHAR &amp;gt; 0 %THEN %DO;&lt;br /&gt;DATA _NULL_;&lt;br /&gt;%do I = 1 %to &amp;amp;N_CHAR ;&lt;br /&gt;%IF "%qtrim(&amp;amp;&amp;amp;CHARMAX&amp;amp;I)" eq "" %THEN %DO;&lt;br /&gt;%let DROP_CHAR = &amp;amp;DROP_CHAR %qtrim( &amp;amp;&amp;amp;CHAR&amp;amp;I ) ;&lt;br /&gt;%END;&lt;br /&gt;%end ;&lt;br /&gt;RUN;&lt;br /&gt;%END;&lt;br /&gt;/*===================================================================*/&lt;br /&gt;/* Create output dataset&lt;br /&gt;/*===================================================================*/&lt;br /&gt;data &amp;amp;DSNOUT ;&lt;br /&gt;%if &amp;amp;DROP_CHAR ^= %then %str(DROP &amp;amp;DROP_CHAR ; ) ; /* drop char variables&lt;br /&gt;that&lt;br /&gt;have only missing values */&lt;br /&gt;%if &amp;amp;DROP_NUM ^= %then %str(DROP &amp;amp;DROP_NUM ; ) ; /* drop num variables&lt;br /&gt;that&lt;br /&gt;have only missing values */&lt;br /&gt;set &amp;amp;DSNIN ;&lt;br /&gt;%if &amp;amp;DROP_CHAR ^= or &amp;amp;DROP_NUM ^= %then %do;&lt;br /&gt;&lt;br /&gt;%put /----------------------------------\ ;&lt;br /&gt;%put | Variables dropped are &amp;amp;DROP_CHAR &amp;amp;DROP_NUM | ;&lt;br /&gt;%put \----------------------------------/ ;&lt;br /&gt;%end;&lt;br /&gt;%if &amp;amp;DROP_CHAR = and &amp;amp;DROP_NUM = %then %do;&lt;br /&gt;%put /----------------------------------\ ;&lt;br /&gt;%put | No variables are dropped |;&lt;br /&gt;%put \----------------------------------/ ;&lt;br /&gt;%end;&lt;br /&gt;run ;&lt;br /&gt;%L9999:&lt;br /&gt;%mend DROPMISS ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Selvaratnam Sridharma&lt;br /&gt;Economic Planning and Coordination Division&lt;br /&gt;U.S. Bureau of the Census&lt;br /&gt;Address&lt;br /&gt;Washington, DC 20233-6100&lt;br /&gt;301-763-6774&lt;br /&gt;Email: selvaratnam.sridharma@census.gov&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-6312028245537720713?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/6312028245537720713/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=6312028245537720713&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6312028245537720713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6312028245537720713'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2010/07/dropping-automatically-variables-with.html' title='Dropping Automatically Variables with Only Missing Values'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-6835902750623542080</id><published>2010-03-26T00:21:00.006-04:00</published><updated>2010-07-23T15:56:56.455-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>PROC MIXED: Macro to assess fixed and random effects for significance using the Likelihood Ratio test and the approximate Mixture Method</title><content type='html'>原文載點：&lt;span class="Apple-style-span" style="font-family: arial, sans-serif; font-size: 13px;"&gt;&lt;a href="https://docs.google.com/viewer?url=http://analytics.ncsu.edu/sesug/2009/SC013.Bardenheier.pdf"&gt;http://analytics.ncsu.edu/sesug/2009/SC013.Bardenheier.pdf&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;若要從兩個nested mixed model挑選較佳的模式，比較專業的人會推薦使用Likelihood Ratio Test（以下簡稱LRT）來處理這類的問題。PROC MIXED程序並沒有語法來進行這個檢定，但這個檢定需要使用到的參數，卻全部都可以從PROC MIXED程序的輸出報表內找到。懂得運作的使用者可以從報表拿擷取相關參數，然後自己算一算再查個表大概就知道結果了。我自己曾經在準備博士班資格考時寫了一個簡易的macro來做LRT，但沒想到真的有人把這個觀念發表出來。我稍微看了一下這份技術文件內的macro寫法，與我當年寫的大同小異，但作者有將輸出報表格式設計的比較好看一點，所以我就來介紹一下這個方便進行LRT的macro。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;假設兩個nested mixed model分別稱為reduced model和full model，通常reduced model會被設定在虛無假設H0下，full model會被設定在對立假設H1下。而整個LRT會從這兩個模式各取出兩個數據出來，一個是他們的自由度，另一個是他們-2log likelihood function的值。這兩個數據全部都可以從PROC MIXED的報表內找到。我以PROC MIXED線上手冊所附的一個範例為例，請參照這個網頁：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.tau.ac.il/cc/pages/docs/sas8/stat/chap41/sect30.htm"&gt;http://www.tau.ac.il/cc/pages/docs/sas8/stat/chap41/sect30.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;這兩個數據可以在這個地方找到，圖示如下（紅色箭頭處）：&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #4c4c4c; font-family: arial, helvetica, sans-serif; font-size: 12px;"&gt;&lt;img id="imgThumbnail" src="http://rookeryiis2.aviary.com/storage/3472500/3472607_252c_rss.jpg" style="border-bottom-style: none; border-bottom-width: 0px; border-color: initial; border-left-style: none; border-left-width: 0px; border-right-style: none; border-right-width: 0px; border-top-style: none; border-top-width: 0px; border-width: initial;" /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #4c4c4c; font-family: arial, helvetica, sans-serif; font-size: 12px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;至於公式，引用 wiki 的資料：&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: sans-serif; font-size: 13px; line-height: 19px;"&gt;&lt;img alt="\begin{align}D &amp;amp; = -2(\ln(\text{likelihood for null model}) - \ln(\text{likelihood for alternative model})) \\&amp;amp; = -2\ln\left( \frac{\text{likelihood for null model}}{\text{likelihood for alternative model}} \right).\end{align}" class="tex" src="http://upload.wikimedia.org/math/a/c/6/ac612f42c3987cbac42333ad2c338013.png" style="border-bottom-style: none; border-color: initial; border-left-style: none; border-right-style: none; border-top-style: none; border-width: initial; vertical-align: middle;" /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;白話一點，就是把 reduced model 的 -2 log likelihood function 的值減掉 full model 的 -2 log likelihood function 的值，就可以算出上面那個 D。然後兩個模式的自由度數量的差異套進卡方分配裡面，就可以算出 p-value 了。如果 p-value &amp;lt; 0.05，就表示代表 reduced model 的 H0 被拒絕了，也就是說 full model 比 reduced model 好。反之亦然。&lt;br /&gt;&lt;br /&gt;這種計算其實根本不需要使用到電腦的，但懶人永遠可以找藉口，所以原文作者還是花了將近兩頁的篇幅寫了這個 macro 來服務大眾。&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;%macro LRMixtureTest(fullmodel=,redmodel=,DFfull=,DFred=);&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;/*&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;This macro calculates the Likelihood Ratio Test for fixed effects in a&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;mixed model&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;See Singer Applied Longitudinal Data Analysis pp 116-120.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;and also calculates the mixture method pvalue for random effects in a&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;mixed model -see KKNM chapter 26.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;The macro argument &amp;amp;fullmodel refers to the output dataset produced by&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;running the full model in proc mixed and using the statement:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ods output FitStatistics=fm;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;The macro argument &amp;amp;DFfull refers to the output dataset produced by&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;running the full model in proc mixed and adding to the statement:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ods output FitStatistics=fm SolutionF=SFfm; The number of&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;parameters being tested (ie, fixed effects) determine the degrees of&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;freedom in the LRT and come from this dataset.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;The argument &amp;amp;redmodel refers to the output dataset produced by running&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;the reduced model in proc mixed using the statement:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&amp;nbsp;&amp;nbsp; ods output FitStatistics=rm &amp;nbsp;SolutionF=SFrm ;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;Maximum Likelihood should be used when comparing fixed effects because&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;it maximizes the likelihood of the sample data. Using the Restricted&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;Maximum likelihood should only be used when assessing a random term&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;(ie, the fixed effects should be the same in both models) &amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;because in RML we maximize the likelihood of the residuals. The degrees&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;of freedom would not be correct if the number of fixed effects were&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;different in each model when using RML -which is the default in PROC&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;MIXED.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;*/&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;data &amp;amp;fullmodel; set &amp;amp;fullmodel;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;if descr='-2 Res Log Likelihood' then chisqfullRML=value; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;*RML;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;else if descr='-2 Log Likelihood' then chisqfullFML=value; &lt;/span&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;*FML;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;run;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;data &amp;amp;redmodel; set &amp;amp;redmodel;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;if descr='-2 Res Log Likelihood' then chisqredRML=value; &lt;/span&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;*RML;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;else &amp;nbsp;if descr='-2 Log Likelihood' then chisqredFML=value; &lt;/span&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;*FML;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;run;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;proc sql;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;CREATE TABLE flDF AS SELECT &amp;nbsp;effect, count(*) AS fullDF from&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;work.&amp;amp;DFfull; quit; &lt;/span&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;*Count number of effects to get degrees of freedom;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;proc sql;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;create table rdDF as select &amp;nbsp;effect, count(*) as redDF from&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;work.&amp;amp;DFred; quit;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;data degfree (drop=effect);&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;merge &amp;nbsp;work.flDF work.rdDF;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;if _n_=1 then &amp;nbsp;LRTDF= fullDF &amp;nbsp;- redDF; run;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;data likelihood;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;merge &amp;amp;fullmodel &amp;amp;redmodel degfree;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;testintRML=abs((chisqredRML)-(chisqfullRML)); &lt;/span&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;**Models can yield&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;negative LLs, those that are smaller in absolute value -ie, closer to 0&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;fit better (pg 116-117, Singer); &amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;7&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;testintFML=abs((chisqredFML)-(chisqfullFML)); &lt;/span&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;**Models can yield&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;negative LLs, those that are smaller in absolute value -ie, closer to 0&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;fit better (pg 116-117, Singer);&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;pvaluemixture=(( .5*(1-probchi(testintRML,2)) + .5*(1-&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;probchi(testintRML,1)) )); &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;*for random terms;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;pvalueLRT=(1-probchi(testintFML,LRTDF)); &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;*For fixed terms;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;proc print data=likelihood split='*' noobs;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; var &amp;nbsp;testintFML &amp;nbsp;pvalueLRT;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;format &amp;nbsp;pvalueLRT 6.4;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;where testintFML ne .;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; label testintFML='likelihood ratio*test statistic*&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; comparing*reduced model to full model'&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pvalueLRT='p-value LRT';&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;title "Likelihood Ratio Test for fixed effects"; run;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;proc print data=likelihood split='*' noobs;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; var &amp;nbsp;testintRML &amp;nbsp;pvaluemixture;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;format pvaluemixture &amp;nbsp;6.4;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;where &amp;nbsp;testintRML ne . ;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; label testintRML='likelihood ratio*test statistic*&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; comparing*reduced model to full model'&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pvaluemixture='mixture method p-value';&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;title "Mixture method Test for random effects";&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&amp;nbsp;run; &amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;%mend LRMixtureTest;&amp;nbsp;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;這個 macro 裡面綠色的部分完全都是作者的註釋和說明，只有藍色的部分才是真正 SAS 會去執行的程式碼。其中只有四個參數要說明：&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;fullmodel：full model 的 -2 log likelihood function 值&lt;/li&gt;&lt;li&gt;redmodel：reduced model 的&amp;nbsp;-2 log likelihood function 值&lt;/li&gt;&lt;li&gt;DFfull：full model 的自由度&lt;/li&gt;&lt;li&gt;DFred：reduced model 的自由度&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;四個參數設定就和上一段的敘述相同。全部都是必要的參數，缺一不可。因此，只要呼叫&amp;nbsp;%macro LRMixtureTest 再套上四個參數值，電腦就會幫你做 LRT。我們來看原文內的一個範例。&lt;br /&gt;&lt;br /&gt;範例模式：&lt;br /&gt;&lt;br /&gt;&lt;img alt="doodle.png" src="http://rookeryiis1.aviary.com/storage/3472500/3472730_b795_625x625.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;這模式只使用一個因變數叫做 PCTBLK，但他同時是固定效應也是隨機效應。假設這是個 full model，而 reduced model 就設定為拿掉 PCTBLK 固定效應的模式，也就是拿掉上面劃紅線的那一段。&lt;br /&gt;&lt;br /&gt;因此，先跑兩個程式把那四個要用到的參數算出來：&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;%include '\\cdc\private\mixture method pvalue macro1.sas';&lt;br /&gt;proc mixed data=bhb7.allUS2levge10blk method=ml covtest empirical &lt;br /&gt;noclprint ;&lt;br /&gt;class &amp;nbsp;state_id;&lt;br /&gt;model diffcov=pctblk/ ddfm=contain s;&lt;br /&gt;random intercept pctblk /subject=state_id type=ar(1) s ;&lt;br /&gt;ods output FitStatistics=fm &amp;nbsp;SolutionF=SFfm ;&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;proc mixed data=bhb7.allUS2levge10blk method=ml covtest empirical&lt;br /&gt;noclprint;&lt;br /&gt;class &amp;nbsp;state_id;&lt;br /&gt;model diffcov=/ddfm=contain &amp;nbsp; s;&lt;br /&gt;random intercept &amp;nbsp;pctblk /subject=state_id type=ar(1) s;&lt;br /&gt;ods output FitStatistics=rm SolutionF=SFrm ;&lt;br /&gt;run;&lt;/span&gt; &lt;/code&gt;&lt;br /&gt;&lt;br /&gt;跑完後，兩個模式的 -2 log likelihood function 值和自由度會被 ods output 輸出到不同的資料裡面，接著使用那個 macro 去把從這四個資料裡面抓數值出來算：&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;%LRMixtureTest(fullmodel=fm,redmodel=rm,DFfull=SFfm,DFred=SFrm); &lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;最後這個 macro 就會輸出下面這個報表給你：&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #4c4c4c; font-family: arial, helvetica, sans-serif; font-size: 12px;"&gt;&lt;img id="imgThumbnail" src="http://rookeryiis1.aviary.com/storage/3472500/3472768_226b_rss.jpg" style="border-bottom-style: none; border-bottom-width: 0px; border-color: initial; border-left-style: none; border-left-width: 0px; border-right-style: none; border-right-width: 0px; border-top-style: none; border-top-width: 0px; border-width: initial;" /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;結果顯示 p-value &amp;lt; 0.05，所以 full model 比 reduced model 好。&lt;br /&gt;&lt;br /&gt;從這個範例中，特別要強調一點是，如果兩個 nested mixed model 差異只有在固定效應時，一開始那兩個 PROC MIXED 執行時，後面的 method option 必須強制設定為 ML，因為如果沒有特別去設定的話，PROC MIXED 預設的參數估計方法是 REML，但這只有在兩個模式的差異是在隨機效應或者是 covariance structure 時才能使用。原文中的第一個範例就是用 REML 再估計參數，因為兩個模式的差別只有在一個 random intercept 而已。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Contact Information:&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Barbara Bardenheier, MPH, MA&lt;br /&gt;Centers for Disease Control and Prevention&lt;br /&gt;1600 Clifton Rd, MS E-52&lt;br /&gt;Atlanta, GA 30333&lt;br /&gt;Tel : (404) 639-8789&lt;br /&gt;Fax : (404) 639-8614&lt;br /&gt;Email : bfb7@cdc.gov&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-6835902750623542080?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/6835902750623542080/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=6835902750623542080&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6835902750623542080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6835902750623542080'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2010/03/proc-mixed-macro-to-assess-fixed-and.html' title='PROC MIXED: Macro to assess fixed and random effects for significance using the Likelihood Ratio test and the approximate Mixture Method'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-1667469089538034965</id><published>2010-03-21T21:32:00.001-04:00</published><updated>2010-03-21T21:37:22.156-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>A Macro for Computing the Mantel-Fleisś Criterion</title><content type='html'>原文載點：&lt;span class="Apple-style-span" style="font-family: arial, sans-serif; font-size: 13px;"&gt;&lt;a href="https://docs.google.com/viewer?url=http://analytics.ncsu.edu/sesug/2009/PO008.Welch.pdf"&gt;http://analytics.ncsu.edu/sesug/2009/PO008.Welch.pdf&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;在作2乘2的卡方分析時，我們通常會看每一格裡面的樣本期望值是不是大於五，如果不大於五的比例超過一半的話，便需要使用 Fisher's exact test 的結果來取代原本的卡方分析結果。但這種判斷方法，在2乘2乘H的表格下並不適用。Mantel 和&amp;nbsp;Fleisś 在 1980 年代發明了一種判斷方法來專門處理這種情況，不過這個方法並沒有內建在 SAS 現存的程序內，因此 Brandon Welch, Jane Eslinger 和 Rob Woolson 在 2009 年的 SESUG 發表了一篇技術文件，提供一個簡便的 macro 供使用者使用。&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;有關 Mantel-Fleisś criterion 的理論，可詳見原文。以下就直接切入這個 macro 的使用方法：&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;%MantelFleiss(In,Strat,Var1,Var2,Count)&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;這個名為 MantelFleiss 的 macro 只有五個參數，定義如下：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;In：資料集名稱&lt;/li&gt;&lt;li&gt;Strat： 層數，亦即2乘2表格的數量(H)&lt;/li&gt;&lt;li&gt;Var1：行變數&lt;/li&gt;&lt;li&gt;Var2：列變數&lt;/li&gt;&lt;li&gt;Count：此變數是加權變數（weight），是非必要的變數。如果省略的話，程式會自動定義為「1」。&lt;/li&gt;&lt;/ul&gt;原始碼如下：&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;%macro MantelFleiss(In,Strat,Var1,Var2,Count);&lt;br /&gt;&lt;br /&gt;%*-----------------------------------------------------------;&lt;br /&gt;%* &amp;amp;In  - input data set                 ;&lt;br /&gt;%* &amp;amp;Strat - stratification variable (e.g., site, race, etc.);&lt;br /&gt;%* &amp;amp;Var1 - row variable                  ;&lt;br /&gt;%* &amp;amp;Var2 - column variable                 ;&lt;br /&gt;%* &amp;amp;Count - optional weight variable            ;&lt;br /&gt;%*-----------------------------------------------------------;&lt;br /&gt;&lt;br /&gt;%*reset output data sets;&lt;br /&gt;PROC DATASETS nodetails nolist;&lt;br /&gt;delete _counts _expect _mantel:;&lt;br /&gt;RUN;&lt;br /&gt;QUIT;&lt;br /&gt;&lt;br /&gt;%*determine number of strata levels;&lt;br /&gt;PROC SQL noprint;&lt;br /&gt;select count(distinct &amp;amp;strat) into: stratflag from &amp;amp;In;&lt;br /&gt;QUIT;&lt;br /&gt;%put **Number of strata levels &amp;amp;stratflag;&lt;br /&gt;&lt;br /&gt;%*get expected counts and totals in each partial table;&lt;br /&gt;PROC FREQ data = &amp;amp;In;&lt;br /&gt;tables &amp;amp;Strat*&amp;amp;Var1*&amp;amp;Var2 / expected outexpect out = _expect;&lt;br /&gt;%if %nrbquote(&amp;amp;Count.) ne %then weight &amp;amp;Count.;;&lt;br /&gt;ODS output CrossTabFreqs = _counts;&lt;br /&gt;RUN;&lt;br /&gt;&lt;br /&gt;%*get sum of expected cell counts in cell n11 in each partial table&lt;br /&gt;(assign to macro var SUMEXP);&lt;br /&gt;DATA _null_; &lt;br /&gt;set _expect end = eof;&lt;br /&gt;by &amp;amp;Strat;&lt;br /&gt;retain sumexp 0;&lt;br /&gt;if first.&amp;amp;Strat then do;&lt;br /&gt;sumexp = sumexp + expected;&lt;br /&gt;end;&lt;br /&gt;if eof then call symput('sumexp',put(sumexp,8.4));&lt;br /&gt;RUN;&lt;br /&gt;%put Sum of expected values in cells nh11: sum(mh11) = %cmpres(&amp;amp;sumexp);&lt;br /&gt;&lt;br /&gt;PROC SORT data = _counts; &lt;br /&gt;by &amp;amp;Strat &amp;amp;Var1 &amp;amp;Var2;&lt;br /&gt;RUN;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;%*Subset to the needed totals output by PROC FREQ&lt;br /&gt;number the &amp;amp;Strat, &amp;amp;Var1, and &amp;amp;Var2 for use below&lt;br /&gt;0 - totals&lt;br /&gt;1 - first &amp;amp;Strat/&amp;amp;Var1/&amp;amp;Var2&lt;br /&gt;2 - second &amp;amp;Strat/&amp;amp;Var1/&amp;amp;Var2&lt;br /&gt;...;&lt;br /&gt;&lt;br /&gt;DATA _mantelf1;&lt;br /&gt;%*only include marginal totals from ODS;&lt;br /&gt;set _counts(where = (_type_ not in ('100' '111'))); &lt;br /&gt;by &amp;amp;Strat &amp;amp;Var1 &amp;amp;Var2;&lt;br /&gt;retain &amp;amp;Strat._ 0 &amp;amp;Var1._ &amp;amp;Var2._;&lt;br /&gt;&lt;br /&gt;%*reset for change in strata;&lt;br /&gt;if first.&amp;amp;Strat then do;&lt;br /&gt;&amp;amp;Var1._ = 0; &amp;amp;Var2._ = 0;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;%*get numeric version of strata variable;&lt;br /&gt;if first.&amp;amp;Strat then &amp;amp;Strat._ = &amp;amp;Strat._ + 1;&lt;br /&gt;&lt;br /&gt;%*define zero as total for any &amp;amp;Var1/&amp;amp;Var2;&lt;br /&gt;if missing(&amp;amp;Var1) then &amp;amp;Var1._ = 0; &lt;br /&gt;else &amp;amp;Var1._ + 1;&lt;br /&gt;&lt;br /&gt;if missing(&amp;amp;Var2) then &amp;amp;Var2._ = 0; &lt;br /&gt;else &amp;amp;Var2._ + 1;&lt;br /&gt;&lt;br /&gt;keep &amp;amp;Strat._ &amp;amp;Var1._ &amp;amp;Var2._ &amp;amp;Strat. &amp;amp;Var1. &amp;amp;Var2. frequency;&lt;br /&gt;RUN;&lt;br /&gt;&lt;br /&gt;DATA _mantelf2;&lt;br /&gt;set _mantelf1;&lt;br /&gt;by &amp;amp;Strat._;&lt;br /&gt;&lt;br /&gt;retain n11_ n1_1 n1_2;&lt;br /&gt;&lt;br /&gt;if first.&amp;amp;Strat._ then do;&lt;br /&gt;n11_ = 0;&lt;br /&gt;n1_1 = 0;&lt;br /&gt;n1_2 = 0; &lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;%*get each total;&lt;br /&gt;if &amp;amp;Var1._ = 1 then n11_ = frequency; %*for row  one in the hth strata;&lt;br /&gt;if &amp;amp;Var2._ = 1 then n1_1 = frequency; %*for column one in the hth strata;&lt;br /&gt;if &amp;amp;Var2._ = 2 then n1_2 = frequency; %*for column two in the hth strata;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;%*define (nh11)L and (nh11)U for final computation;&lt;br /&gt;max_ = max(0,n11_-n1_2);&lt;br /&gt;min_ = min(n1_1,n11_);&lt;br /&gt;&lt;br /&gt;if last.&amp;amp;Strat._;&lt;br /&gt;&lt;br /&gt;RUN;&lt;br /&gt;&lt;br /&gt;%*sum acoss min and max to get lower/upper bounds of criterion;&lt;br /&gt;DATA _mantelf3(keep = mf_suml mf_sumu mflendpt mfrendpt mf_r);&lt;br /&gt;set _mantelf2 end = eof;&lt;br /&gt;&lt;br /&gt;retain mf_suml mf_sumu;&lt;br /&gt;&lt;br /&gt;if _n_ = 1 then do;&lt;br /&gt;mf_suml = 0; mf_sumu = 0;&lt;br /&gt;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;mf_suml = mf_suml + max_;&lt;br /&gt;mf_sumu = mf_sumu + min_;&lt;br /&gt;&lt;br /&gt;if eof then do;&lt;br /&gt;mflendpt = &amp;amp;sumexp-mf_suml;&lt;br /&gt;mfrendpt = mf_sumu-&amp;amp;sumexp;&lt;br /&gt;mf_r   = min(mflendpt,mfrendpt);&lt;br /&gt;&lt;br /&gt;put "Sum of lower bound (sum[(nh11)L]) = " mf_suml;&lt;br /&gt;put "Sum of upper bound (sum[(nh11)U]) = " mf_sumu;&lt;br /&gt;put "Left end-point: sum[mh11] - sum[(nh11)L] = " mflendpt;&lt;br /&gt;put "Right endpoint: sum[(nh11)U] - sum[mh11] = " mfrendpt;&lt;br /&gt;put "Mantel-Fleiss R = min[" mflendpt "," mfrendpt "] = " mf_r;&lt;br /&gt;&lt;br /&gt;if mf_r&amp;gt;5 then put "Mantel-Fleiss criterion satisfied (since R &amp;gt; 5)";&lt;br /&gt;else      put "Mantel-Fleiss criterion NOT satisfied (since R &amp;lt;= 5)";&lt;br /&gt;output; &lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;label&lt;br /&gt;mf_suml = "Summation of Maximum (sum[(nh11)L])"&lt;br /&gt;mf_sumu = "Summation of Minumum (sum[(nh11)U])"&lt;br /&gt;mflendpt = "Left End-Point: sum[mh11] - sum[(nh11)L]"&lt;br /&gt;mfrendpt = "Right End-Point: sum[(nh11)U] - sum[mh11]"&lt;br /&gt;mf_r   = "R Value: min[sum[mh11] - sum[(nh11)L],sum[(nh11)U] -  sum[mh11]]";&lt;br /&gt;RUN;&lt;br /&gt;%mend;&lt;/span&gt;                               &lt;/code&gt;&lt;br /&gt;&lt;br /&gt;範例一：&lt;br /&gt;資料檔：&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt; PROC FORMAT;&lt;br /&gt;value trtf&lt;br /&gt;1 = 'TreatmentA'&lt;br /&gt;2 = 'TreatmentB'&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;value sitef&lt;br /&gt;1 = 'Arkansas'&lt;br /&gt;2 = 'Indiana'&lt;br /&gt;3 = 'Illinois'&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;value respf&lt;br /&gt;1 = 'Present'&lt;br /&gt;2 = 'Absent'&lt;br /&gt;;&lt;br /&gt;RUN;&lt;br /&gt;&lt;br /&gt;DATA test;&lt;br /&gt;do site = 1 to 3;&lt;br /&gt;do treat = 1 to 2;&lt;br /&gt;do resp = 1 to 2;&lt;br /&gt;input counts @@;&lt;br /&gt;output;&lt;br /&gt;end;&lt;br /&gt;end;&lt;br /&gt;end;&lt;br /&gt;label site = "Site" treat = "Treatment" resp = "Response";&lt;br /&gt;format treat trtf. site sitef. resp respf.;&lt;br /&gt;cards;&lt;br /&gt;12 5 7 3&lt;br /&gt;1 2 5 2 &lt;br /&gt;0 9 5 6&lt;br /&gt;;&lt;br /&gt;RUN;&lt;/span&gt;   &lt;/code&gt;&lt;br /&gt;&lt;br /&gt;上述程式在表格內呈現的結果如下：&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #4c4c4c; font-family: arial, helvetica, sans-serif; font-size: 12px;"&gt;&lt;img id="imgThumbnail" src="http://rookery5.aviary.com/storagev12/3432000/3432014_e602_rss.jpg" style="border-bottom-style: none; border-bottom-width: 0px; border-color: initial; border-left-style: none; border-left-width: 0px; border-right-style: none; border-right-width: 0px; border-top-style: none; border-top-width: 0px; border-width: initial;" /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;接著執行 macro：&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;%MantelFleiss(test,site,treat,resp,counts) ;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;要特別注意的一點是，這個 macro 的結果並不是呈現在 output 視窗裡面，而是直接呈現在 log 視窗裡面，所以送出這行程式碼後，便可以直接在 log 視窗上看到結果，如下所示：&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;Sum of expected values in cells nh11: sum(mh11) = 20.5130&lt;br /&gt;Sum of lower bound (sum[(nh11)L]) = 9&lt;br /&gt;Sum of upper bound (sum[(nh11)U]) = 25&lt;br /&gt;Left end-point: sum[mh11] - sum[(nh11)L] = 11.513&lt;br /&gt;Right endpoint: sum[(nh11)U] - sum[mh11] = 4.487&lt;br /&gt;Mantel-Fleiss R = min[11.513 ,4.487 ] = 4.487&lt;br /&gt;Mantel-Fleiss criterion NOT satisfied (since R &amp;lt;= 5)&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;原文作者很好心地幫使用者做出該資料是否有滿足 Mantel-Fleiss criterion 的判斷句，所以就不用管上面的數據所代表的意義了，但若在寫 paper 時，可能還是要把一些數據呈現出來，但其實這些數據並沒有解釋上的明顯意義。&lt;br /&gt;&lt;br /&gt;這個例子並沒有滿足 Mantel-Fleiss criterion，也就是說我們得使用 Fisher's exact test 來取代原本的卡方檢定。&lt;br /&gt;&lt;br /&gt;我們再來看另一個有滿足 Mantel-Fleiss criterion 的例子。&lt;br /&gt;&lt;br /&gt;範例二：&lt;br /&gt;&lt;br /&gt;我們直接來看資料的表格結構。&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #4c4c4c; font-family: arial, helvetica, sans-serif; font-size: 12px;"&gt;&lt;img id="imgThumbnail" src="http://rookeryiis2.aviary.com/storage/3432000/3432079_0028_rss.jpg" style="border-bottom-style: none; border-bottom-width: 0px; border-color: initial; border-left-style: none; border-left-width: 0px; border-right-style: none; border-right-width: 0px; border-top-style: none; border-top-width: 0px; border-width: initial;" /&gt;&lt;/span&gt;&lt;br /&gt;所有參數設定都和範例一同樣，只是數據改變而已。執行 macro 後的結果如下：&lt;br /&gt;&lt;code&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;Sum of expected values in cells nh11: sum(mh11) = 19.3630&lt;br /&gt;Sum of lower bound (sum[(nh11)L]) = 9&lt;br /&gt;Sum of upper bound (sum[(nh11)U]) = 30&lt;br /&gt;Left end-point: sum[mh11] - sum[(nh11)L] = 10.363&lt;br /&gt;Right endpoint: sum[(nh11)U] - sum[mh11] = 10.637&lt;br /&gt;Mantel-Fleiss R = min[10.363 ,10.637 ] = 10.363&lt;br /&gt;Mantel-Fleiss criterion satisfied (since R &amp;gt; 5)&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;從最後一句話得知這份資料是有滿足 Mantel-Fleiss criterion 的，所以我們便可以直接使用卡方檢定的結果。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&lt;/b&gt;&lt;br /&gt;Brandon Welch&lt;br /&gt;Rho®, Inc.&lt;br /&gt;Statistical Programming&lt;br /&gt;6330 Quadrangle Dr., Ste. 500&lt;br /&gt;Chapel Hill, NC 27517&lt;br /&gt;Email: Brandon_Welch@rhoworld.com&lt;br /&gt;Phone: 919-595-6339&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-1667469089538034965?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/1667469089538034965/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=1667469089538034965&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/1667469089538034965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/1667469089538034965'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2010/03/macro-for-computing-mantel-fleiss.html' title='A Macro for Computing the Mantel-Fleisś Criterion'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-6068546477592325753</id><published>2009-11-24T23:23:00.000-04:00</published><updated>2009-11-24T23:23:28.276-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程序語法'/><title type='text'>User-Written DATA Step Functions</title><content type='html'>原文載點：&lt;a href="http://docs.google.com/viewer?url=http://www.nesug.org/Proceedings/nesug08/bb/bb13.pdf" target="_blank"&gt;User-Written DATA Step Functions&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;這是一個 SAS V9.2 版新釋出的功能，類似 macro，可自行定義 SAS 沒有的函式（function），並可在不用重複呼叫的情況之下，自由使用於每個 data step 裡面。這個自行定義函式的功能，是由 PROC FCMP 來完成。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;直接來看一個範例：&lt;br /&gt;&lt;code&gt;proc fcmp outlib=sasuser.funcs.trial;&lt;br /&gt;function study_day(intervention_date, event_date);&lt;br /&gt;if event_date &amp;lt; intervention_date then&lt;br /&gt;return(event_date – intervention_date);&lt;br /&gt;else&lt;br /&gt;return(event_date – intervention_date + 1);&lt;br /&gt;endsub;&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;options cmplib=sasuser.funcs;&lt;br /&gt;data _null_;&lt;br /&gt;start = '15Feb2006'd;&lt;br /&gt;today = '27Mar2006'd;&lt;br /&gt;sd = study_day(start, today);&lt;br /&gt;put sd=;&lt;br /&gt;run;&lt;/code&gt;&lt;br /&gt;這個範例可分為兩部分。第一部份使用 PROC FCMP 去製作一個名叫 study_day 的函式，而裡頭包含了兩個參數，一個叫 intervention _date，另一個叫 event_date。裡面的內容包含了一個 if-else- 的條件判斷式，並依照不同的條件傳回 event_date 減去 intervention_date 的天數或 event_date 減去 intervention_date 加一的天數。結束後使用 endsub 把 function 裡面的內容包起來，並將結果存到 sasuser 底下的 funcs 這個資料裡面，並命名為 trials。&lt;br /&gt;&lt;br /&gt;等到要使用時，必須用 options cmplib 把 sasuser.funcs 叫進來，之後便可以無限次的在任何 data step 裡面使用 study_day 這個函式。即便重新開啟 SAS，也不用再跑一次 PROC FCMP 程序，只要執行 options cmplib=sasuser.funcs 這一行後，便可以直接使用 study_day 這個函式了。&lt;br /&gt;&lt;br /&gt;如果想要製作 call routine 的函式，則需要在 PROC FCMP 裡面使用 subroutine statement 來製作。範例如下：&lt;br /&gt;&lt;code&gt;proc fcmp outlib=sasuser.funcs.math;&lt;br /&gt;subroutine subA();&lt;br /&gt;x = 5;&lt;br /&gt;call subB();&lt;br /&gt;put 'In subA:' x=;&lt;br /&gt;endsub;&lt;br /&gt;subroutine subB();&lt;br /&gt;x = 'subB';&lt;br /&gt;put 'In subB:' x=;&lt;br /&gt;endsub;&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;options cmplib=sasuser.funcs;&lt;br /&gt;data _null_;&lt;br /&gt;x = 99;&lt;br /&gt;call subA();&lt;br /&gt;put 'In DATA step: ' x=;&lt;br /&gt;run;&lt;/code&gt;&lt;br /&gt;在這個範例中，PROC FCMP 程序先用 subroutine 製作一個叫做 subA() 的 call routine，其功能是會定義 x=5，並且呼叫另一個 call routine 名為 subB()，最後會在 log 視窗列印出「In subA: x=」的字樣。但 subB() 這個 call routine 也是自創的，所以需要用另一個 subroutine statement 把他的功能寫好。完成後兩個 subroutine statement 都要用 endsub 把 subA() 和 subB() 打包好，如此一來，這個自創的 subA() 就可以在第二部份的 data step 裡面使用。&lt;br /&gt;&lt;br /&gt;原文裡面還有一些更進階的寫法，但我覺得上面兩個範例已經足夠一般使用者來使用，所以就不花篇幅寫進階的教學了，有興趣的人可以自行下載原文來研究。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;CONTACT INFORMATION&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. Contact the author:&lt;br /&gt;Jason Secosky&lt;br /&gt;SAS Institute Inc.&lt;br /&gt;SAS Campus Drive&lt;br /&gt;Cary, NC 27513&lt;br /&gt;919-677-8000&lt;br /&gt;Jason.Secosky@sas.com&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-6068546477592325753?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/6068546477592325753/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=6068546477592325753&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6068546477592325753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6068546477592325753'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2009/11/user-written-data-step-functions.html' title='User-Written DATA Step Functions'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-523864405682283234</id><published>2009-11-24T20:22:00.000-04:00</published><updated>2009-11-24T20:22:39.544-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程序語法'/><title type='text'>Stopping stepwise: Why stepwise and similar selection methods are bad, and what you should use</title><content type='html'>原文連結：&lt;a href="http://docs.google.com/viewer?url=http://www.nesug.org/Proceedings/nesug09/sa/sa01.pdf" target="_blank"&gt;Stopping Stepwise: Why Stepwise Selection Methods are Bad and What you Should use Instead&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;從事統計諮詢工作多年，經常遇到這樣的問題：為什麼經過stepwise過後的線性迴歸結果與預期的相差很大，無法有效解釋。這類問題也反應出理論統計和實際應用上的出入。SAS 在選擇變數的過程中，只能藉由讀進去的數字來套用公式，但每個變數的背後意義，在 SAS 還沒演化成「天網」Skynet 之前，應該是猜不出來。以往的解決方式，通常是希望使用者根據經驗法則，從電腦挑出的變數裡面刪除研究內不會去討論到的變數，或者是從刪除掉的變數裡面強迫加入研究內會討論到的變數。但這些比較主觀的方法，總是有點失去科學性。這篇教學文件主要是回答諸多常用線性迴歸做研究的人內心的疑惑，並使用 PROC GLMSELECT 來解決這個問題。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;早在2001年，Dr. Frank Harrell 就提出傳統的線性迴歸模式選擇法（含backward, forward and stepwise）的盲點，諸如：&lt;br /&gt;。R平方有偏誤（過高）&lt;br /&gt;。參數估計值的標準差太小&lt;br /&gt;。F值或卡方統計量並沒有真正服從F分配或卡方分配&lt;br /&gt;。參數估計值的信賴區間太小&lt;br /&gt;。p-value有偏誤（太小）&lt;br /&gt;。參數估計值（絕對值）太大&lt;br /&gt;。共線性&lt;br /&gt;&lt;br /&gt;有人可能懷疑會不會是因為樣本數不多導致 power 不夠，但這跟模式選擇是沒有太大的關係。原文作者甚至利用模擬的資料來比較 100 subjects 和 1000 subjects 在同一個模式下進行模式選擇，發現 1000 subjects 的結果也沒有來得特別好。&lt;br /&gt;&lt;br /&gt;為了要克服模式選擇的問題，原文作者提出幾個方案：&lt;br /&gt;&lt;br /&gt;&lt;b&gt; (1) A FULL(ER) MODEL&lt;/b&gt;&lt;br /&gt;顧名思義，就是完全不要去做模式選擇，直接用 full model 去分析資料。當然使用這種有點逃避現實的方法很明顯的會出現嚴重的共線性問題。以我個人的經驗來看，為了要規避模式選擇卻讓共線性影響分析的方式並沒有高明到哪裡去。因此我得建議是，共線性分析一定要做，並把他視為模式選擇的替代品。若某個變數不是研究的重點，也沒有統計上的顯著性，又跟其他獨立變數產生高度的相關性時，便可以直接砍除了。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;(2) EXPERT KNOWLEDGE&lt;/b&gt;&lt;br /&gt;這個方法就是我在第一段提到的，使用個人對研究主題和資料背景的認知，主觀地決定什麼變數該留下，什麼變數開刪除。雖然這並不是非常科學的方法，但我一直認為統計分析必須適度跳脫教科書的範疇，在整個統計分析的過程中，完全交由電腦去決定並不是一個百分之百有保障的作法，真正的決策還是得依靠人腦才行。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;(3) MODEL AVERAGING&lt;/b&gt;&lt;br /&gt;這個方法的觀念有點像是在稀釋掉使用 full model 時會造成的問題，其概念是建立數個可能的模式，再利用 AIC 去計算每個變數在每個模式的權重，最後用加權的方法把每個變數在不同模式下的估計值給平均起來。詳細的作法可以參考這本書：&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Burnham, K. P. &amp;amp; Anderson, D. R. (2002), Model selection and multimodel inference, Springer, New York.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;(4) PARTIAL LEAST SQUARES&lt;/b&gt;&lt;br /&gt;這個方法主要是用來解決用主成分分析法（Principal Component Analysis, PCA）建立 PCA regression 以達成變數減少目的所產生不易解釋 PCA 變數的問題。&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&lt;b&gt;(5) LASSO&lt;/b&gt;&lt;br /&gt;這個方法是借用脊迴歸（ridge regression）的參數估計方法來重新估計參數，詳細過程可見：&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Trevor Hastie, R. T. &amp;amp; Friedman, J. (2001), The elements of statistical learning, Springer-Verlag, New York.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;(6) LAR&lt;/b&gt;&lt;br /&gt;Least Angle Regression 的縮寫，其概念是將所有參數中央化，讓所有的參數從零開始，然後再慢慢加上從殘差相關係數所產生的數據。詳細方法可見：&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Bradley Efron, Trevor Hastie, I. J. &amp;amp; Tibshirani, R. (2004), ‘Least angle regression’, Annals of Statistics 32, 407–499.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;(7) CROSS VALIDATION&lt;/b&gt;&lt;br /&gt;類似 bootstrap 和 jackknife 的 resampling 方法，先決定要重複抽出 K 組資料，每一組資料裡面用 (K-1)/K 筆資料去估計模式，剩下的 1/K 筆資料拿來做驗證。&lt;br /&gt;&lt;br /&gt;上述的方法中，LASSO 和 LAR 已經可以透過 PROC GLMSELECT 來完成，此程序的基本語法如下：&lt;br /&gt;&lt;code&gt;PROC GLMSELECT (options);&lt;br /&gt;CLASS variable;&lt;br /&gt;MODEL variable = (effects)/(options);&lt;br /&gt;SCORE (data=dataset) (out=dataset)&lt;/code&gt;&lt;br /&gt;此程式在執行模式選擇的主要關鍵語法是 MODEL statement 後面的 selection=。透過 selection= 這個 option 來指定選模方法和設定變數選取的準則（AIC, AICC, BIC,...,etc）。如果要計算 LASSO 和 LAR，只需要簡單地寫上「selection=LAR」和「selection=LASSO」即可。傳統的 backward、foreward 以及 stepwise 法仍舊可以使用在 PROC GLMSELECT 程序中，但提供額外參數供使用者自行設定，例如：&lt;br /&gt;&lt;br /&gt;selection=forward(select=SL stop=validation)&lt;br /&gt;&lt;br /&gt;selection=backward(select=SL)&lt;br /&gt;&lt;br /&gt;selection=stepwise(select=SL SLE=0.1 SLS=0.08 choose=AIC)&lt;br /&gt;&lt;br /&gt;這些參數其實就跟 PROC REG 裡面會用到的模式選擇參數一樣，在此不額外補充（其實原文裡面也沒有，是我自己從 &lt;a href="http://docs.google.com/viewer?url=http://support.sas.com/rnd/app/papers/glmselect.pdf"&gt;PROC GLMSELECT手冊&lt;/a&gt;裡面添加的）。&lt;br /&gt;&lt;br /&gt;使用 LASSO 和 LAR 法可提供傳統的模式選擇結果出現問題的替代方案，但這兩個方法也不是一本萬利，因為他們也各自有一些假設需要去檢驗。由於原文裡面沒有提到要檢定哪些假設，所以請自行參考原著。但原文作者也提到，這兩個方法仍舊比傳統的 stepwise 要好很多。若今後我有看到有專門在探討這兩種方法的 SAS 技術文件，會再以專文提出。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;CONTACT INFORMATION&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Peter L. Flom&lt;br /&gt;515 West End Ave&lt;br /&gt;Apt 8C&lt;br /&gt;New York, NY 10024&lt;br /&gt;peterﬂomconsulting@mindspring.com&lt;br /&gt;(917) 488 7176&lt;br /&gt;&lt;br /&gt;David L. Cassell&lt;br /&gt;mathematical statistician&lt;br /&gt;Design Pathways&lt;br /&gt;3115 NW Norwood Pl.&lt;br /&gt;Corvallis OR 97330&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-523864405682283234?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/523864405682283234/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=523864405682283234&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/523864405682283234'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/523864405682283234'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2009/11/stopping-stepwise-why-stepwise-and.html' title='Stopping stepwise: Why stepwise and similar selection methods are bad, and what you should use'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-1815028904733537829</id><published>2009-11-18T19:01:00.004-04:00</published><updated>2009-11-18T19:07:44.041-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='其他'/><title type='text'>SAS® Abbreviations Are Your Friends;  Use a Template Method to  Code!</title><content type='html'>原文載點：&lt;i&gt;&lt;a href="http://support.sas.com/resources/papers/proceedings09/073-2009.pdf"&gt;SAS® Abbreviations Are Your Friends; Use a Template Method to Code!&lt;/a&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;SAS 造成許多初學者學習障礙的主要原因是因為語法很多，對於沒有程式撰寫基礎的人來說，門檻可說是相當的高。坊間有許多不同的 SAS 參考書，但內容程度不一，不過有個共同的特點就是，頁數都很多，內容也很雜。通常參考書一開始會從資料格式與輸入開始教，再來是敘述統計量的輸出方法，還有一些簡單的 Proc 程序，然後是作圖，最後通常會用一些函式和 macro 的介紹。印象中自己也買過兩本中文的 SAS 參考書，但必須承認的一件事是：我從來沒有從頭到尾看完過一遍，通常都是要用到某些語法時才去翻。即便自己對 SAS 已屬稍微熟悉，但仍舊沒有辦法記住所有語法，每隔一段時間，某些語法就會從腦海裡面消失，等到要用的時候再去翻書。後來網路發達了，可以用孤狗去搜尋語法，看似比翻書快了一些，但網路搜尋的結果有時候一開始並不是自己真正想要去尋找的目標，也許需要翻個幾頁，開過幾個連結看一下才能找到真正想要的內容。這種情況所消耗的時間可能跟翻書是差不多的。此外，即便是已經熟悉語法了，但可能因為分析內容的需要，必須大量重複使用一些相當簡單比方說 Proc sort 或 Proc print 等程序。Macro 雖然提供了簡化程式行數的功能，但像 Proc sort 或 Proc print 程序本來就不需要花什麼行數，先宣告 macro 並沒有特別節省掉多少程式碼。如果有一種功能，就是當寫程式寫到一半，知道某個語法但忘記裡面要放什麼參數，SAS 能適時給予提醒，或者是利用更簡短的自訂名稱來取代頻繁使用的簡單程序，便可以讓程式撰寫的過程更省時省力。這種功能在 SAS 裡面，叫做「&lt;b&gt;SAS abbreviation&lt;/b&gt;」。&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;假設我們要在一個 data step 裡面使用 tranwrd function，結果打到一半.....&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/422/6830934526.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="164" src="http://easycaptures.com/fs/uploaded/422/6830934526.png" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;發現忘記 tranwrd function 所要用到的第二個和第三個語法，結果只好趕快去翻書或是求救於孤狗大神。但畢竟這個函式並不是每天在使用，所以隔了一個星期後突然又要用到，又得再一次去翻書或上網搜尋。為了避免這種情況，便可以開啟 SAS Abbreviation的功能，來把這些參數的定義註明起來，若下次再遇到時，SAS 便可以馬上提醒該函式的參數用法。方法如下：&lt;br /&gt;&lt;br /&gt;首先，點選 SAS 工具列的「Tools」 ，再點選裡面的「Add Abbreviation」：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/422/9247028027.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/422/9247028027.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;接著會開啟一個新的對話框：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/422/7734074180.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/422/7734074180.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;其中，「Abbreviation」欄位可填上函式名稱 tranwrd，「Text to insert for abbreviation」欄位可填上 tranwrd function 的參數註解。如下所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/422/2899258505.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/422/2899258505.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;輸入好點選 &lt;b&gt;OK&lt;/b&gt; 就大功告成了。&lt;br /&gt;&lt;br /&gt;下次當你要再次使用 tranwrd function 時，打出 tranwrd 則 SAS Abbreviation 會自動啟動，彈出之前新增過的 tranwrd function 註解，如下圖所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/422/3987783419.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/422/3987783419.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;如果你是照著 tranwrd function 的格式去加註解，則看到註解跳出來時，可以直接按 &lt;b&gt;Enter&lt;/b&gt; 或 &lt;b&gt;Tab&lt;/b&gt; 鍵，SAS 會把註解直接輸入到 Editor 裡面。如果你只是要看看，或已經記得了正確完整的寫法，那就可以繼續輸入，不用管拿個字動彈跳出來的註解。&lt;br /&gt;&lt;br /&gt;若你已經完全記住了這個語法，並且保證永遠都不會忘記，那就可以刪除這個註解。刪除的方法是，一樣到 SAS 工具列點選「&lt;b&gt;Tools&lt;/b&gt;」，然後在下拉選單裡面點選「&lt;b&gt;Keyboard Macros&lt;/b&gt;」，再點選「&lt;b&gt;Macros...&lt;/b&gt;」：&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/422/8958964113.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/422/8958964113.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;此時會有一個新的對話視窗彈出，可以看到 tranwrd在一個框框裡面，點選 tranwrd 後再按 &lt;b&gt;Delete&lt;/b&gt; 按鈕即可刪除。如果想要編輯的話，點 &lt;b&gt;Edit&lt;/b&gt; 按鈕即可進行編輯，以下是一個例子。&lt;br /&gt;&lt;br /&gt;假設我們今天有一個模版程式會經常使用，但還沒有需要用到 macro 來寫，如下所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/422/4672814791.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/422/4672814791.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;我們也可以使用上述的方法把這個模版寫進 &lt;b&gt;SAS Abbreviation&lt;/b&gt; 裡面，並且命名為 &lt;i&gt;DataReport&lt;/i&gt;。但用了一陣子之後，發現 PROC REPORT 程序裡面的 Define statement 還滿常用到的，因此想要加入這一行，則一樣操作「Tools -&amp;gt; Keyboard Macros -&amp;gt; Macros -&amp;gt; 選擇 DataReport -&amp;gt; 點 Edit」，之後會彈出下面這個視窗：&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/422/2216263997.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/422/2216263997.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;視窗下方的 &lt;b&gt;Modify&lt;/b&gt; 按鈕會亮起來，點擊下去會彈出第二個視窗：&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/422/7228005714.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/422/7228005714.png" /&gt;&lt;/a&gt;&amp;nbsp; &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;使用者便可以在裡面將 Define的語法輸入到 PROC REPORT 裡面，完畢後按 &lt;b&gt;OK&lt;/b&gt; 鍵。此後，當再一次於 Editor 視窗輸入 &lt;i&gt;DataReport&lt;/i&gt; 並按下 &lt;b&gt;Enter &lt;/b&gt;鍵時，便會出現更新後的模版程式：&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/422/4447993189.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/422/4447993189.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;如果你經常需要使用到某個 SAS Abbreviation，而且你又是個超級懶人的話，SAS 提供熱鍵功能，讓你免於重複輸入，而只需要按個熱鍵便可把模版整個貼上數次。&lt;br /&gt;&lt;br /&gt;定義熱鍵的方法，一樣是「Tools -&amp;gt; Keyboard Macros -&amp;gt; Macros」，然後在視窗內選擇想要設定熱鍵的 SAS Abbreviation，接著點擊右邊的「&lt;b&gt;Assign Keys&lt;/b&gt;」按鈕，會彈出一個新的視窗：&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/422/8865134339.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/422/8865134339.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;接著在「&lt;b&gt;Press new shortcut key&lt;/b&gt;」底下的空白欄位填上你愛用的熱鍵，如「&lt;b&gt;Alt+E&lt;/b&gt;」等等。輸入完畢後，旁邊的「&lt;b&gt;Assign&lt;/b&gt;」按鈕會亮起來，點擊下去後，便會看到這個熱鍵出現在上方的「&lt;b&gt;Current keys&lt;/b&gt;」的空白欄位裡面。點擊下方的 OK 按鈕，便可以在 Keyboard Macros 視窗裡面看到設定好的熱鍵出現在 Keys 的欄位裡面：&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://easycaptures.com/fs/uploaded/422/1185306965.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://easycaptures.com/fs/uploaded/422/1185306965.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;關閉這個對話視窗後，該熱鍵就算是正式可以啟用了。&lt;br /&gt;&lt;br /&gt;原文內還有教導如何在 SAS Enterprise 4.2 裡面使用 SAS Abbreviation 的功能，請有需要的人自行參考原文。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;CONTACT INFORMATION&amp;nbsp; &lt;/b&gt;&lt;br /&gt;Elizabeth Ceranowski &lt;br /&gt;Student Programs Manager &lt;br /&gt;SAS Institute Inc. &lt;br /&gt;SAS Campus Drive &lt;br /&gt;Cary, NC 27513 &lt;br /&gt;Work Phone:&amp;nbsp; (919) 531-9347 &lt;br /&gt;E-mail: Elizabeth.Ceranowski@sas.com&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-1815028904733537829?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/1815028904733537829/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=1815028904733537829&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/1815028904733537829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/1815028904733537829'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2009/11/sas-abbreviations-are-your-friends-use.html' title='SAS® Abbreviations Are Your Friends;  Use a Template Method to  Code!'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-7036525952744732775</id><published>2009-06-18T16:57:00.002-04:00</published><updated>2010-03-21T21:50:43.850-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='其他'/><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><category scheme='http://www.blogger.com/atom/ns#' term='模型配適'/><title type='text'>Examining Mediator and Moderator effect using Rural Women HIV Study</title><content type='html'>原文載點：&lt;a href="https://docs.google.com/viewer?url=http://support.sas.com/resources/papers/proceedings09/191-2009.pdf"&gt;http://support.sas.com/resources/papers/proceedings09/191-2009.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;這一篇技術文件是簡單地利用一個真正的女性HIV資料來教如何使用 SAS 檢定 mediator（或稱 mediation） 和 moderator。關於 mediator 和 moderator 的定義請參照：&lt;br /&gt;&lt;br /&gt;Mediator：&lt;a href="http://davidakenny.net/cm/mediate.htm"&gt;http://davidakenny.net/cm/mediate.htm&lt;/a&gt;&lt;br /&gt;Moderator：&lt;a href="http://davidakenny.net/cm/moderation.htm"&gt;http://davidakenny.net/cm/moderation.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;首先，這個資料背景是來自一個cross-sectional的長期研究裡面所抽出來的第一次面訪資料，總計有 280 位遭到 HIV 感染的女性。&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Baron &amp;amp; Kenny (1986) 首度發表檢測 mediator 的方法，整個流程要跑三個迴歸模式（Eq1, Eq2, Eq3），並且要符合四個準則（C1, C2, C3, C4）。三個迴歸模式分別為：&lt;br /&gt;(Eq1) IV -&amp;gt; DV&lt;br /&gt;(Eq2) IV -&amp;gt; M (Mediator)&lt;br /&gt;(Eq3) IV + M -&amp;gt; DV&lt;br /&gt;&lt;br /&gt;前兩個準則 C1 和 C2 是，如果 Eq1 和 Eq2 都出現顯著的結果，基本上就表示 Mediator 可能是存在的。此外，還需要另兩個存在於 Eq3 的準則需要符合：&lt;br /&gt;(C3) M 在 Eq3 一定要顯著。&lt;br /&gt;(C4) IV 的估計參數在 Eq3 要降到 0。&lt;br /&gt;&lt;br /&gt;若這四個準則都達成了，則可以說這個 M 變數是 full mediator。如果 C4 沒有達成，則稱 M 為 partial mediator。&lt;br /&gt;&lt;br /&gt;最後，再用 Sobel test 來檢定一個 mediator 是否顯著地將 IV -&amp;gt; DV 的總效應完全取代。&lt;br /&gt;&lt;br /&gt;因此，在這個 HIV Women 的資料庫中，定義 Available Social Support (tssqav) 為 IV，Reason for Missing Medication (treas) 為 DV，而 mediator 變數則為 Spiritual Activity (tcopesa)。&lt;br /&gt;&lt;br /&gt;我們可以連續用三個 PROC REG 程序把 Eq1~Eq3 給建立起來：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ods rtf;&lt;br /&gt;ods listing close;&lt;br /&gt;proc reg data=two;&lt;br /&gt;model treas = tssqav / stb pcorr2 scorr2;&lt;br /&gt;title ' Regression model / step1 y=x' ;&lt;br /&gt;run;&lt;br /&gt;proc reg data=two;&lt;br /&gt;model tcopesa = tssqav / stb pcorr2 scorr2;&lt;br /&gt;title ' Regression model / step2 m=x' ;&lt;br /&gt;run;&lt;br /&gt;proc reg data=two;&lt;br /&gt;model treas = tssqav tcopesa / stb pcorr2 scorr2;&lt;br /&gt;title ' Regression model / step3 y=m x' ;&lt;br /&gt;run;&lt;br /&gt;ods rtf close;&lt;br /&gt;ods listing;&lt;br /&gt;quit;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;第一個 PROC REG 得到 β=-0.98 (p-value=0.02)，因此 C1 達成。第二個 PROC REG 程序得到 β=0.143 (p-value=0.003)，因此 C2 也達成。至於 Eq3 的配適結果，得到 (β1, β2)=(-0.79, -0.44)，其 p-value 分別為 0.055 和 0.02，表示 M 在 Eq3 依舊顯著，但 IV 在 Eq3 變成不顯著了。所以基本上 C3 是達成了，但由於 β1 沒有降到接近 0，所以 C4 不算達成，因此 Spiritual Activity 只能稱是個 partial mediator，而不是 full mediator。&lt;br /&gt;&lt;br /&gt;不過本篇技術文件並沒有繼續去做 Sobel test，但前北卡大心理系教授 Dr. Preacher 和 OSU 教授 Dr. Hayes 曾經在 2004 年發表了一篇關於 Sobel test 的論文，裡面有附完整的 Sobel test SAS macro。&lt;br /&gt;&lt;br /&gt;原文：&lt;a href="https://docs.google.com/viewer?url=http://www.comm.ohio-state.edu/ahayes/BRMIC2004.pdf"&gt;http://www.comm.ohio-state.edu/ahayes/BRMIC2004.pdf&lt;/a&gt;&lt;br /&gt;程式：&lt;a href="http://www.comm.ohio-state.edu/ahayes/SPSS%20programs/sobel_sas.sas"&gt;here&lt;/a&gt;&lt;br /&gt;語法：%sobel(data=file, y=dv, x=iv, m=med, boot=z);&lt;br /&gt;&lt;br /&gt;其中，data表示想要呼叫進來使用的資料，y 是放 DV 變數名稱，x 是放 IV 變數名稱， m 是放 mediator 變數名稱，而 boot 則是指定要做 bootstrap resampling 的次數，從 1000 到 1000000 之間任一數字皆可。如果不想用的話就直接寫 0，這樣一來 %sobel 會自動關閉 bootstrap resampling 的功能。&lt;br /&gt;&lt;br /&gt;網路上也有不少的 Sobel test calculator，可自行用 google 搜尋。&lt;br /&gt;&lt;br /&gt;那麼，要進行 moderator 的檢定，則需要配適這個迴歸模型：IV+M+IV*M -&amp;gt; DV。如果 IV*M 的估計參數是顯著的話，則表示 M 是 IV 和 DV 的 moderator。程式如下：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ods rtf;&lt;br /&gt;ods listing close&lt;br /&gt;proc reg data=two;&lt;br /&gt;model treas = tssqav tcopesa sscopesa/ stb pcorr2 scorr2;&lt;br /&gt;title ' Regression model / testing moderator effect' ;&lt;br /&gt;run;&lt;br /&gt;ods rtf close;&lt;br /&gt;ods listing;&lt;br /&gt;quit;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;其中 sscopesa 是 tssqav 和 tcopesa 的交互作用項，這是由於 PROC REG 程序裡面不能使用 tssqav*tcopesa 這種語法來代表交互作用。因此在跑這個程式之前，一定要先用一個 data step 把交互作用項用另一個變數名稱給建立起來。&lt;br /&gt;&lt;br /&gt;最後我們得到 IV*M 的估計參數 β=0.00175，其 p-value=0.5172 並不顯著，因此可以測得 Spiritual Activity 並不是 Moderator。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-7036525952744732775?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/7036525952744732775/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=7036525952744732775&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/7036525952744732775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/7036525952744732775'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2009/06/examining-mediator-and-moderator-effect.html' title='Examining Mediator and Moderator effect using Rural Women HIV Study'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-3982435335620652381</id><published>2009-06-11T15:23:00.010-04:00</published><updated>2011-06-08T13:19:07.574-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程序語法'/><category scheme='http://www.blogger.com/atom/ns#' term='繪圖技巧'/><title type='text'>Using PROC SGPLOT for Quick High-Quality Graphs</title><content type='html'>原文載點：&lt;a href="http://docs.google.com/viewer?url=http://support.sas.com/resources/papers/proceedings09/158-2009.pdf"&gt;http://support.sas.com/resources/papers/proceedings09/158-2009.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;雖然不曉得有多少人已經拿到 SAS V9.2，不過由於我已經拿到了，所以之後會開始陸續介紹一些新版的功能。&lt;br /&gt;&lt;br /&gt;首先先來展示一個 V9.2 最新的繪圖程序—PROC SGPLOT。舊版的 SAS 雖然有提供繪圖程序，但是他們都分散在不同的程序裡面，反而造成使用者的不便。此外，他們的老毛病還是存在，那就是畫出來的圖品質不佳，後來雖然有 ODS 的協助，稍微改善了這方面的缺失，不過 V9.2 版把這些舊的繪圖程序都打包在 PROC SGPLOT 裡面。SGPLOT 顧名思義就是 sophisticated graphical plot 的縮寫，讓我們先來看看這個新繪圖程序的功能。&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;/span&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;span id="fullpost"&gt; &lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;。HISTOGRAMS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;舊版的長條圖要用 PROC GCHART 或 PROC NORMAL 裡面的 HISTOGRAM statement 才能畫出，而且還需要加上許多語法。現在在 PROC SGPLOT 裡面只要使用 HISTOGRAM statement，後面加上變數名稱，就可以完成一個精美的長條圖。&lt;br /&gt;&lt;br /&gt;範例：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span id="fullpost"&gt;PROC SGPLOT DATA = Freestyle;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;   HISTOGRAM Time;&lt;/span&gt;&lt;br /&gt;TITLE "Olympic Men's Swimming Freestyle 100";&lt;br /&gt;RUN;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id="fullpost"&gt;成果：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3617101487" style="width: 379px;"&gt;&lt;span id="fullpost"&gt;&lt;img alt="你拍攝的 image006.jpg。" class="reflect" height="283" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3568/3617101487_82337ba72c.jpg?v=0" title="" width="377" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;&lt;img alt="" src="file:///C:/DOCUME%7E1/lchien/LOCALS%7E1/Temp/moz-screenshot-7.jpg" /&gt;若想要加上機率密度曲線，則只要多寫一行 DENSITY option，並宣告變數名稱即可。&lt;br /&gt;&lt;br /&gt;範例：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span id="fullpost"&gt;PROC SGPLOT DATA = Freestyle;&lt;br /&gt;HISTOGRAM Time;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;   DENSITY Time;&lt;/span&gt;&lt;br /&gt;TITLE "Olympic Men's Swimming Freestyle 100";&lt;br /&gt;RUN;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id="fullpost"&gt;成果：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3617921924" style="width: 380px;"&gt;&lt;span id="fullpost"&gt;&lt;img alt="你拍攝的 image008.jpg。" class="reflect" height="284" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3367/3617921924_26e2a27633.jpg?v=0" title="" width="378" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;。BAR CHARTS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;要畫柱狀圖的的話，原本 PROC GCHART 裡面的 VBAR 和 HBAR 被完全移植過來。&lt;br /&gt;&lt;br /&gt;範例：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span id="fullpost"&gt;PROC SGPLOT DATA = Countries;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;   VBAR Region;&lt;/span&gt;&lt;br /&gt;TITLE 'Olympic Countries by Region';&lt;br /&gt;RUN;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id="fullpost"&gt;成果：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3617101833" style="width: 379px;"&gt;&lt;span id="fullpost"&gt;&lt;img alt="你拍攝的 image010.jpg。" class="reflect" height="283" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3588/3617101833_dd3b8205ba.jpg?v=0" title="" width="377" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;若想要顯示每根 bar 裡面不同群體所佔的比例，則只要在後面加上 GROUP option 即可。&lt;br /&gt;&lt;br /&gt;範例：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span id="fullpost"&gt;PROC SGPLOT DATA = Countries;&lt;br /&gt;VBAR Region / &lt;span style="color: red; font-weight: bold;"&gt;GROUP = PopGroup&lt;/span&gt;;&lt;br /&gt;TITLE 'Olympic Countries by Region and Population Group';&lt;br /&gt;RUN;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id="fullpost"&gt;成果：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3617922492" style="width: 379px;"&gt;&lt;div class="photoImgDiv" id="photoImgDiv3617922308" style="width: 379px;"&gt;&lt;span id="fullpost"&gt;&lt;img alt="你拍攝的 image012.jpg。" class="reflect" height="283" onload="show_notes_initially();" src="http://farm3.static.flickr.com/2425/3617922308_0f8b00c9ea.jpg?v=0" title="" width="377" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;如果要計算次數的目標是另一個變數的話，可以用 RESPONSE option來另外累計。&lt;br /&gt;&lt;br /&gt;範例：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span id="fullpost"&gt;PROC SGPLOT DATA = Countries;&lt;br /&gt;VBAR Region / &lt;span style="color: red; font-weight: bold;"&gt;RESPONSE = NumParticipants&lt;/span&gt;;&lt;br /&gt;TITLE 'Olympic Participants by Region';&lt;br /&gt;RUN;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id="fullpost"&gt;成果：&lt;br /&gt;&lt;img alt="你拍攝的 image014.jpg。" class="reflect" height="283" onload="show_notes_initially();" src="http://farm3.static.flickr.com/2469/3617922492_e25023c2b1.jpg?v=0" title="" width="377" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;。SERIES PLOTS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;畫 X-Y 座標圖的功能被整合進 SERIES statement 中。而且重複呼叫 SERIES statement 的話，可以自動完成重疊圖形的功能，不用像以前一樣一定得加上 overlay option。&lt;br /&gt;&lt;br /&gt;範例：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span id="fullpost"&gt;PROC SGPLOT DATA = Weather;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;   SERIES X = Month Y = BRain;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;   SERIES X = Month Y = VRain;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;   SERIES X = Month Y = LRain;&lt;/span&gt;&lt;br /&gt;TITLE 'Average Monthly Rainfall in Olympic Cities';&lt;br /&gt;RUN;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id="fullpost"&gt;成果：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3617102709" style="width: 380px;"&gt;&lt;span id="fullpost"&gt;&lt;img alt="你拍攝的 image016.jpg。" class="reflect" height="284" onload="show_notes_initially();" src="http://farm3.static.flickr.com/2159/3617102709_60e2c3bfd6.jpg?v=0" title="" width="378" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;接下來看看怎樣替圖形做一些細部的調整。&lt;br /&gt;&lt;span style="font-size: 130%; font-weight: bold;"&gt;&lt;br /&gt;。XAXIS AND YAXIS STATEMENTS&lt;/span&gt;&lt;br /&gt;這兩個 statement 便是拿來更改 X 軸和 Y 軸設定的語法，功能就和以前的 AXIS&lt;span style="font-style: italic;"&gt;n&lt;/span&gt; statement 一樣。從上面的圖可以發現，X-軸代表月份，但是刻度卻是 2.5, 5.0, 7.5, 10.0, 12.5，顯然是不合理的，若加上 TYPE=DISCRETE 則會以實際資料裡面的數據來刻畫度數。GRID 則是在每個刻度上面劃上一條淡灰色的準線。如果 XAXIS 和 YAXIS 都加上 GRID option 的話就可以畫出格狀的底圖。LABEL 自然就是將軸重新命名，而 VALUES 則可以自己定義刻度的起始點和間距大小。&lt;br /&gt;&lt;br /&gt;範例：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span id="fullpost"&gt;PROC SGPLOT DATA = Weather;&lt;br /&gt;SERIES X = Month Y = BRain;&lt;br /&gt;SERIES X = Month Y = VRain;&lt;br /&gt;SERIES X = Month Y = LRain;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;   XAXIS TYPE = DISCRETE GRID;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;   YAXIS LABEL = 'Rain in Inches' GRID VALUES = (0 TO 10 BY 1);&lt;/span&gt;&lt;br /&gt;TITLE 'Average Monthly Rainfall in Olympic Cities';&lt;br /&gt;RUN;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id="fullpost"&gt;成果：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3617923022" style="width: 380px;"&gt;&lt;span id="fullpost"&gt;&lt;img alt="你拍攝的 image018.jpg。" class="reflect" height="284" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3358/3617923022_1dcc16604e.jpg?v=0" title="" width="378" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;。PLOT STATEMENT OPTIONS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;如果想要針對座標軸內的線條圖形或是圖例說明做調整，則需要在 SEREIS statement 後面加上一些 option。LEGENDLABEL 可以更改圖例說明內的標籤，MARKERS 的功能就和以前的 SYMBOL 一樣，可以在資料點上標上符號。LINEATTRS 則是可以規範線條型態和粗細。&lt;br /&gt;&lt;br /&gt;範例：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span id="fullpost"&gt;PROC SGPLOT DATA = Weather;&lt;br /&gt;SERIES X = Month Y = BRain / &lt;span style="color: red; font-weight: bold;"&gt;LEGENDLABEL = 'Beijing' MARKERS LINEATTRS = (THICKNESS = 2);&lt;/span&gt;&lt;br /&gt;SERIES X = Month Y = VRain / &lt;span style="color: red; font-weight: bold;"&gt;LEGENDLABEL = 'Vancouver' MARKERS LINEATTRS = (THICKNESS = 2);&lt;/span&gt;&lt;br /&gt;SERIES X = Month Y = LRain / &lt;span style="color: red; font-weight: bold;"&gt;LEGENDLABEL = 'London' MARKERS LINEATTRS = (THICKNESS = 2);&lt;/span&gt;&lt;br /&gt;XAXIS TYPE = DISCRETE;&lt;br /&gt;TITLE 'Average Monthly Rainfall in Olympic Cities';&lt;br /&gt;RUN;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id="fullpost"&gt;成果：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3617102975" style="width: 380px;"&gt;&lt;span id="fullpost"&gt;&lt;img alt="你拍攝的 image020.jpg。" class="reflect" height="284" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3648/3617102975_c05efe7b0e.jpg?v=0" title="" width="378" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;。REFLINE STATEMENT&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;如果想要在座標圖上加上一些參考線，則可以 REFLINE statement來完成。同樣地，參考線也可以做一些細部設定，比方說透明度可以用 TRANSPARENCY option 來設定，每條參考線也可以用 LABEL option 寫上標籤。&lt;br /&gt;&lt;br /&gt;範例：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span id="fullpost"&gt;PROC SGPLOT DATA = Weather;&lt;br /&gt;SERIES X = Month Y = BRain;&lt;br /&gt;SERIES X = Month Y = VRain;&lt;br /&gt;SERIES X = Month Y = LRain;&lt;br /&gt;XAXIS TYPE = DISCRETE;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;REFLINE 2.03 4.78 1.94 / TRANSPARENCY = 0.5 LABEL = ('Beijing(Mean)' 'Vancouver(Mean)' 'London(Mean)');&lt;/span&gt;&lt;br /&gt;TITLE 'Average Monthly Rainfall in Olympic Cities';&lt;br /&gt;RUN;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id="fullpost"&gt;成果：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3617921354" style="width: 380px;"&gt;&lt;span id="fullpost"&gt;&lt;img alt="你拍攝的 image022.jpg。" class="reflect" height="284" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3411/3617921354_b1ce8ccf67.jpg?v=0" title="" width="378" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;。INSET STATEMENT&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;座標圖內可以用 INSET statement 寫上一些註釋文字，至於位置當然就得用 POSITION option 來設定。若要將註釋文字加框，則簡單地用 BORDER option 即可搞定。&lt;br /&gt;&lt;br /&gt;範例：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span id="fullpost"&gt;PROC SGPLOT DATA = Weather;&lt;br /&gt;SERIES X = Month Y = BRain;&lt;br /&gt;SERIES X = Month Y = VRain;&lt;br /&gt;SERIES X = Month Y = LRain;&lt;br /&gt;XAXIS TYPE = DISCRETE;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;INSET 'Source Lonely Planet Guide'/ POSITION = TOPRIGHT BORDER;&lt;/span&gt;&lt;br /&gt;TITLE 'Average Monthly Rainfall in Olympic Cities';&lt;br /&gt;RUN;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id="fullpost"&gt;成果：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3617101347" style="width: 380px;"&gt;&lt;span id="fullpost"&gt;&lt;img alt="你拍攝的 image024.jpg。" class="reflect" height="284" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3389/3617101347_c2d93f3678.jpg?v=0" title="" width="378" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;。THE SGPANEL PROCEDURE&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;以前如果要針對一個資料集裡面不同的群組或個體畫出各自的圖形並且放在同一張圖裡面，是相當大費周章的事情。現在這種苦差事利用 PROC SPGPANEL 程序即可輕鬆解決。假設我們要畫一個資料集的迴歸線，用 PROC SGPLOT 的 REG statement 就可以畫出。程式如下：&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span id="fullpost"&gt;PROC SGPLOT DATA=sg.countries;&lt;br /&gt;&lt;span style="color: red; font-size: 100%; font-weight: bold;"&gt;REG X=NumParticipants Y=TotalMedals;&lt;/span&gt;&lt;br /&gt;TITLE 'Number of Participants by Total Medals Won for Each Country';&lt;br /&gt;RUN;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id="fullpost"&gt;圖形如下：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3617177061" style="width: 379px;"&gt;&lt;span id="fullpost"&gt;&lt;img alt="你拍攝的 image062.jpg。" class="reflect" height="283" onload="show_notes_initially();" src="http://farm3.static.flickr.com/2437/3617177061_df581f4b45.jpg?v=0" title="" width="377" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;如果這個資料集裡面共包含六個區域，該如何分別製作迴歸圖，並且用 2X3 排成一張圖。程式如下：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span id="fullpost"&gt;PROC SGPANEL DATA=sg.countries;&lt;br /&gt;&lt;span style="color: red; font-size: 100%;"&gt;&lt;span style="font-weight: bold;"&gt;PANELBY Region;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;REG X=NumParticipants Y=TotalMedals;&lt;br /&gt;TITLE 'Number of Participants by Total Medals Won for Each Country';&lt;br /&gt;RUN;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span id="fullpost"&gt;首先呼叫 PROC SGPANEL，再用 PANELBY statement 定義 Region 是類別變數。這功能就很像 CLASS statement。其餘的程式都和之前的 PROC SGPLOT 一樣，結果如下：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3617997730" style="width: 379px;"&gt;&lt;span id="fullpost"&gt;&lt;img alt="你拍攝的 image064.jpg。" class="reflect" height="283" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3101/3617997730_16b1121324.jpg?v=0" title="" width="377" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;這份技術文件裡面有製作幾個表格，分別說明每種圖形要在 PROC SGPLOT 裡面用哪一種 statement，以及選了一些比較重要的 option，如下所示：&lt;br /&gt;&lt;img src="http://farm3.static.flickr.com/2458/3617161271_b809c22dee_o.png" /&gt;&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3406/3617162147_881ba62468_o.png" /&gt;&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3647/3617983280_887d5ec71f_o.png" /&gt;&lt;br /&gt;&lt;img src="http://farm3.static.flickr.com/2473/3617983972_f8d5ba9af8_o.png" /&gt;&lt;br /&gt;&lt;br /&gt;由於裡面的敘述都很簡單，各位可以自行下載原始檔案來看。不過這些語法都只是整個 PROC SGPLOT 裡面的九牛一毛而已，當然如果都學會的話應該也夠用了。如果想要知道全部的語法，可以到 SAS 官網去看。&lt;br /&gt;&lt;br /&gt;網址：&lt;a href="http://support.sas.com/documentation/cdl/en/grstatproc/61948/HTML/default/sgplot-stmt.htm"&gt;http://support.sas.com/documentation/cdl/en/grstatproc/61948/HTML/default/sgplot-stmt.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;ABOUT THE AUTHORS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Lora Delwiche and Susan Slaughter are the authors of The Little SAS Book: A Primer, and The Little SAS Book for&lt;br /&gt;Enterprise Guide which are published by SAS Institute. The authors may be contacted at:&lt;br /&gt;Lora D. Delwiche&lt;br /&gt;(530) 752-9321&lt;br /&gt;llddelwiche@ucdavis.edu&lt;br /&gt;&lt;br /&gt;Susan J. Slaughter&lt;br /&gt;(530)756-8434&lt;br /&gt;susan@avocetsolutions.com&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-3982435335620652381?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/3982435335620652381/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=3982435335620652381&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/3982435335620652381'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/3982435335620652381'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2009/06/using-proc-sgplot-for-quick-high.html' title='Using PROC SGPLOT for Quick High-Quality Graphs'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-441974092118506074</id><published>2009-04-27T16:44:00.003-04:00</published><updated>2010-07-23T16:11:12.911-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程序語法'/><category scheme='http://www.blogger.com/atom/ns#' term='其他'/><title type='text'>Updates to SAS® Power and Sample Size Software in SAS/STAT® 9.2</title><content type='html'>原文載點：&lt;a href="http://www2.sas.com/proceedings/forum2008/368-2008.pdf"&gt;http://www2.sas.com/proceedings/forum2008/368-2008.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;SAS V9.2 釋出已經有一段時間，雖然仍舊有很多學校機關沒有升級到最新的版本，而仍舊沿用 V9.1.3，不過我已經用新版差不多快四個月的時間，所以之後會慢慢來介紹 V9.2 的新功能。這篇技術文件首先是來介紹新版的 proc power 以及 proc glmpower 所帶來的新的功能。&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;1. LOGISTIC REGRESSION&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;新版的 proc power 已經可以計算 logistic regression 下的 power analysis。範例如下：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;pre&gt;&lt;code&gt;proc  power;&lt;br /&gt;logistic&lt;br /&gt;alpha  =  0.05&lt;br /&gt;vardist(’Duration’)  =  normal(4,  1.5)&lt;br /&gt;testpredictor  =  ’Duration’&lt;br /&gt;testoddsratio  =  1.7&lt;br /&gt;responseprob  =  0.65&lt;br /&gt;ntotal  =  50  60  70&lt;br /&gt;power  =  .  ;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;語法的使用方法如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;logistic：呼叫 logistic regression 下的 power analysis。&lt;/li&gt;&lt;li&gt;alpha：設定顯著水準。&lt;/li&gt;&lt;li&gt;vardist：設定 testpredictor 所指定的因變數 X 的分配，記得要再 vardist 後面用 ('....') 寫上在 testpredictor 一樣的變數名稱。此例是設定變數 Duration 的分配是 Normal(4, 1.5)。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;testpredictor：因變數名稱&lt;/li&gt;&lt;li&gt;testoddsratio：因變數的 OR&lt;br /&gt;&lt;/li&gt;&lt;li&gt;responseprob：反應變數 Y 的機率&lt;/li&gt;&lt;li&gt;ntotal：樣本總數&lt;/li&gt;&lt;li&gt;power：power 設定值。&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;用法和一般的 proc power 一樣，如果要計算某個樣本下的 power，則 power option 後面就要打個 dot。如果已經決定了 power，想要知道多少的樣本才能滿足，則在 power option 後面填上設定值，在 ntotal option 後面打個 dot。&lt;br /&gt;&lt;br /&gt;此範例的報表結果如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3483557075" style="width: 502px;"&gt;&lt;img alt="你拍攝的 2009-04-28_1637。" class="reflect" height="267" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3300/3483557075_72b5936b95.jpg?v=0" title="" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;由於此例一口氣設定了三個樣本數（50, 60, 70），所以報表裡面也列出三個樣本數所產生的 power 值（0.664, 0.742, 0.805）。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;2. CONFIDENCE INTERVAL FOR ONE PROPORTION&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;新版的 proc power 可以計算一個二項變數比例的信賴區間。此功能跟 proc freq 一樣。範例如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc  power;&lt;br /&gt;onesamplefreq  ci  =  Wilson&lt;br /&gt;alpha  =  0.05&lt;br /&gt;proportion  =  0.3&lt;br /&gt;halfwidth  =  0.1&lt;br /&gt;ntotal  =  70&lt;br /&gt;probwidth  =  .;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;語法解釋如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;onesamplefreq ci：計算係賴區間的方式。此例用 Wilcox score。另外五種分別為：Wald, continuity-corrected Wald, exact, Agresti-Coull, and Jeffreys&lt;br /&gt;&lt;/li&gt;&lt;li&gt;alpha：顯著水準&lt;/li&gt;&lt;li&gt;proportion：該二項變數的比例。&lt;/li&gt;&lt;li&gt;halfwidth：設定信賴區間一半的寬度。&lt;/li&gt;&lt;li&gt;ntotal：樣本總數。&lt;/li&gt;&lt;li&gt;probwidth：信賴區間&lt;/li&gt;&lt;/ul&gt;此例是計算一個比例為 0.3 的信賴區間寬度。由於程式中設定整個信賴區間的長度是 0.2（halfwidth*2），所以 probwidth 算出來的結果一定會小於 halfwidth*2。結果如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3484589742" style="width: 502px;"&gt;&lt;img alt="你拍攝的 2009-04-28_1649.png。" class="reflect" height="229" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3333/3484589742_4168b521da.jpg?v=0" title="" width="500" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;3. WILCOXON MANN-WHITNEY TEST FOR TWO INDEPENDENT GROUPS&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Wilcoxon Mann-Whitney test 底下的 power analysis 在新版中也可以計算出來了，但只限定於兩個獨立樣本的檢定。範例如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc  power;&lt;br /&gt;twosamplewilcoxon&lt;br /&gt;alpha  =  0.05&lt;br /&gt;vard   ist(’lidocaine’)  =&lt;br /&gt;ordinal(  (-3  -2  -1  0  1  2  3):  (.01  .04  .20  .50  .20  .04  .01)  )&lt;br /&gt;vardist(’mironel  plus  lidocaine’)  =&lt;br /&gt;ordinal(  (-3  -2  -1  0  1  2  3):  (.01  .03  .15  .35  .30  .10  .06)  )&lt;br /&gt;variables  =  ’lidocaine’  |  ’mironel  plus  lidocaine’&lt;br /&gt;sides  =  u&lt;br /&gt;ntotal  =  .&lt;br /&gt;power  =  0.85;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;語法解釋如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;twosamplewilcoxon：呼叫兩獨立樣本檢定的 power analysis。&lt;/li&gt;&lt;li&gt;alpha：顯著水準。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;vardist：指定 group 變數的屬性。以此為例，兩個變數都是 ordinal，並且每個類別（-3  -2  -1  0  1  2  3）對應到的機率（.01  .04  .20  .50  .20  .04  .0）都必須要寫上。由於有兩個 group 要比較，所以必須宣告 vardist 兩次。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;variables：指定兩個 group variable 的變數名，中間記得用「|」隔開來。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;sides：標明該檢定單尾還是雙尾，此例用「u」表單尾。&lt;/li&gt;&lt;li&gt;ntotal：樣本總數。&lt;/li&gt;&lt;li&gt;power：power設定值。&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;此例兩個要比較的群組分別是 lidocaine 和 mironel plus lidocane，要計算在 power=0.85 底下要多少樣本才夠，結果如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3483776619" style="width: 502px;"&gt;&lt;img alt="你拍攝的 2009-04-28_1754.png。" class="reflect" height="279" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3616/3483776619_c63b48db7d.jpg?v=0" title="" width="500" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;此外，SAS V9.2 中也設計了視窗介面來執行 power analysis。其實前幾個版本的 SAS 大概覺得受到 SPSS 或其他類似視窗介面型的統計軟體的威脅，在 V6.0 之後開始加入視窗分析介面，但總是讓人有種畫虎不成反類犬的情況。V9.2 版的情況大概也不可能一下跳升到 SPSS 或 Statistica 那種程度，更何況個人是覺得真要用視窗分析介面的話，SAS 的副產品「JMP」就可以辦到了，SAS 也不用特定來搞這塊。無論如何，從這份技術文件上，我們可以看到新版的視窗分析介面的確有點改進。以下是一些截圖：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3483777101" style="width: 502px;"&gt;&lt;img alt="你拍攝的 2009-04-28_1800.png。" class="reflect" height="428" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3594/3483777101_d1e4b78c6e.jpg?v=0" title="" width="500" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3483777499" style="width: 502px;"&gt;&lt;img alt="你拍攝的 2009-04-28_1806.png。" class="reflect" height="448" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3313/3483777499_89eef74968.jpg?v=0" title="" width="500" /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="photoImgDiv" id="photoImgDiv3483776281" style="width: 502px;"&gt;&lt;img alt="你拍攝的 2009-04-28_1807.png。" class="reflect" height="356" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3403/3483776281_b0900b6202.jpg?v=0" title="" width="500" /&gt;&lt;/div&gt;&lt;/span&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;但由於不覺得真的有到很方便的地步，所以建議還是用寫程式的方法來進行 power analysis。&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;CONTACT INFORMATION&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Wayne Watson&lt;br /&gt;Building S, Room 3040&lt;br /&gt;SAS Institute, Inc.&lt;br /&gt;SAS Campus Drive&lt;br /&gt;Cary, NC 27513&lt;br /&gt;Work Phone: 919-531-6770&lt;br /&gt;E-mail: wayne.watson@sas.com&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-441974092118506074?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/441974092118506074/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=441974092118506074&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/441974092118506074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/441974092118506074'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2009/04/updates-to-sas-power-and-sample-size.html' title='Updates to SAS® Power and Sample Size Software in SAS/STAT® 9.2'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-4049822009923207473</id><published>2008-11-10T03:47:00.000-04:00</published><updated>2008-11-10T03:47:00.937-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='資料整理'/><title type='text'>Combining, Combining, Combining, Splitting, Splitting, Splitting</title><content type='html'>原文載點：&lt;a href="http://www.nesug.info/Proceedings/nesug06/dm/da30.pdf"&gt;http://www.nesug.info/Proceedings/nesug06/dm/da30.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;這是一篇教導如何使用 data step 和 proc sql 合併和分割資料的 SAS 技術文件，由 Emmy Pahmer 於 NESUG 2006 發表。&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;本文所使用的範例如下：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-11-03_1353。" src="http://farm4.static.flickr.com/3007/3000351632_96276192da.jpg?v=0" onload="show_notes_initially();" height="156" width="265" /&gt;&lt;br /&gt;這筆資料總共只有五個觀測值，每個觀測值包含三個變數：年齡、姓名和性別。其中第五個觀測值的性別是打錯的 G。&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;。分割資料&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;若想要將上述資料依照性別切割成兩個分開的資料集，則有下列幾種方式。&lt;br /&gt;&lt;br /&gt;1. 使用兩個 data step：這是最笨但也是最直接的方式。程式碼如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data males;&lt;br /&gt;    set everyone;&lt;br /&gt;    if sex = 'M';&lt;br /&gt;run;&lt;br /&gt;data females;&lt;br /&gt;    set everyone;&lt;br /&gt;    if sex = 'F';&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;2. 使用兩個 data step 配合 where：這個方法僅僅是縮短程式碼行數。程式碼如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data female;&lt;br /&gt;    set everyone&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt; (where=(sex=’F’))&lt;/span&gt; ;&lt;br /&gt;run;&lt;br /&gt;data male;&lt;br /&gt;    set everyone&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt; (where=(sex=’M’))&lt;/span&gt; ;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;有此程式可知，這只是把 IF 的指令改成 WHERE 並放在 SET 後面。對行數來說，的確是減少了，不過打的字變多了，因為 WHERE 後面的條件式要加上括弧。&lt;br /&gt;&lt;br /&gt;3. 使用兩個 data step 配合 where：這個方法僅僅是把 WHERE 從 SET 移到 DATA 後面，並沒有太特別的地方。程式碼如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data female &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;(where= (sex = ‘F’))&lt;/span&gt; ;&lt;br /&gt;    set everyone ;&lt;br /&gt;run;&lt;br /&gt;data male&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt; (where= (sex = ‘M’))&lt;/span&gt; ;&lt;br /&gt;    set everyone ;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;4. 使用一個 data step 並配合 IF...ELSE... 和 OUTPUT：這是比較進階的方式，可以大幅縮短程式碼的行數。如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data males females;&lt;br /&gt;    set everyone;&lt;br /&gt;    &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;if sex = 'F' then output females;&lt;/span&gt;&lt;br /&gt;    &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;else if sex = 'M' then output males;&lt;/span&gt;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;由於本資料中某觀測值的性別是打錯的。為了確定有沒有這類的情況，當資料相當龐大時，建議使用下列程式碼：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data males females;&lt;br /&gt;    set everyone;&lt;br /&gt;    if sex = 'F' then output females;&lt;br /&gt;        else if sex = 'M' then output males;&lt;br /&gt;            &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;else put “Neither F nor M - check “ _all_;&lt;/span&gt; &lt;span style="color: rgb(0, 153, 0); font-weight: bold;"&gt;*or output to another dataset ;&lt;/span&gt;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;其中紅色那行的程式碼會讓性別變數不是 F 和 M 的觀測值通通分類到 _all_ 這個資料集中。亦或是另外定義一個資料集把他們 output 進去。當打開這個資料集時，如果裡面是空的，就可以確定沒有打錯的情況產生。&lt;br /&gt;&lt;br /&gt;5. 使用一個 data step 並配合 WHERE：這是從方法二改良來。程式碼如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;female (where=(sex=’F’)) male (where=(sex=’M’))&lt;/span&gt; ;&lt;br /&gt;    set everyone ;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;這個程式碼比方法四 要來的更精簡精簡。如果想要擁有方法三第二個可以偵測有沒有打錯的資料，則可以改進如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data female (where=(sex=’F’)) male (where=(sex=’M’)) &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;checkothers (where = (sex not in (‘M’,’F’)))&lt;/span&gt; ;&lt;br /&gt;    set everyone ;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;道理同方法四，把 sex 不是 M 和 F 的通通丟到 checkothers 這個資料集裡面，然後再去看看該資料集是不是空的。&lt;br /&gt;&lt;br /&gt;6. 使用 proc sql：使用 proc sql 看起來好像比較高檔，但是行數並沒有減少。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sql;&lt;br /&gt;    create table males as&lt;br /&gt;    select *&lt;br /&gt;    from everyone (where=(sex='M'));&lt;br /&gt;    create table females as&lt;br /&gt;    select *&lt;br /&gt;    from everyone (where=(sex='F'));&lt;br /&gt;quit;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;7. 使用一個 data step 把 不同的變數放到不同的資料集：若想要把 who 和 age 放到新資料集 age，然後再把 who 和 sex 放到新資料集 sex，則可仿照方法五來切割。程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data age (keep = who age) sex (keep = who sex);&lt;br /&gt;    set everyone;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;8. 使用 proc sql 完成方法七：程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sql;&lt;br /&gt;    create table age as&lt;br /&gt;    select who, age&lt;br /&gt;    from everyone;&lt;br /&gt;    create table sex as&lt;br /&gt;    select who, sex&lt;br /&gt;    from everyone;&lt;br /&gt;quit;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;感覺行數沒有減少很多，只是寫法比較接近口語。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;。合併資料&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;這回使用兩筆資料，如下所示：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-11-03_1421。" src="http://farm4.static.flickr.com/3157/2999588821_eabd73ba2b.jpg?v=0" onload="show_notes_initially();" height="340" width="489" /&gt;&lt;br /&gt;其中 EVERYONE 這筆和之前用的一樣，而新的 ACTIVITY 資料有一點要特別注意的是它並沒有排序過。為什麼要特別強調這一點，理由是在 SAS 的合併過程中，一定要設定一個 index variable，這樣 SAS 才有辦法依照那個 index variable 來進行資料合併。而那個被設定成 index variable 的變數一定要經過排序，否則 SAS 在合併的過程中會錯亂掉。這個錯亂有時候還是會給你 output，只是結果是錯的。如果一時忽略沒有看到 log 視窗上面的警告訊息，就完蛋了。因此若要依照「who」這個變數來合併這兩組資料，則必須要先用 PROC SORT 把該變數排序：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sort data=activity;&lt;br /&gt;    by who;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;而通常要養成一個好習慣就是所有合併的資料最好都給他排序一下，免得有漏網之魚。反正 PROC SORT 的程式碼很簡單，多寫幾行比較安心：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sort data=everyone;&lt;br /&gt;    by who;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;然後用 merge 和 by 來合併：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data combined_11;&lt;br /&gt;    &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;merge&lt;/span&gt; everyone activity;&lt;br /&gt;    &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;by who;&lt;/span&gt;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;結果如下：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-11-03_1427。" src="http://farm4.static.flickr.com/3172/3000445170_34dec791b1.jpg?v=0" onload="show_notes_initially();" height="196" width="370" /&gt;&lt;br /&gt;從上表得知，Annie, Bill, Chandra, Igor, Jose 和 Karen 在 ACTIVITY 裡面有資料，所以合併時會顯示在 activity 這個變數底下，但 David 和 Eleanor 則沒有出現在 ACTIVITY 裡面，所以合併後他們兩人的 activity 變數就變成 missing data 了。Age 也是同樣的道理。&lt;br /&gt;&lt;br /&gt;如果只想顯示同時出現在兩個資料的觀測值，則必須啟用 in 這個指令。程式碼如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data combined_12;&lt;br /&gt;    merge everyone&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt; (in = in_a)&lt;/span&gt; activity&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt; (in = in_b)&lt;/span&gt;;&lt;br /&gt;    by who;&lt;br /&gt;    &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;if in_a and in_b;&lt;/span&gt;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;使用 in 這個指令會讓 SAS 在合併的過程中，於兩組資料裡面各加上一個隱藏的變數，分別名為 in_a 和 in_b，其數值都預設為 1。合併之後在程式裡面加上「if in_a and in_b;」來讓 SAS 挑出同時具有 in_a=1 和 in_b=1 的觀測值（要打成「if in_a=1 and in_b=1;」也可以），缺少任一個變數的觀測值則會自動被剔除。結果如下：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-11-03_1433。" src="http://farm4.static.flickr.com/3253/2999622637_4bd5f7b827.jpg?v=0" onload="show_notes_initially();" height="90" width="388" /&gt;&lt;br /&gt;如果想要知道哪些觀測值被剔除，可使用下列程式碼：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data combined_14;&lt;br /&gt;    merge everyone (in = in_a) activity (in = in_b);&lt;br /&gt;    by who;&lt;br /&gt;    if in_a and in_b then output;&lt;br /&gt;        &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;else if in_a then put "In A only: " Who=; &lt;span style="color: rgb(0, 153, 0);"&gt;*or output to another dataset ;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;else if in_b then put "In B only: " Who=;&lt;/span&gt;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;最後那兩個 else if... 會讓程式在 log 視窗印出下列字樣：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-11-03_1437。" src="http://farm4.static.flickr.com/3296/3000472224_47d61f37ab.jpg?v=0" onload="show_notes_initially();" height="106" width="246" /&gt;&lt;br /&gt;&lt;br /&gt;同樣地，proc sql 也可達成同樣效果：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sql;&lt;br /&gt;    create table combined_15a as&lt;br /&gt;    select a.*, b.activity, b.sex&lt;br /&gt;    from everyone as a, activity as b&lt;br /&gt;    where a.who = b.who&lt;br /&gt;    order by activity&lt;br /&gt;    ;&lt;br /&gt;quit;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;或者&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sql;&lt;br /&gt;    create table combine_15b as&lt;br /&gt;    select a.*, b.activity, b.sex&lt;br /&gt;    from everyone as a inner join activity as b&lt;br /&gt;    on a.who = b.who&lt;br /&gt;    ;&lt;br /&gt;quit;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;但由於 proc sql 的指令比較麻煩，所以還是建議使用 data step 來完成。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;CONTACT INFORMATION&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. Contact the author at:&lt;br /&gt;Emmy Pahmer&lt;br /&gt;MDS Pharma Services&lt;br /&gt;St. Laurent, Québec&lt;br /&gt;Work Phone: (514) 333-0042 ext. 4222&lt;br /&gt;E-mail: emmy.pahmer@mdsinc.com&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-4049822009923207473?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/4049822009923207473/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=4049822009923207473&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/4049822009923207473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/4049822009923207473'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2008/11/combining-combining-combining-splitting.html' title='Combining, Combining, Combining, Splitting, Splitting, Splitting'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-316321631603740487</id><published>2008-11-01T01:17:00.001-04:00</published><updated>2008-11-02T17:04:54.394-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='報表輸出'/><title type='text'>Funny ^Stuff~ in My Code – Using ODS ESCAPECHAR</title><content type='html'>原文載點：&lt;a href="http://www2.sas.com/proceedings/forum2007/099-2007.pdf"&gt;http://www2.sas.com/proceedings/forum2007/099-2007.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;SAS 的 ODS 系統通常是拿來把報表另存成新的資料或者是列印出比較精緻的格式出來。但大多數的人可能不知道 ODS 還可以像 Word 一樣編輯報表，舉凡加上顏色、字型粗細大小、甚至是上標下標、放特殊符號，通通可以在 ODS 裡面完成。Cynthia L. Zender 於 SAS Global Forum 2007 發表的技術文件教導使用者如何來完成這些動作。&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;在決定使用 ODS 來編輯文件時，必須先宣告要使用哪種特殊符號來命令 ODS 開始進行一些動作。這個宣告得用 ods escapechar 來完成。比方：&lt;br /&gt;ods escapechar='^';&lt;br /&gt;ods escapechar='~';&lt;br /&gt;ods escapechar='#';&lt;br /&gt;接下來的範例接使用「^」符號來命令 ODS 編輯文件。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;範例一：編輯文字&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;一個很簡單例子。假設要列印出某個字串變數，資料如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data use_esc;&lt;br /&gt;  length var1 $200;&lt;br /&gt;  var1 = "The quick brown fox";&lt;br /&gt;  output;&lt;br /&gt;run;&lt;br /&gt;ods html;&lt;br /&gt;proc print data=use_esc;&lt;br /&gt;run;&lt;br /&gt;ods html close;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;則 ODS 只會印出下面這種相當單調的結果：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-10-24_1546。" src="http://farm4.static.flickr.com/3239/2969337609_38a58f82b4.jpg?v=0" onload="show_notes_initially();" height="91" width="226" /&gt;&lt;br /&gt;下面的程式將可改變字體的粗細、字型和字的顏色：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data use_esc;&lt;br /&gt;  length var1 $200;&lt;br /&gt;  var1 = "The quick brown fox";&lt;br /&gt;  output;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;var1 = "The ^S={font_weight=bold}quick ^S={} brown fox";&lt;/span&gt;&lt;br /&gt;  output;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;var1 = "The quick ^S={foreground=brown}brown ^S={}fox";&lt;/span&gt;&lt;br /&gt;  output;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;var1 = "The quick brown ^S={font_face='Courier New'}fox ^S={}";&lt;/span&gt;&lt;br /&gt;  output;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;var1 = "The ^S={font_weight=bold}quick ^S={}" ||&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;"^S={foreground=brown}brown ^S={}"||&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;"^S={font_face='Courier New'}fox ^S={}";&lt;/span&gt;&lt;br /&gt;  output;&lt;br /&gt;run;&lt;br /&gt;ods html style=sasweb;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;ods escapechar='^';&lt;/span&gt;&lt;br /&gt;proc print data=use_esc;&lt;br /&gt;run;&lt;br /&gt;ods html close;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;首先，在原先的 data step 裡面加上紅色部分的程式碼。其中，「^」就是用來宣告之後的 ODS 要進行某些動作。S={} 即是用來編輯。以第一個紅色程式碼來看，^S={font_weight=bold} 接在 quick 前面即是要讓 quick 變成粗體的 &lt;span style="font-weight: bold;"&gt;quick&lt;/span&gt;。第二個紅色程式碼 ^S={foreground=brown} 是將 brown 的顏色變更為棕色的 &lt;span style="color: rgb(153, 0, 0);"&gt;brown&lt;/span&gt;。第三個紅色程式碼 ^S={font_face='Courier New'} 即是變更 fox 的字型為 Courier New 的 &lt;span style="font-family:courier new;"&gt;fox&lt;/span&gt;。所有的動作完成後都必須要在後面加上 ^S={}，ODS 才會停止編輯。如果沒有 ^S={} 來中斷，則之前所宣告的編輯動作將會繼續套用在後面的內容中。第四個紅色程式碼比較複雜，這是將前三個紅色程式碼合併。此處將 quick, brown 和 fox 拆成三段，編輯過後用連接符號「||」將結果串起來。但根據我自己試驗的結果，不需要那麼麻煩，直接寫成下列的程式碼也可以做出同樣的效果：&lt;br /&gt;var1 = "The ^S={font_weight=bold}quick ^S={} ^S={foreground=brown}brown ^S={} ^S={font_face='Courier New'}fox ^S={}";&lt;br /&gt;最後，在宣告 ods html 之後，不要忘了加上 ods escapechar='^' 來讓 ODS 知道之前使用的「^」符號是要叫 ODS 做一些編輯動作。&lt;br /&gt;&lt;br /&gt;執行後的結果如下所示：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-10-24_1559。" src="http://farm4.static.flickr.com/3216/2969363581_eb20b8787b.jpg?v=0" onload="show_notes_initially();" height="303" width="294" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;範例二：加上特殊符號&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;特殊符號的通常用在數學方程式、註解、或化學式裡面。而使用方式也不像編輯文字一樣要用 ^S={&lt;span style="font-style: italic;"&gt;options&lt;/span&gt;} 來宣告，而只要用 ^={&lt;span style="font-style: italic;"&gt;options&lt;/span&gt;} 即可。假設想要做出下面這種表格：&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3242/2970221528_3b6f8a92cb_o.png" /&gt;&lt;br /&gt;&lt;br /&gt;則可使用下列程式：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data sup_sub;&lt;br /&gt;  length myvar $200;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;myvar = "Pythagorean Theorem: a^{super 2} + b^{super 2} = c^{super 2}";&lt;/span&gt;&lt;br /&gt;  output;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;myvar = "This is something that needs a footnote. ^{super 1}";&lt;/span&gt;&lt;br /&gt;  output;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;myvar = "Macbeth: 'Is this a dagger I see before me?' ^{dagger}";&lt;/span&gt;&lt;br /&gt;  output;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;myvar = "The Caffeine molecule is an alkaloid of the methylxanthine family: " ||&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;"C^{sub 8}H^{sub 10}N^{sub 4}O^{sub 2}";&lt;/span&gt;&lt;br /&gt;  output;&lt;br /&gt;run;&lt;br /&gt;ods html file='inline2.html' style=sasweb;&lt;br /&gt;ods rtf file='inline2.rtf' notoc_data;&lt;br /&gt;ods pdf file='inline2.pdf';&lt;br /&gt;ods escapechar='^';&lt;br /&gt;proc print data=sup_sub;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;title j=r 'PDF &amp;amp; RTF: Page ^{thispage} of ^{lastpage}';&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;title2 j=c 'RTF only: ^{pageof}';&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;footnote '^{super 1}If this were a real footnote, there would be something very                            &lt;/span&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;academic here.';&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;footnote2 '^{dagger} Macbeth talked to himself a lot. This quote is from Macbeth: &lt;/span&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;Act 2, Scene 1, Lines 33-39.';&lt;/span&gt;&lt;br /&gt;run;&lt;br /&gt;ods _all_ close;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;在第一個紅色程式碼中，畢氏定理需要在 a, b, c 各上標一個「2」，這個動作用 ^{super 2} 即可完成。換句話說，super 這個指令在 ^{} 裡面就是拿來做上標用的。第二個紅色程式碼同樣也是要將最後的 1 給上標，所以使用 ^{super 1} 來完成。第三個紅色程式碼同樣也是要加上一個特殊符號當作註解符號。而這個小小的十字架需要使用 ^{dagger} 才能呼叫出來。第四個紅色程式碼是要編輯一個化學方程式，讓一些數字在英文字旁邊坐下標，所以這個動作就得用 ^{sub n} 來完成。接著看最後 proc print 裡面的紅色程式碼。裡面用兩個 title 指令和 footnote 指令來完成表格標題和註解的動作。其中，在 title 裡面，^{thispage} 和 ^{lastpage} 只會作用於 ods rtf 或 ods pdf 裡面。這兩個指令會自動將整份文件的頁數已經該頁是屬於第幾頁列印出來。但這個功能在 ods html 顯示不出來。所以 ^{thispage} 和 ^{lastpage} 在 html 報表裡面會變成空白。同樣地，title2 是讓標題顯示這屬於整份文件的第幾頁，使用 ^{pageof} 來執行。可是這個指令只能在 rtf 文件裡面才會有作用，在 pdf 裡面將會把 ^{pageof} 原封不動地印出來，但在 html 文件裡面則會變成空白。&lt;br /&gt;&lt;br /&gt;這是 rtf 文件的結果：&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3224/2969417469_26055a577f_o.png" /&gt;&lt;br /&gt;這是 pdf 文件的結果：&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3067/2970261440_d77bf2cf93_o.png" /&gt;&lt;br /&gt;&lt;br /&gt;範例三：折行&lt;br /&gt;&lt;br /&gt;如果一串文字太常，如上例的第四個化學方程式，則可使用折行的指令來讓字串在某處斷行。這個動作只要簡單地在宣告符號後面加上個「n」或「an」(a=任意數字)即可。程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data linebr;&lt;br /&gt;  length myvar $200;&lt;br /&gt;  myvar ="The Caffeine molecule is an alkaloid of the methylxanthine family: &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;~n&lt;/span&gt;" ||&lt;br /&gt;" C~{sub 8}H~{sub 10}N~{sub 4}O~{sub 2}";&lt;br /&gt;  output;&lt;br /&gt;  myvar ="The Caffeine molecule is an alkaloid of the methylxanthine family: &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;~2n&lt;/span&gt;" ||&lt;br /&gt;" C~{sub 8}H~{sub 10}N~{sub 4}O~{sub 2}";&lt;br /&gt;  output;&lt;br /&gt;  myvar ="The Caffeine molecule is an alkaloid of the methylxanthine family: &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;~3n&lt;/span&gt;" ||&lt;br /&gt;" C~{sub 8}H~{sub 10}N~{sub 4}O~{sub 2}";&lt;br /&gt;  output;&lt;br /&gt;  myvar ="The Caffeine molecule is an alkaloid of the methylxanthine family: &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;~4n&lt;/span&gt;" ||&lt;br /&gt;" C~{sub 8}H~{sub 10}N~{sub 4}O~{sub 2}";&lt;br /&gt;  output;&lt;br /&gt;run;&lt;br /&gt;ods listing;&lt;br /&gt;ods html file='inline3.html' style=sasweb;&lt;br /&gt;ods rtf file='inline3.rtf' notoc_data;&lt;br /&gt;ods pdf file='inline3.pdf';&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;ods escapechar='~';&lt;/span&gt;&lt;br /&gt;proc print data=linebr;&lt;br /&gt;  title 'Using the ODS ESCAPECHAR for line break';&lt;br /&gt;  title2 'Title 2';&lt;br /&gt;  title3 'Title 3';&lt;br /&gt;  title4 'Title 4';&lt;br /&gt;  title5 'Title 5';&lt;br /&gt;  title6 'Title 6';&lt;br /&gt;  title7 'Title 7';&lt;br /&gt;  title8 'Title 8';&lt;br /&gt;  title9 'Title 9';&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;title10 'Title 10 ~n Title 11 ~n Title 12 ~n Title 13 ~n Title 14';&lt;/span&gt;&lt;br /&gt;run;&lt;br /&gt;ods _all_ close;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;為了與前兩例做一點區別，此例將宣告符號「^」改成「~」。在 data step 裡面，分別將 The Caffeine molecule is an alkaloid of the methylxanthine family: 和 化學方程式之間各斷一、二、三、四行，因此只要在冒號後面打上「~n」,「~2n」,「~3n」,「~4n」即可。設定完後不要忘了在 proc print 前面加上 ods escapecha='~'; ，否則之前的宣告不會被執行。至於下面很多 title 指令是要展示折行的效果。如果不使用折行，折需要連續呼叫 title&lt;span style="font-style: italic;"&gt;n&lt;/span&gt; statement。但有了折行指令，則只需要打一行，裡面再連續使用數個 ~n 即可（如最後的紅色程式碼所示）。僅列出 html 的結果如下：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-10-24_1641。" src="http://farm4.static.flickr.com/3191/2969440399_de98e87964.jpg?v=0" onload="show_notes_initially();" height="500" width="356" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-size:130%;" &gt;&lt;span style="font-weight: bold;"&gt;例四：更改欄位設定&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;以 ods html 來說，如果沒有特別的設定，則一般的輸出報表會像下圖所示：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-10-24_1645。" src="http://farm4.static.flickr.com/3233/2970292602_c35bdb46a8.jpg?v=0" onload="show_notes_initially();" height="65" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;如果想要將整行從第一個 Sales 處斷行，並把 Sales Total Sales 改成斜體的話，可使用下列程式碼：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;ods html style=sasweb;&lt;br /&gt;ods escapechar='^';&lt;br /&gt;proc means data=sashelp.shoes sum min mean max;&lt;br /&gt;  class Region;&lt;br /&gt;  var Sales;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;label Sales='^S={font_style=italic}^nShoe Sales';&lt;/span&gt;&lt;br /&gt;run;&lt;br /&gt;ods html close;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;紅色部分就是用來更改那個表格內標籤的設定。^S={font_style=italic} 是用來將後面的 Total Sales 改成斜體字。而緊接著的 ^n 就是用來斷行的。結果如下：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-10-24_1654。" src="http://farm4.static.flickr.com/3245/2969465469_db7c7f2ac3.jpg?v=0" onload="show_notes_initially();" height="74" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-size:130%;" &gt;&lt;span style="font-weight: bold;"&gt;範例五：特殊符號&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;有些特殊符號需要使用特定的指令來印出。承上例，我們想要在表格後面加上註腳，並打上 trade mark、copy right mark 和美分符號，程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;data _null_;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;hexcode = 'AE'x;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;call symput ('hexreg',hexcode);&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;hexcode1 = 'A9'x;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;call symput('hexcopy' , hexcode1);&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;hexcode2 = 'A2'x;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;call symput('hexcent', hexcode2);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;run;&lt;/span&gt;&lt;br /&gt;  ** Display the hex codes in the SAS log;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;%put hexreg= &amp;hexreg;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;%put hexcopy= &amp;hexcopy;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;%put hexcent= &amp;hexcent;&lt;/span&gt;&lt;br /&gt;ods html file='inline5.html' style=sasweb;&lt;br /&gt;ods rtf file='inline5.rtf' notoc_data startpage=no;&lt;br /&gt;ods pdf file='inline5.pdf' startpage=no;&lt;br /&gt;ods escapechar='^';&lt;br /&gt;ods noptitle;&lt;br /&gt;proc means data=sashelp.shoes sum min mean max;&lt;br /&gt;  class Region;&lt;br /&gt;  var Sales;&lt;br /&gt;  label Sales='^S={font_style=italic}^nShoe Sales';&lt;br /&gt;run;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;ods pdf text="^S={just=c font_size=18pt}PDF File^nOpens with Adobe Reader^n&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;&amp;amp;hexreg &amp;amp;hexcopy My 2&amp;amp;hexcent";&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;ods rtf text="^S={just=c font_size=18pt}RTF File^nOpens with Microsoft Word^n&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;&amp;amp;hexreg &amp;amp;hexcopy My 2&amp;amp;hexcent";&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;ods html text="^S={just=c font_size=18pt}HTML File^nOpens with Microsoft Internet&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;Explorer^n &amp;amp;hexreg &amp;amp;hexcopy My 2&amp;amp;hexcent";&lt;/span&gt;&lt;br /&gt;proc freq data=sashelp.shoes;&lt;br /&gt;  tables Product /nocum;&lt;br /&gt;  label Product='^S={font_style=italic}Shoe Types Sold';&lt;br /&gt;run;&lt;br /&gt;ods _all_ close;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;使用者必須先用一個 _null_ 的 data step，呼叫 %symput 函式把這三個特殊符號叫進來。這三個特殊符號在 SAS 系統裡都有自己的代稱，trade mark 的代碼是 'AE'x，copy right mark 的代碼是 'A9'x，而美分的代碼是 'A2'x。然後用 %put 指令把剛剛用 %symput 叫進來的三個代碼設定為巨集參數，供之後使用。而那些註解可以直接寫在 ods 後面，使用 text 來印出，而所有諸如編輯文字、斷行以及安插特殊符號的指令全部都可以在 text 後面使用。以 ods html 來講， ^S={just=c font_size=18pt} 即是設定整個註腳的字型大小為 18pt，並且全部置中。放在 File 和 Opens 中間的 ^n 即表示從這個位置斷行，最後使用 &amp;amp;hexreg、&amp;amp;hexcopy 和 &amp;amp;hexcent 把 trade mark, copy right mark 和美分符號安插進去。結果如下：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-10-24_1702。" src="http://farm4.static.flickr.com/3174/2969480373_a147625534.jpg?v=0" onload="show_notes_initially();" height="420" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;範例六：安插圖片&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ODS 也可以拿來安插圖片。先看看程式：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;proc format;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;value $prdimg 'Boot' = 'c:\temp\boot.jpg'&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;"Women's Dress" = 'c:\temp\dressheels.jpg'&lt;/span&gt;&lt;br /&gt;                &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;'Slipper' = 'c:\temp\slipper.jpg';&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;run;&lt;/span&gt;&lt;br /&gt;ods html file='inline6.html' style=sasweb;&lt;br /&gt;ods rtf file='inline6.rtf' notoc_data;&lt;br /&gt;ods pdf file='inline6.pdf';&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;ods escapechar='^';&lt;/span&gt;&lt;br /&gt;proc report data=sashelp.shoes nowd style(column) = {vjust=b};&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;title '^S={preimage="c:\temp\shoe_logo.jpg"}';&lt;/span&gt;&lt;br /&gt;  where product in ('Boot', 'Slipper', "Women's Dress");&lt;br /&gt;  column Product Sales N;&lt;br /&gt;  define Product / group&lt;br /&gt;                   style(header)={background=white foreground=black}&lt;br /&gt;                   &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;style(column)={postimage=$prdimg.};&lt;/span&gt;&lt;br /&gt;  define Sales / sum;&lt;br /&gt;  &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;define N / '^S={background=white foreground=black}Number of Sales';&lt;/span&gt;&lt;br /&gt;run;&lt;br /&gt;ods _all_ close;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;如果只要在 title 上安插圖形的話，則可簡單地於 title statement 後面加上 ^S={preimage="路徑\檔名.jpg"} 來把圖形放上。如果要在文件內容部分的話，得需要先用 proc format 把每一張圖的路徑和檔名分別設定給某個變數的不同的 value，並用一個 $prdimg 來表示（這個字串可以自行設定）。然後在 proc report 裡面的 define 後面放上選項 style(column)={postimage=prdimg.}，則每一欄裡面都會安插不同的圖形。若只想單純的更改欄位背景或前景顏色的話，則使用 ^S={backgroun=color1 foreground=color2} 來改變。此例使用 ^S={background=white foreground=black} 把總數欄位的前景顏色改成黑色，背景顏色改成白色。&lt;br /&gt;&lt;br /&gt;三種輸出格式的結果如下：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-10-24_1708。" src="http://farm4.static.flickr.com/3055/2969492565_14e393bd36.jpg?v=0" onload="show_notes_initially();" height="370" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;CONTACT INFORMATION&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. Contact the author:&lt;br /&gt;Cynthia L. Zender&lt;br /&gt;SAS Institute Inc.&lt;br /&gt;Home Office&lt;br /&gt;Las Cruces, NM 88011&lt;br /&gt;Work Phone: (505) 522-3803&lt;br /&gt;Fax: (505) 521-9328&lt;br /&gt;E-mail: Cynthia.Zender@sas.com&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-316321631603740487?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/316321631603740487/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=316321631603740487&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/316321631603740487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/316321631603740487'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2008/11/funny-stuff-in-my-code-using-ods.html' title='Funny ^Stuff~ in My Code – Using ODS ESCAPECHAR'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-6930445392885774430</id><published>2008-10-23T15:18:00.003-04:00</published><updated>2010-07-23T16:12:45.771-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>Performing Iterative Processes with the Macro Facility</title><content type='html'>原文載點：&lt;a href="http://www.nesug.info/Proceedings/nesug07/cc/cc21.pdf"&gt;http://www.nesug.info/Proceedings/nesug07/cc/cc21.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;有時候要針對一組資料裡面不同類別的觀測值進行分析，在所有的 PROC 程序裡面都可以利用 BY 這個語法來完成。但是 BY 並沒有辦法在某些特殊情況下使用，因此利用 macro 進行遞迴式的處理就變成一另一種可行的方式。Katie Joseph 和 Taylor Lewis 在 NESUG 2007 發表了一篇利用 macro + do loop + %scan 來完成 BY 所無法完成的工作，可供有需要的人參考。&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;a name='more'&gt;&lt;/a&gt;&amp;nbsp;假設有一組資料如下所示：&lt;br /&gt;&lt;img alt="你拍攝的 2008-10-24_1333。" class="reflect" height="227" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3277/2969071225_14f1b2e873.jpg?v=0" title="" width="435" /&gt;&lt;br /&gt;每個 agency 有數筆重複觀測資料，Q1-Q73 為 73 個類別變數，weight 是連續變數表「權重」，而 strata 則是一個獨立的分層變數，同一個 agency 可能有兩種以上不同的分層變數。&lt;br /&gt;&lt;br /&gt;假設我們要計算抽樣母體的平均值，則可使用下列程式：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;pre&gt;&lt;code&gt;proc surveymeans data=survey total=frametotals;&lt;br /&gt;strata STRATA;&lt;br /&gt;var Q1-Q73;&lt;br /&gt;weight weight;&lt;br /&gt;domain agency;&lt;br /&gt;ods output domain=outstats;&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;這個程式特殊的地方在於他有使用 domain statement 來執行 domain analysis。關於 domain analysis 可以參考下面這個網址：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://support.sas.com/rnd/app/da/new/801ce/stat/chap13/sect9.htm#smeansdomainanalysis"&gt;http://support.sas.com/rnd/app/da/new/801ce/stat/chap13/sect9.htm#smeansdomainanalysis&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Domain analysis 在變數分層多的時候會消耗大量電腦記憶體，而此例的 agency 總共有 87 層，一般電腦可能會出現「out of memory」的訊息而中斷程序。因此得轉個彎讓每個 agency 跑一次 proc surveymeans，然後一個一個去跑 domain analysis 就不會有記憶體不足的問題。假設只跑 agy1 這一層，則程式如下：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data split;&lt;br /&gt;set survey;&lt;br /&gt;length split $1;&lt;br /&gt;if agency='agy1' then split='Y';&lt;br /&gt;else split='N';&lt;br /&gt;run;&lt;br /&gt;proc surveymeans data=split total=frametotals;&lt;br /&gt;strata STRATA;&lt;br /&gt;var Q1-Q73;&lt;br /&gt;weight weight;&lt;br /&gt;domain split;&lt;br /&gt;ods output domain=outstats_agy1 (where=(split='Y'));&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;第一個 data step 設定一個新的變數 split，當 agency=agy1 時則 split = 'Y'，反之則 split = 'N'。然後執行 proc surveymeans 時，把 split 放進 domain statement 裡面。由於 split 只是個二項變數，因此 domain 只要處理兩層就好。然後用一個 ods output 把 domain analysis 的表格輸出並存成 outstats_agy1。由於我們只關心 agy1 的結果，所以只要留下 split='Y' 的部分，至於 split='N' 的部分就不是我們所關心的了，這就是 ods output 後面要用一個 where 來抑制 split='N' 部分的輸出。&lt;br /&gt;&lt;br /&gt;根據這個程式，我們可用一個 macro + do loop 讓他對每個 agency 都執行一次 proc surveymeans 程序。程式如下：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span style="color: red; font-weight: bold;"&gt;%macro agydoloop();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;%do agynum=1 %to 87;&lt;/span&gt;&lt;br /&gt;data split;&lt;br /&gt;set survey;&lt;br /&gt;length split $1;&lt;br /&gt;if agency="agy&lt;span style="color: red; font-weight: bold;"&gt;&amp;amp;agynum&lt;/span&gt;" then split='Y';&lt;br /&gt;else split='N';&lt;br /&gt;run;&lt;br /&gt;proc surveymeans data=split total=frametotals;&lt;br /&gt;strata STRATA;&lt;br /&gt;var Q1-Q73;&lt;br /&gt;weight weight;&lt;br /&gt;domain split;&lt;br /&gt;ods output domain=outstats_agy&lt;span style="color: red; font-weight: bold;"&gt;&amp;amp;agynum&lt;/span&gt; (where=(split='Y'));&lt;br /&gt;run;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;%end;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;%mend agydoloop;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;這個程式首先先用 %macro agydoloop(); 和 %mend agydoloop; 把整個程式包起來。由於沒有額外的巨集參數需要使用，所以 %macro agydoloop(); 裡面就流空白即可。然後裡面再用一個 %do agynum=1 %to 87; 和 %end; 把那個 data step 以及 proc surveymeans 程序給包起來。特別注意是 do, to 和 end 若使用在 macro 裡面時，前面需加上百分比符號「%」。之後再把 1 改成 &amp;amp;agynum 即可，這樣讓 do loop 在跑時能把 1 到 87 遞迴地代入 agynum 裡面。如此一來 87 次 proc surveymeans 就可以輕鬆完成了。&lt;br /&gt;&lt;br /&gt;如果不想一次把 Q1 到 Q73 跑完，而也想用 do loop 分批跑的話，只要再加上一層 do loop 即可。程式如下：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro agyandQdoloop();&lt;br /&gt;%do agynum=1 %to 87;&lt;br /&gt;data split;&lt;br /&gt;set survey;&lt;br /&gt;length split $1;&lt;br /&gt;if agency="agy&amp;amp;agynum" then split='Y';&lt;br /&gt;else split='N';&lt;br /&gt;run;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;%do qnum=1 %to 73;&lt;/span&gt;&lt;br /&gt;proc surveymeans data=split total=frametotals;&lt;br /&gt;strata STRATA;&lt;br /&gt;var Q&lt;span style="color: red; font-weight: bold;"&gt;&amp;amp;qnum&lt;/span&gt;;&lt;br /&gt;weight weight;&lt;br /&gt;domain split;&lt;br /&gt;ods output domain=outstats_agy&lt;span style="color: red; font-weight: bold;"&gt;&amp;amp;agynum.&lt;/span&gt;_Q&lt;span style="color: red; font-weight: bold;"&gt;&amp;amp;qnum&lt;/span&gt; (where=(split='Y'));&lt;br /&gt;run;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;%end; /* qnum do loop */&lt;/span&gt;&lt;br /&gt;%end; /* agynum do loop */&lt;br /&gt;%mend agyandQdoloop;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;由於 Qn 變數只出現在 proc surveymeans，所以新的 do loop 只需要放在 proc surveymeans 的頭尾即可。然後用 &amp;amp;qnum 來替換數字 1 到 73。特別一提的是，此處的 ods output 在設定輸出資料名稱時，原先的 &amp;amp;agynum 由於後面接了一個特殊符號「_」，因此 &amp;amp;agynum 後面要先打上一個句點「.」再接「_」。如果沒有打上句點，則這個 macro 會無法分辨出 &amp;amp;agynum 是個參數而非定值。這個規則通用於各種情況，只要巨集變數後面接上符號如「_」,「.」或「\」，都需要打上一個句點先。&lt;br /&gt;&lt;br /&gt;可是，當類別變數全都是字串時，do loop 就無法處理了。因此需要利用 %scan 來輔助完成。%scan 函式是用來切割一長串的字串。其語法為：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%scan(參數, n [,分隔符號]);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;其中，n 代表要抽出切割後的第幾個字串，而[,分隔符號]是一個選擇性的參數。在沒有額外設定的情況下，預設值為「空白」,「.」,「&amp;lt;」,「(」,「+」,「|」,「&amp;amp;」,「$」,「*」,「)」,「;」,「﹁」,「-」,「/」,「,」,「%」,「￠」。  假設 agency 變數不再是 agy1-agy87，而是 ED, BO, CM 這三個字串，則程式如下： &lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro agyscanloop(agylist=);&lt;br /&gt;&lt;br /&gt;%let num=1;&lt;br /&gt;&lt;br /&gt;%let &lt;span style="color: red; font-weight: bold;"&gt;agy=%scan(&amp;amp;agylist,&amp;amp;num)&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;%do %while (&amp;amp;agy ne );&lt;br /&gt;&lt;br /&gt;data split;&lt;br /&gt;&lt;br /&gt;set survey;&lt;br /&gt;&lt;br /&gt;length split $1;&lt;br /&gt;&lt;br /&gt;if agency="&amp;amp;agy" then split='Y';&lt;br /&gt;&lt;br /&gt;else split='N';&lt;br /&gt;&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;proc surveymeans data=split total=frametotals;&lt;br /&gt;&lt;br /&gt;strata STRATA;&lt;br /&gt;&lt;br /&gt;var Q1-Q73;&lt;br /&gt;&lt;br /&gt;weight weight;&lt;br /&gt;&lt;br /&gt;domain split;&lt;br /&gt;&lt;br /&gt;ods output domain=outstats_&amp;amp;agy(where=(split='Y'));&lt;br /&gt;&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;%let num=%eval(&amp;amp;num+1); *** increase by one the position pointer;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;%let agy=%scan(&amp;amp;agylist,&amp;amp;num);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;%end;&lt;br /&gt;&lt;br /&gt;%mend agyscanloop;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;其中，agy=%scan(&amp;amp;agylist,&amp;amp;num)是要把巨集參數 agylist 裡面所打的字串切割並取第 &amp;amp;num 個部分。由於一開始 &amp;amp;num 設定為 1，所以每跑完一次之後要把 &amp;amp;num 加一，這樣跑第二次時就會去取切割後的第二個字串。而遞迴的過程是由 %do %while (&amp;amp;agy ne); 來驅動。這個道理很簡單，只要當 &amp;amp;agy=%scan(&amp;amp;agylist, &amp;amp;num) 的結果不是空白（即 missing data），則這個 do while 就會一直跑，直到 &amp;amp;agy 是 missing data 為止。要怎樣讓這個 do while 結束，就是靠之後得 %let num=%eval(&amp;amp;num+1); 和 %let agy=%scan(&amp;amp;agylist, &amp;amp;num); 來控制。當跑完第一次時，num=%eval(&amp;amp;num+1) 會讓 &amp;amp;num = 2。之所以要用 %eval 的原因是因為任何四則運算在 macro 裡面都會被視為字串。只有包在 %eval 函式裡面的四則運算過程才會真正被計算出來並輸出結果。所以如果沒有用 %eval 函式的話，num 會變成字串型的「1+1」，而非數值型的「2」。當 num=2 後代入下面那個 %let agy=%scan(&amp;amp;agylist, &amp;amp;num); 時，這行就會把 &amp;amp;agylist 所代表的字串再次切割，然後取出第二個部分。所以這個 do while 就會繼續去執行，直到 num=3 時才會跳出。&lt;br /&gt;&lt;br /&gt;因此當執行下面這行時：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%agyscanloop(agylist=ED BO CM);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;此巨集會把「ED BO CM」從中間的空白處切成「ED」,「BO」以及「CM」，然後再一個一個去執行 proc surveymeans。&lt;br /&gt;&lt;br /&gt;雖然 %scan 可以幫忙切割字串，但是如果 agency 這個變數有數十個字串型的類別，而非上例的只有三個類別，則在輸入巨集參數 &amp;amp;agylist 時便會顯得相當相當耗時。作者提出了一個 proc sql 程序來解決這項煩人的工作。程式改寫如下：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span style="color: red; font-weight: bold;"&gt;proc sql;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;select distinct agy into :agylist separated by ' '&lt;/span&gt;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;from survey;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;%put &amp;amp;agylist;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;quit;&lt;/span&gt;&lt;br /&gt;%macro agySQLscanloop();&lt;br /&gt;%let num=1;&lt;br /&gt;%let agy=%scan(&amp;amp;agylist,&amp;amp;num);&lt;br /&gt;%do %while (&amp;amp;agy ne );&lt;br /&gt;&lt;span style="color: #009900; font-weight: bold;"&gt;*** PROC SURVEYMEANS Code - uses &amp;amp;agy as the agency code;&lt;/span&gt;&lt;br /&gt;%let num=%eval(&amp;amp;num+1);&lt;br /&gt;%let agy=%scan((&amp;amp;agylist,&amp;amp;num);&lt;br /&gt;%end;&lt;br /&gt;%mend agySQLscanloop;&lt;/code&gt;&lt;/pre&gt;&lt;/span&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;這個 proc sql 會把 agy 所有的類別黏成一串，並用空白符號分隔開來，然後把黏成一串的結果用 %put 函式放進一個巨集變數 &amp;amp;agylist 裡面。由於這個 &amp;amp;agylist 變數已經在外部設定好了，所以之後寫 macro 時就不用在 %macro agySQLscanloop(); 裡面放 agylist 了。至於 macro 裡面的內容和設定則完全跟前例一樣。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;CONTACT INFORMATION&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. Contact the authors at:&lt;br /&gt;Katie Joseph&lt;br /&gt;US Office of Personnel Management&lt;br /&gt;1900 E St, NW, Room 7439&lt;br /&gt;Washington, DC 20415&lt;br /&gt;Work Phone: (202) 606-1817&lt;br /&gt;Fax: (202) 606-1719&lt;br /&gt;E-mail: Katie.Joseph@opm.gov&lt;br /&gt;Taylor Lewis&lt;br /&gt;U.S. Office of Personnel Management (OPM)&lt;br /&gt;1900 E St., NW, Room 7439&lt;br /&gt;Washington, DC 20415&lt;br /&gt;Work Phone: (202) 606-1309&lt;br /&gt;Fax: (202) 606-1719&lt;br /&gt;E-mail: Taylor.Lewis@opm.gov&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-6930445392885774430?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/6930445392885774430/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=6930445392885774430&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6930445392885774430'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6930445392885774430'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2008/10/performing-iterative-processes-with.html' title='Performing Iterative Processes with the Macro Facility'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-2825635172297871603</id><published>2008-10-21T00:37:00.007-04:00</published><updated>2010-07-23T16:13:28.372-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>A macro for nearest neighbor imputation</title><content type='html'>原文載點：&lt;a href="http://www.mediafire.com/?sharekey=00ab0205b2465593dd8b33b5aa27078d"&gt;http://www.mediafire.com/?sharekey=00ab0205b2465593dd8b33b5aa27078d&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;長期以來 SAS 內部只能使用 PROC MI 來執行多重插補法的資料插補動作，而當然世界上不可能只有這麼一種方法。由於多重插補法的使用時機需要配合他強大的假定，所以一旦資料不適用 PROC MI 時，SAS 使用者往往沒有別的替代方案。另外，有時缺失值的情況不嚴重，但使用 Complete Case Analysis 直接刪除有缺失值的觀測值，往往對其他沒有缺失值的變數造成一些資料上的浪費。使用 PROC MI 又需要驗證許多假定，還得在事後進行 PROC MIANALYSIS，實在相當浪費時間。如果有個簡單但又不失可靠的替代方案，將可大大增加處理缺失值的效率。Nearest neighbor imputation（以下簡稱 NNI）是個形之多年的資料插補法，但 SAS 現存的程序並不支援。這篇於 SESUG 2008 由 Lung-Chang Chien (我本人)和 Mark Weaver (我的committee member)所發表的技術文件，提供了一個簡易的 macro 來執行 NNI 的插補動作。&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;首先，要瞭解 Nearest neighbor imputation 的理論，可以參考這一篇文章：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://cchien.pixnet.net/blog/post/11383935"&gt;Nearest。Neighbor。Imputation&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;我所設計的 %NNI 一共只有五個語法便可完成插補的動作。原始碼如下：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;pre&gt;&lt;code&gt;%MACRO NNI(INDATA=,                  /*INPUT DATA SET(INCLUDING LIBRARY NAME) */&lt;br /&gt;MISSVAR=,                 /*INPUT SINGLE VARIABLE WITH MISSING DATA*/&lt;br /&gt;RESPVAR=,                 /*RESPONSE VARIABLE*/&lt;br /&gt;IDVAR=,                   /*SUBJECT VARIABLE*/&lt;br /&gt;OUTDATA=                  /*OUTPUT DATA SET WITH COMPLETE DATA*/&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;DATA OBSY_MISSX;&lt;br /&gt;SET &amp;amp;INDATA;&lt;br /&gt;IF &amp;amp;MISSVAR=.;&lt;br /&gt;KEEP &amp;amp;IDVAR &amp;amp;RESPVAR;&lt;br /&gt;RUN;&lt;br /&gt;&lt;br /&gt;PROC MEANS DATA=&amp;amp;INDATA N NMISS NOPRINT;              &lt;br /&gt;VAR &amp;amp;MISSVAR;&lt;br /&gt;OUTPUT OUT=OBSN N=OBSX NMISS=MISSX;&lt;br /&gt;RUN;&lt;br /&gt;&lt;br /&gt;DATA _NULL_;&lt;br /&gt;SET OBSN;&lt;br /&gt;CALL SYMPUT('OBSN',OBSX);&lt;br /&gt;CALL SYMPUT('MISSN',MISSX);&lt;br /&gt;RUN;&lt;br /&gt;&lt;br /&gt;DATA SIMDATA_NOMISS;&lt;br /&gt;SET &amp;amp;INDATA;&lt;br /&gt;IF &amp;amp;MISSVAR NE .;&lt;br /&gt;RUN;&lt;br /&gt;&lt;br /&gt;PROC IML;&lt;br /&gt;USE SIMDATA_NOMISS;&lt;br /&gt;READ ALL VAR {&amp;amp;MISSVAR} INTO XMAT;&lt;br /&gt;READ ALL VAR {&amp;amp;RESPVAR} INTO YMAT;&lt;br /&gt;USE OBSY_MISSX;&lt;br /&gt;READ ALL VAR {&amp;amp;IDVAR &amp;amp;RESPVAR} INTO MISSMAT;&lt;br /&gt;TXMAT=T(XMAT);&lt;br /&gt;TYMAT=T(YMAT);&lt;br /&gt;DISTANCE=J(&amp;amp;MISSN,&amp;amp;OBSN,.);&lt;br /&gt;MIND=J(&amp;amp;MISSN,1,.);&lt;br /&gt;MISSVAR=J(&amp;amp;MISSN,&amp;amp;OBSN,.);&lt;br /&gt;IMP=J(&amp;amp;MISSN,1,.);&lt;br /&gt;DO I = 1 TO &amp;amp;MISSN;&lt;br /&gt;DO J = 1 TO &amp;amp;OBSN;&lt;br /&gt;DISTANCE[I,J]=ABS(MISSMAT[I,2]-TYMAT[,J]);&lt;br /&gt;END;&lt;br /&gt;MIND[I,]=MIN(DISTANCE[I,]);&lt;br /&gt;END;&lt;br /&gt;DO I = 1 TO &amp;amp;MISSN;&lt;br /&gt;DO J = 1 TO &amp;amp;OBSN;&lt;br /&gt;IF DISTANCE[I,J]=MIND[I,] THEN MISSVAR[I,J]=TXMAT[,J];&lt;br /&gt;END;&lt;br /&gt;IMP[I,]=MISSVAR[I,:];&lt;br /&gt;END;&lt;br /&gt;CNAME={"&amp;amp;IDVAR" "&amp;amp;RESPVAR" "&amp;amp;MISSVAR"};&lt;br /&gt;IMPX=MISSMAT||IMP;&lt;br /&gt;CREATE NNI FROM IMPX[C=CNAME];&lt;br /&gt;APPEND FROM IMPX;&lt;br /&gt;QUIT;&lt;br /&gt;&lt;br /&gt;DATA &amp;amp;OUTDATA;&lt;br /&gt;MERGE &amp;amp;INDATA NNI;&lt;br /&gt;BY &amp;amp;IDVAR;&lt;br /&gt;RUN;&lt;br /&gt;%MEND;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;語法使用方式如下：&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;INDATA：原始資料的名稱，包含其所用的 library&lt;br /&gt;&lt;/li&gt;&lt;li&gt;MISSVAR：含有 missing data 的變數（只能放一個）&lt;br /&gt;&lt;/li&gt;&lt;li&gt;RESPVAR：沒有 missing data 的變數（也只能放一個）&lt;br /&gt;&lt;/li&gt;&lt;li&gt;IDVAR：放 id number 或 case number，如果沒有的話必須要自己造一個&lt;br /&gt;&lt;/li&gt;&lt;li&gt;OUTDATA：插補過後輸出的完整資料&lt;/li&gt;&lt;/ul&gt;這邊使用一個實際範例來說明如何使用 %NNI。我使用一個位於北卡 Raleigh 的空氣品質監測站的資料，使用裡面的 PM2.5 和二十四小時日均溫這兩個變數，時間點取在西元兩千年，所以總共有 366 個觀測值。其中氣溫變數是完整的，但是 PM2.5 有十七個 missing data。我用這個資料來配適下面這個模式：&lt;br /&gt;&lt;br /&gt;&lt;img alt="你拍攝的 2008-10-22_1608。" class="reflect" height="39" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3222/2965318700_beabe30d8c.jpg?v=0" title="" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;程式如下：&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%NNI(INDATA=CASE.RALFORNNI,&lt;br /&gt;MISSVAR=PM25TMEAN,&lt;br /&gt;RESPVAR=TMPD,&lt;br /&gt;IDVAR=DATE,&lt;br /&gt;OUTDATA=CASE.RAL_NNI); &lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;這張散佈圖說明了插補資料所在的位置：&lt;br /&gt;&lt;br /&gt;&lt;img alt="你拍攝的 2008-10-22_1610。" class="reflect" height="318" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3044/2964480237_347e4ec489.jpg?v=0" title="" width="437" /&gt;&lt;br /&gt;&lt;br /&gt;由於 Nearest neighbor imputation 是一個比較保守的插補法，所以插補值很依賴既有資料的變異程度。如果既有資料的變異程度比較小，那能夠拿來當作插補值的變化也會跟著變小。不過至少不可能插補到離群值，這一點是絕對可以保證的。&lt;br /&gt;&lt;br /&gt;再來看看 PM2.5 在插補前後的差異：&lt;br /&gt;&lt;img alt="你拍攝的 2008-10-22_1613。" class="reflect" height="299" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3208/2965328264_be9bb1f992.jpg?v=0" title="" width="257" /&gt;&lt;br /&gt;可以發現數值都很逼近。&lt;br /&gt;&lt;br /&gt;經過 PROC GAM 程序的配適後，比較一下最重要的兩個參數估計值的結果：&lt;br /&gt;&lt;img alt="你拍攝的 2008-10-22_1614。" class="reflect" height="110" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3194/2964488307_3724b8b69d.jpg?v=0" title="" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;從上表可知彼此的差異不大。顯著情況也沒有改變。&lt;br /&gt;&lt;br /&gt;再來看看平滑曲線圖：&lt;br /&gt;&lt;img alt="你拍攝的 2008-10-22_1615。" class="reflect" height="194" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3066/2965334520_cfe7f41afe.jpg?v=0" title="" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;兩張圖的情況也非常近似。不過這邊要特別強調一點，那就是如果 missing data 是出現在要配適平滑曲線的變數時，Nearest neighbor imputation 的成效並不好。這一點已經經過我用另外一個模擬結果證實了，只是沒放在這篇技術文件裡面。這個實例之所以會有相似的平滑曲線是因為 missing data 只出現在線性的應變數 PM2.5 裡面，而非使用在平滑曲線的時間變數裡面。&lt;br /&gt;&lt;br /&gt;Nearest neighbor imputation 還是有一些限制，整理如下：&lt;br /&gt;1. 不太適用於插補離散變數，但如果資料夠大，能來搭配的完整變數內的數值變化也夠多的話，還是可以勉強使用。&lt;br /&gt;2. 資料一定要多，太小的樣本數會大幅降低插補功效。&lt;br /&gt;3. 資料裡面一定至少要有一個完整的變數，如果所有變數都有 missing data，則此方法和程式都會失效。&lt;br /&gt;4. 目前這個 macro 的版本只能在 MISSVAR 和 RESPVAR 裡面各放一個變數。如果有數個變數含有 missing data，則需要重複使用這個 %NNI 來插補。如果情況是完整的變數有很多個，那到底要放哪一個變數在 RESPVAR 裡面。目前為止並沒有什麼準則來決定最好的完整變數。根據我個人的經驗，最好先用 PROC CORR 把所有變數的相關矩陣弄出來，然後挑出那個和有 missing data 變數有最高相關程度的完整變數即可。&lt;br /&gt;&lt;br /&gt;此外，這次在 St. Pete Beach 舉辦的 SESUG 2008 會議，我也有去會場發表。整個過程可以看下面這篇文章：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;&lt;a href="http://cchien.pixnet.net/blog/post/22106126"&gt;St。Pete。Beach&lt;/a&gt;&lt;/h2&gt;&lt;/span&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;比較令人印象深刻的是我在 Tampa International Airport 等交通車時遇到了 Wendi Wright 女士。本部落格曾經發表過兩篇她寫的 SAS 技術文件：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://sugiclub.blogspot.com/2008/10/legend-is-not-just-legend.html"&gt;A Legend is Not Just a Legend&lt;/a&gt;&lt;br /&gt;&lt;a href="http://sugiclub.blogspot.com/2007/11/checking-for-duplicates.html"&gt;Checking for Duplicates&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;她今年也在 SESUG 發表了兩篇技術文件，有空我再來分享她的著作。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: 130%;"&gt;&lt;span style="font-weight: bold;"&gt;CONTACT INFORMATION &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Your comments and questions are valued and encouraged.  Contact the author at:&lt;br /&gt;Lung-Chang Chien&lt;br /&gt;University of North Carolina at Chapel Hill&lt;br /&gt;Chapel Hill, NC  27599&lt;br /&gt;E-mail: cchien@email.unc.edu   &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-2825635172297871603?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/2825635172297871603/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=2825635172297871603&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/2825635172297871603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/2825635172297871603'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2008/10/macro-for-nearest-neighbor-imputation.html' title='A macro for nearest neighbor imputation'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-8000972976249164667</id><published>2008-10-14T17:30:00.003-04:00</published><updated>2008-10-14T18:28:17.480-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='繪圖技巧'/><title type='text'>A Legend is Not Just a Legend</title><content type='html'>原文載點：&lt;a href="http://www.nesug.org/Proceedings/nesug07/po/po21.pdf"&gt;http://www.nesug.org/Proceedings/nesug07/po/po21.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;這是一篇關於介紹 SAS/GRAPH 裡面圖例（legend）的基本寫法和一些變化，由 Wendi Wright 在 NESUG 2007 所發表。&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;假設有個程式如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;TITLE font=’Times New Roman’ height=1.5 ‘Number of Hits on Websites 1, 2, and 3’;&lt;br /&gt;TITLE2 font=’Times New Roman’ height=1.5 ‘For the Month of ‘ COLOT=red ‘March 2007’;&lt;br /&gt;FOOTNOTE JUSTIFY=left ‘Educational Testing Service’ JUSTIFY=right ‘April 1, 2007’;&lt;br /&gt;AXIS1 LABEL=(ANGLE=270 ROTATE=90 HEIGHT=1.5 ‘Number of Hits’)&lt;br /&gt;     ORDER=(0 to 1800 by 200) MINOR=(NUMBER=3);&lt;br /&gt;AXIS2 REFLABEL=(POSITION=top JUSTIFY=center ‘Email Ad‘)&lt;br /&gt;     VALUE=(‘1’ ‘2’ ‘3’ ‘4’ ‘5’ ‘6’ ‘7’ ‘8’ ‘9’);&lt;br /&gt;SYMBOL1 COLOR=blue INTERPOL=join LINE=1 VALUE=dot;&lt;br /&gt;SYMBOL2 COLOR=red INTERPOL=join LINE=2 VALUE=star;&lt;br /&gt;SYMBOL3 COLOR=green INTERPOL=join LNEe=3 VALUE=circle;&lt;br /&gt;PROC GPLOT DATA=perm.hits;&lt;br /&gt;   PLOT Web1*day Web2*day Web3*day&lt;br /&gt;        / OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2;&lt;br /&gt;RUN;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;能夠畫出這樣的圖：&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3196/2942041331_59c3abc097_o.png" /&gt;&lt;br /&gt;以此圖為基準，我們來看看如果加上圖例，並且做一些變化。&lt;br /&gt;&lt;br /&gt;最基本的圖例就是依照 SAS 內部的設定將三條折線的點和線的型態標註在整張圖的最下方。這個動作只需要在 plot statement 後面加上 legend 即可，如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;PROC GPLOT DATA=perm.hits;&lt;br /&gt;   PLOT Web1*day Web2*day Web3*day&lt;br /&gt;        / OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;LEGEND&lt;/span&gt;;&lt;br /&gt;Run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;SAS 會輸出下面這種圖：&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3192/2942906244_045dd87623_o.png" /&gt;&lt;br /&gt;如果想要換掉 legend 裡面三條折線的標籤，則可以在 PROC GPLOT 程序前面加上一條 legendn 的指令來修改。其中 n=1,2,3... 表示可以寫 n 條 legend 的指令。之後再把寫好的 legend statement 掛在 legend option 的後面，如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;LEGEND1 VALUE=(COLOR=blue HEIGHT=1 ‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’);&lt;/span&gt;&lt;br /&gt;PROC GPLOT DATA=perm.hits;&lt;br /&gt;   PLOT Web1*day Web2*day Web3*day&lt;br /&gt;        / OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=&lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;legend1&lt;/span&gt;;&lt;br /&gt;Run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;在 legend1 指令中，value 可以設定標籤的顏色（color option）、大小（height option）還有標籤字樣（此例用 'Web Site 1' 'Web Site 2' 'Web Site 3'，記得要加引號，不要加逗號）。改好後得圖例會變成這樣：&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3016/2942919582_50859cfe69_o.png" /&gt;&lt;br /&gt;如果也想一併把 legend 的名字（此例為「PLOT」）改掉，則可使在 legendn 指令裡面再加上一個 label 的選項，如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;LEGEND1 &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;LABEL=(COLOR=blue HEIGHT=2 ‘Our Web Pages’)&lt;/span&gt;&lt;br /&gt;        VALUE=(COLOR=blue HEIGHT=1 ‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’);&lt;br /&gt;PROC GPLOT data=perm.hits;&lt;br /&gt;    PLOT Web1*day Web2*day Web3*day&lt;br /&gt;         / OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;&lt;br /&gt;Run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;同樣地，label 裡面也可以設定顏色大小和想要用的字，語法和 value 一模一樣。改出來的效果如下所示：&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3235/2942930526_914bc51933_o.png" /&gt;&lt;br /&gt;&lt;br /&gt;如果不想讓 legend 橫的排列，而想改成直的，則需使用 across 和 down 兩個選項控制。across 可以表示行數，down 可以表示列數。因此此例要讓 legend 直的排，就等於是要宣告 legend 裡面只要一行三列，程式改寫如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;LEGEND1 LABEL=(HEIGHT=1 ‘Our Web Pages’)&lt;br /&gt;        VALUE=(‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’)&lt;br /&gt;        &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt;ACROSS=1 DOWN=3&lt;/span&gt;;&lt;br /&gt;PROC GPLOT DATA=perm.hits;&lt;br /&gt;PLOT Web1*day Web2*day Web3*day&lt;br /&gt;   / OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS axis2 LEGEND=legend1;&lt;br /&gt;Run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;此時 legend 就會站起來了！&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3009/2942083399_9c91f37139_o.png" /&gt;&lt;br /&gt;&lt;br /&gt;若覺得這樣還不夠，想要讓 legend 名稱「Our Web Pages」也放在圖例的上頭，則需要在 legend 裡面的 label option 多加兩個指令。一個是 position，用來指定 legend 名稱的位置，有上下左右（top, bottom, left, right）可選，然後再用 justify 指令來對齊，有置左(left)、置中(center)、和置右(right)可選。程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;LEGEND1 LABEL=(HEIGHT=1 &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;POSITION=top JUSTIFY=center&lt;/span&gt; ‘Web Sites’)&lt;br /&gt;        VALUE=(‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’)&lt;br /&gt;        ACROSS=1 DOWN=3;&lt;br /&gt;PROC GPLOT DATA=perm.hits;&lt;br /&gt;   PLOT Web1*day Web2*day Web3*day&lt;br /&gt;        / OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;&lt;br /&gt;Run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;此程式是將他放在上頭並置中，所以用 position=top 和 justify=center 來調整。結果如下：&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3239/2942094011_3ddcf5d3b6_o.png" /&gt;&lt;br /&gt;&lt;br /&gt;若覺得這樣的圖例太大很佔空間，想要把他移到圖內，只要在 position 裡面加上一個 inside 選項即可。如果要把圖例移到左上角，則可以再同時宣告 top 和 left 於 position 裡面。換句話說，position 可以一次宣告三種位置。另外，如果擔心圖例會遮到既有的點或線，則可以使用 mode 來決定要不要覆蓋。要的話設定為 protect，不要的話則設定為 share。此例設定為要覆蓋，所以使用 mode=protect。程式改寫如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;LEGEND1 LABEL=(HEIGHT=1 POSITION=top JUSTIFY=center ‘Web Sites’)&lt;br /&gt;        VALUE=(‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’)&lt;br /&gt;        ACROSS=1 DOWN=3&lt;br /&gt;       &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt; POSITION = (top left inside)&lt;/span&gt;&lt;br /&gt;       &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt; MODE=protect&lt;/span&gt;;&lt;br /&gt;PROC GPLOT DATA=perm.hits;&lt;br /&gt;    PLOT Web1*day Web2*day Web3*day&lt;br /&gt;         / OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;&lt;br /&gt;Run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;圖形如下：&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3196/2942968506_ee6a25f6a2_o.png" /&gt;&lt;br /&gt;&lt;br /&gt;如果覺得這個 legend 太單調，想要多加一個有顏色的框，則需使用 cframe 來設定顏色，如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;LEGEND1 LABEL=(HEIGHT=1 POSITION=top JUSTIFY=center ‘Web Sites’)&lt;br /&gt;       VALUE=(‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’)&lt;br /&gt;       ACROSS=1 DOWN=3&lt;br /&gt;       POSITION = (top left inside)&lt;br /&gt;       MODE=protect&lt;br /&gt;      &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt; CFRAME = yellow&lt;/span&gt;;&lt;br /&gt;PROC GPLOT DATA=perm.hits;&lt;br /&gt;    PLOT Web1*day Web2*day Web3*day&lt;br /&gt;         / OVERLYA HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;&lt;br /&gt;Run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;然後你就會得到一個黃色的框架：&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3020/2942971172_7a8519c197_o.png" /&gt;&lt;br /&gt;&lt;br /&gt;當然框架也是可以做一些微調的，比方說若覺得他太靠近 Y 軸的話，可利用 offset 來進行調整。以此圖為例，如果想要將 legend 框架和 Y 軸拉開差不多整張圖的 3% 的距離，則可以下列程式：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;LEGEND1 LABEL=(HEIGHT=1 POSITION=top JUSTIFY=center ‘Web Sites’)&lt;br /&gt;       VALUE=(‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’)&lt;br /&gt;       ACROSS=1 DOWN=3&lt;br /&gt;       POSITION = (top left inside)&lt;br /&gt;       MODE=protect&lt;br /&gt;       CFRAME= yellow&lt;br /&gt;       &lt;span style="color: rgb(255, 0, 0); font-weight: bold;"&gt; OFFSET = (3 pct)&lt;/span&gt;;&lt;br /&gt;PROC GPLOT DATA=perm.hits;&lt;br /&gt;    PLOT Web1*day Web2*day Web3*day&lt;br /&gt;         / OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;&lt;br /&gt;Run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;成效如下：&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3149/2942978838_35d0b63ea3_o.png" /&gt;&lt;br /&gt;特別一提的是，這種調整通常很難一次到位，所以使用者需要輸入不同的數值以求達到自己最滿意的結果。&lt;br /&gt;&lt;br /&gt;這框架也可以更改長寬大小，只要在 legend 裡面使用 shape=(w,h) 語法就可設定，其中 w 代表寬度，h 代表高度。預設值是 (w,h)=(5,1)。此例若要加長寬度，則需用 shape=(10,1)，如下所示：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;LEGEND1 LABEL=(HEIGHT=1 POSITION=top JUSTIFY=center ‘Web Sites’)&lt;br /&gt;       VALUE=(‘Web Site 1’ ‘Web Site 2’ ‘Web Site 3’)&lt;br /&gt;       ACROSS=1 DOWN=3&lt;br /&gt;       POSITION = (top left inside)&lt;br /&gt;       MODE=protect&lt;br /&gt;       CFRAME = yellow&lt;br /&gt;       OFFSET = (3 pct)&lt;br /&gt;       &lt;span style="font-weight: bold; color: rgb(255, 0, 0);"&gt;SHAPE=(10,1)&lt;/span&gt;;&lt;br /&gt;PROC GPLOT DATA=perm.hits;&lt;br /&gt;    PLOT Web1*day Web2*day Web3*day&lt;br /&gt;         / OVERLAY HREF = ‘17’ FRAME VAXIS=axis1 HAXIS=axis2 LEGEND=legend1;&lt;br /&gt;RUN;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3244/2942986920_c05cdded38_o.png" /&gt;&lt;br /&gt;&lt;br /&gt;當然 legend 指令還有很多，不過這些基本的設定可以應付大部分的情況，如果想要再深入研究其他指令，可以依照下面的路徑去找網路上的手冊：&lt;br /&gt;&lt;img src="http://farm4.static.flickr.com/3210/2942994526_6869f172b9_o.png" /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;&lt;span style="font-weight: bold;"&gt;AUTHOR CONTACT&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Your comments and questions are valued and welcome. Contact the author at:&lt;br /&gt;Wendi L. Wright&lt;br /&gt;1351 Fishing Creek Valley Rd.&lt;br /&gt;Harrisburg, PA 17112&lt;br /&gt;Phone: (717) 513-0027&lt;br /&gt;E-mail: wendi_wright@ctb.com&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-8000972976249164667?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/8000972976249164667/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=8000972976249164667&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/8000972976249164667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/8000972976249164667'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2008/10/legend-is-not-just-legend.html' title='A Legend is Not Just a Legend'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-8748576307575429576</id><published>2008-09-11T18:14:00.006-04:00</published><updated>2008-10-04T20:15:58.286-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='資料整理'/><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>Names, Names, Names - Make Me a List</title><content type='html'>原文載點：&lt;a href="http://www2.sas.com/proceedings/forum2007/052-2007.pdf"&gt;http://www2.sas.com/proceedings/forum2007/052-2007.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;如果你曾經讀過去年的這一篇文章「&lt;a target="_blank" class="gs-title" href="http://sugiclub.blogspot.com/2007/03/text-utility-macros-for-manipulating.html"&gt;&lt;b&gt;Text Utility&lt;/b&gt; Macros for Manipulating Lists of Variable Names&lt;/a&gt;」，而且也親自使用過該原文作者所提供的 text utility macro 的話，想必一定會對其強大的批次 rename 功能印象深刻。不過這個 macro 有個缺點，那就是在使用前要先定義這個東西：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%let orig_vars = a01a a01b d01 d02 t1_r t2_r;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;這個 %let 的作用是把所有原始變數集中定義成 orig_vars 這個變數，然後再讓 text utility 來使用。不過，如果當變數很多時，我們需要手動去輸入，仍舊是相當耗時。而之前我曾經發過這篇文章「&lt;a target="_blank" class="gs-title" href="http://sugiclub.blogspot.com/2008/01/automatically-renaming-common-variables.html"&gt;Automatically Renaming Common Variables Before Merging&lt;/a&gt;」，裡面是利用 PROC SQL 來抓出舊變數名稱。不過，如果舊變數名稱是有規則可尋，比方說 y1~y1000 時（ %let 不允許使用 y1-y1000 這種寫法），則這篇在 SAS Global Forum 2007 由 Ian Whitlock 發表的技術文件可以有很大的幫助。&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;這篇技術文件一共發佈了五個有用的 macro 讓使用者可以輕易操作大量變數名稱。以下就一一介紹：&lt;br /&gt;&lt;br /&gt;。%ZIP&lt;br /&gt;這個 macro 顧名思義就和壓縮檔 zip 一樣，可以組合數個不同的變數或 index 來產生有規則的變數。語法如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%zip (l1= , lv1= , sep1=, l2= , l2v= , sep2= , osep= )&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;變數解釋如下：&lt;br /&gt;。l1= 第一列字串&lt;br /&gt;。lv1= 取代第一列字串的字串（可省略不用）&lt;br /&gt;。sep1= 用來區隔第一列字串的字元，預設值是空白（%str()）&lt;br /&gt;。l2= 第二列字串&lt;br /&gt;。l2v= 取代第二列字串的字串（可省略不用）&lt;br /&gt;。sep2= 用來區隔第二列字串的字元，預設值是空白（%str()）&lt;br /&gt;。osep= 用來區隔輸出字串的字元，預設值是空白（%str()）&lt;br /&gt;&lt;br /&gt;比方說想要生成「Ax By Cz」這三個字串，可使用下列程式：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%zip(l1=A B C, l2=x y z);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;l1 所表示的「A B C」會去抓在 l2 相對應位置的「x y z」，這便是 %zip 所呈現的功能。&lt;br /&gt;&lt;br /&gt;。XPROD&lt;br /&gt;這是可以拿來產生連續字尾或字首的 macro。語法如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%xprod ( l1= , lv1= , l2= , lv2=, sep1=, sep2=, osep=) )&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;使用方式和 %zip 一模一樣，但產生出來的效果完全不同。比方說想要產生「lib.w1  lib.w2  lib.w3」這三個字串，可發現這三個字串只有尾數不同，所以可以用 %xprod 來產生：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%xprod(l1=lib.w, l2=1 2 3);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;換句話說，在 %xprod 裡面，l1 是拿來放共同字串，l2 是拿來放會改變的字串。他甚至可以做出更複雜的效果。假設想要產生「a_x  a_y  b_x  b_y  c_x  c_y」這六個字串，我們可以想像這是一個 3X2 的矩陣：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;      x   y&lt;br /&gt;a_&lt;br /&gt;b_&lt;br /&gt;c_&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;而實際上 %xprod 就是用這種原理去做字串合併，因此我們只需要輸入：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%xprod(l1=a_ b_ c_, l2=x y);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;就可自動產生那六個字串出來。&lt;br /&gt;&lt;br /&gt;。RANGE&lt;br /&gt;這是拿來生成連續數字的程式。語法如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%range ( to=, from= , step= , sep= )&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;變數解釋：&lt;br /&gt;。to= 連續數字最後一位數，預設值是 1&lt;br /&gt;。from= 連續數字的第一位數，預設值是 1&lt;br /&gt;。step= 跳號的間格數，預設值是 1&lt;br /&gt;。sep= 分隔連續數字的字元，預設值是空格（%str( )）&lt;br /&gt;&lt;br /&gt;顧名思義，如果要生出「1 2 3 4 5」這串連續數字，則可使用：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%range(to=5);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;。REPLACE&lt;br /&gt;這是拿來取代字元的 macro，特別是使用在重新命名的動作裡面。語法如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%replace ( l= , lv= , code= , key= , lsep=, osep=)&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;變數解釋：&lt;br /&gt;。l= 輸入字串&lt;br /&gt;。lv= 取代上列字串的字串（可省略不用）&lt;br /&gt;。code= 包含 key 所代表的符號變數的字串，通常是在程式中不會被變動的字串&lt;br /&gt;。key= 用來當作取代「l」代表的字串的符號變數，預設值是 #&lt;br /&gt;。lsep= 用來區隔輸入字串的字元，預設值是空白（%str()）&lt;br /&gt;。osep= 用來區隔輸出字串的字元，預設值是空白（%str()）&lt;br /&gt;&lt;br /&gt;舉例來說，如果在套入一組資料時要順便改變某些變數名稱，則程式碼為：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data ww;&lt;br /&gt; set w(rename=(x=__x y=__y z=__z);&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;則可使用 %replace 來簡化：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data ww;&lt;br /&gt; set w(rename=(%replace(l=x y z, code=#=__#));&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;這個程式會先把 l 所定義的 x y z 用依序一個 # 來取代，而 code 的作用就是把 x y z 一一套入「#=__#」的框架裡面，進而產生「x=__x y=__y z=__z」這三個字串出來。&lt;br /&gt;&lt;br /&gt;另外還有更進階的寫法，就是把 %replace 放進另一個自創的 %rename 裡面，程式如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro rename ( list, pref=__) ;&lt;br /&gt;%replace ( l=&amp;amp;list, code = # = &amp;amp;pref# )&lt;br /&gt;%mend rename ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;%rename 的第一個參數就等於 %replace 的第一個參數，而 pref 就等於輸出字串裡面共有的字串（此例預設值是「__」）。因此原來的程式可以更簡化為：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data ww;&lt;br /&gt; set w(rename=(%rename(x y z)));&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;這時「x y z」就等於「list」，也等於「l」，而 pref 所表示的「__」被丟進 %replace 的 code 參數裡面，則 code 就變成「code= #=__#」，這就便回原來只用 %replace 的那個程式碼了。&lt;br /&gt;&lt;br /&gt;%replace 也可以使用在變數轉換上面。比方說上面這個例子，在 rename 後要把新變數轉換成 best 32. 的格式。如果不用額外的 macro 則語法是：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data ww;&lt;br /&gt;  set w(rename=(%rename(x y z)));&lt;br /&gt; x=input(__x, best32.);&lt;br /&gt; y=input(__y, best32.);&lt;br /&gt; z=input(__z, best32.);&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;同樣地，我們可以另外自製一個命為 %CHAR2NUM 的 macro，然後套用 %replace 去寫。方法如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro char2num ( list , pref = __ ) ;&lt;br /&gt;%replace ( l=&amp;amp;list&lt;br /&gt;, code= %str(# = input(&amp;amp;pref#,best32.);)&lt;br /&gt;)&lt;br /&gt;%mend char2num ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;這個新 macro 的參數用法和 %rename 一樣，但我們來看看 %replace 在裡面發會什麼功用。l 去呼叫 list 所定義的字串，而 code 生出「#=input(&amp;amp;pref#,best32.);」，其中 # 就是暫時替代 l/list 參數所定義的字串，pref 是利用預設值「__」，則 code 其實就是產生下面這三行：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;x=input(__x, best32.);&lt;br /&gt;y=input(__y, best32.);&lt;br /&gt;z=input(__z, best32.);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;因此原本的程式可以改寫成：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data ww;&lt;br /&gt;   set w(rename=(%rename(x y z)));&lt;br /&gt; %char2num(x y z);&lt;br /&gt;run;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;。QT&lt;br /&gt;這個 macro 只是很簡單地幫每個字元加上雙引號。語法如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%qt ( l=, lv= , lsep= %str( ), qt = %str(%"), osep=%str( ) )&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;變數解釋：&lt;br /&gt;。l= 輸入字串&lt;br /&gt;。lv= 取代上列字串的字串（可省略不用）&lt;br /&gt;。lsep= 用來區隔輸入字串的字元，預設值是空白（%str()）&lt;br /&gt;。qt= 幫每個字元左右加上的符號，預設值是雙引號（"）&lt;br /&gt;。osep= 用來區隔輸出字串的字元，預設值是空白（%str()）&lt;br /&gt;&lt;br /&gt;因此，如果要生成出「"a" "b" "c"」只需要簡單地使用：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%qt(l=a b c);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;以下是各 macro 的原始碼：&lt;br /&gt;。ZIP&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro zip&lt;br /&gt;( l1= /* first list */&lt;br /&gt;, lv1= /* external variable override for first list */&lt;br /&gt;, sep1=%str( ) /* separator between the joined elements */&lt;br /&gt;, l2= /* second list */&lt;br /&gt;, lv2= /* external variable override for second list */&lt;br /&gt;, sep2=%str( ) /* separator between the joined elements */&lt;br /&gt;, osep=%str( ) /* separator between new elements */&lt;br /&gt;) ;&lt;br /&gt;/* %zip ( l1= a b , l2= c d ) produces ac bd&lt;br /&gt;so does&lt;br /&gt;%let list1 = a b ;&lt;br /&gt;%let list2 = c d ;&lt;br /&gt;%zip (lv1=list1, lv2=list2)&lt;br /&gt;If lists do not have same length shorter length used and&lt;br /&gt;warning to the log. Empty lists result in empty list and&lt;br /&gt;no message.&lt;br /&gt;If the LV options are used then L1, L2, and ZIP_: should be&lt;br /&gt;avoided for variable names.&lt;br /&gt;*/&lt;br /&gt;%local zip_i zip_1 zip_2 zip_list ;&lt;br /&gt;%if %length(&amp;amp;lv1) = 0 %then&lt;br /&gt;%let lv1 = l1 ;&lt;br /&gt;%if %length(&amp;amp;lv2) = 0 %then&lt;br /&gt;%let lv2 = l2 ;&lt;br /&gt;%do zip_i = 1 %to &amp;amp;sysmaxlong ;&lt;br /&gt;%let zip_1 = %qscan(%superq(&amp;amp;lv1) , &amp;amp;zip_i, &amp;amp;sep1 ) ;&lt;br /&gt;%let zip_2 = %qscan(%superq(&amp;amp;lv2) , &amp;amp;zip_i, &amp;amp;sep2 ) ;&lt;br /&gt;%if %length(&amp;amp;zip_1) = 0 or %length(&amp;amp;zip_2) = 0 %then&lt;br /&gt;%goto check ;&lt;br /&gt;%if &amp;amp;zip_i = 1 %then&lt;br /&gt;%let zip_list = &amp;amp;zip_1&amp;amp;zip_2 ;&lt;br /&gt;%else&lt;br /&gt;%let zip_list = &amp;amp;zip_list&amp;amp;osep&amp;amp;zip_1&amp;amp;zip_2 ;&lt;br /&gt;%end ;&lt;br /&gt;%check:&lt;br /&gt;%if %length(&amp;amp;zip_1) &gt; 0 or %length(&amp;amp;zip_2) &gt; 0 %then&lt;br /&gt;%put WARNING: Macro ZIP - list lengths do not match - shorter used. ;&lt;br /&gt;%unquote(&amp;amp;zip_list)&lt;br /&gt;%mend zip ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;。XPROD&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro xprod&lt;br /&gt;( l1= /* first list */&lt;br /&gt;, lv1= /* external variable override for first list */&lt;br /&gt;, sep1=%str( ) /* separator between elements of first list */&lt;br /&gt;, l2= /* second list */&lt;br /&gt;, lv2= /* external variable override for second list */&lt;br /&gt;, sep2=%str( ) /* separator between elements of second list */&lt;br /&gt;, osep=%str( ) /* separator between elements of new list */&lt;br /&gt;) ;&lt;br /&gt;%local xp_i xp_j xp_1 xp_2 xp_list ;&lt;br /&gt;%if %length(&amp;amp;lv1) = 0 %then&lt;br /&gt;%let lv1 = l1 ;&lt;br /&gt;%if %length(&amp;amp;lv2) = 0 %then&lt;br /&gt;%let lv2 = l2 ;&lt;br /&gt;%do xp_i = 1 %to &amp;amp;sysmaxlong ;&lt;br /&gt;%let xp_1 = %qscan(%superq(&amp;amp;lv1), &amp;amp;xp_i, &amp;amp;sep1) ;&lt;br /&gt;%if %length(&amp;amp;xp_1) = 0 %then %goto endloop1 ;&lt;br /&gt;%do xp_j = 1 %to &amp;amp;sysmaxlong ;&lt;br /&gt;%let xp_2 = %qscan(%superq(&amp;amp;lv2), &amp;amp;xp_j, &amp;amp;sep2) ;&lt;br /&gt;%if %length(&amp;amp;xp_2) = 0 %then %goto endloop2 ;&lt;br /&gt;%if &amp;amp;xp_i = 1 and &amp;amp;xp_j = 1 %then&lt;br /&gt;%let xp_list = &amp;amp;xp_1&amp;amp;xp_2 ;&lt;br /&gt;%else&lt;br /&gt;%let xp_list = &amp;amp;xp_list&amp;amp;osep&amp;amp;xp_1&amp;amp;xp_2 ;&lt;br /&gt;%end ;&lt;br /&gt;%endloop2:&lt;br /&gt;%end ;&lt;br /&gt;%endloop1:&lt;br /&gt;%unquote(&amp;amp;xp_list)&lt;br /&gt;%mend xprod ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;%RANGE&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro range /* second more efficient version due to Chang Chung */&lt;br /&gt;( to=1 /* end integer value */&lt;br /&gt;, from=1 /* starting integer value */&lt;br /&gt;, step=1 /* increment integer */&lt;br /&gt;, osep=%str( ) /* sparator between integers */&lt;br /&gt;) ;&lt;br /&gt;/*&lt;br /&gt;return sequence of integers starting at &amp;amp;FROM going to &amp;amp;TO&lt;br /&gt;in steps of &amp;amp;step&lt;br /&gt;%range(to=5) produces 1 2 3 4 5&lt;br /&gt;*/&lt;br /&gt;%local rg_i ;&lt;br /&gt;%do rg_i = &amp;amp;from %to &amp;amp;to %by &amp;amp;step ;&lt;br /&gt;%if &amp;amp;rg_i = &amp;amp;from %then&lt;br /&gt;%do;&amp;amp;rg_i%end ;&lt;br /&gt;%else&lt;br /&gt;%do;&amp;amp;osep&amp;amp;rg_i%end ;&lt;br /&gt;%end ;&lt;br /&gt;%mend range ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;。REPLACE&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro replace&lt;br /&gt;( l= /* value list */&lt;br /&gt;, lv= /* external variable override for value list */&lt;br /&gt;, lsep=%str( ) /* separator between values */&lt;br /&gt;, code= /* block of code containing symbolic variable */&lt;br /&gt;, key=# /* symbolic variable to replace (#abc# etc.) */&lt;br /&gt;, osep=%str( ) /* separator between new elements */&lt;br /&gt;/* may be %str(;) when code is statement */&lt;br /&gt;/* if so remember to add closing semicolon */&lt;br /&gt;) ;&lt;br /&gt;%local rg_i rg_w rg_list ;&lt;br /&gt;%if %length(&amp;amp;lv) = 0 %then&lt;br /&gt;%let lv = l ;&lt;br /&gt;%if %length(%superq(&amp;amp;lv)) = 0 /*or %index(%superq(code),&amp;amp;key) = 0*/ %then&lt;br /&gt;%do ;&lt;br /&gt;%let rg_list = %superq(code) ;&lt;br /&gt;%goto mexit ;&lt;br /&gt;%end ;&lt;br /&gt;%do rg_i = 1 %to &amp;amp;sysmaxlong ;&lt;br /&gt;%let rg_w = %qscan(%superq(&amp;amp;lv),&amp;amp;rg_i,&amp;amp;lsep) ;&lt;br /&gt;%if %length(&amp;amp;rg_w) = 0 %then %goto mexit ;&lt;br /&gt;%if &amp;amp;rg_i = 1 %then&lt;br /&gt;%let rg_list = %sysfunc(tranwrd(%superq(code),&amp;amp;key,&amp;amp;rg_w)) ;&lt;br /&gt;%else&lt;br /&gt;%let rg_list =&lt;br /&gt;&amp;amp;rg_list&amp;amp;osep%sysfunc(tranwrd(%superq(code),&amp;amp;key,&amp;amp;rg_w)) ;&lt;br /&gt;%end ;&lt;br /&gt;%mexit:&lt;br /&gt;%unquote(&amp;amp;rg_list)&lt;br /&gt;%mend replace ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Contact information&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Ian Whitlock&lt;br /&gt;29 Lonsdale Lane&lt;br /&gt;Kennett Square, PA 19348&lt;br /&gt;Ian.Whitlock@comcast.net&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-8748576307575429576?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/8748576307575429576/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=8748576307575429576&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/8748576307575429576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/8748576307575429576'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2008/09/names-names-names-make-me-list.html' title='Names, Names, Names - Make Me a List'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-8621059153573912699</id><published>2008-08-23T16:13:00.002-04:00</published><updated>2008-10-04T20:16:23.260-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='報表輸出'/><title type='text'>Using 22 Easy Tricks with ODS to Generate Colorful Reports</title><content type='html'>原文載點：&lt;a href="http://www.lexjansen.com/mwsug/2007/Tutorials/T10-2007.pdf"&gt;http://www.lexjansen.com/mwsug/2007/Tutorials/T10-2007.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;ODS 系統在 SAS V9.1 版中已經逐漸發揮他的威力，到了 V9.2 版後更是往上提升了一個階層。不過很多人以為用用 ODS 把圖或報表直接輸出就已經是最方便的，殊不知他可以結合最簡單的 PROC PRINT 程序將輸出結果強化。這一篇在 NESUG 2007 發表的技術文件詳細記載了如何讓 ODS 搭配 PROC PRINT 來產生更美觀的報表，也同時揭露了一些在 SAS 手冊裡都沒有介紹的指令。&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;簡單來講，如果要用 PROC PRINT 程序加上 ODS 來列印報表，在完全沒有額外設定，只使用預設值的情況下，語法大概就諸如此款：&lt;br /&gt;&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-22_1738。" src="http://farm4.static.flickr.com/3284/2788122050_25f218153f.jpg?v=0" onload="show_notes_initially();" height="156" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;然後得到的結果是：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-22_1734。" src="http://farm4.static.flickr.com/3194/2787260117_374c4a6366.jpg?v=0" onload="show_notes_initially();" height="331" width="468" /&gt;&lt;br /&gt;&lt;br /&gt;如果你覺得上面這種呈現方式有點像是墓碑上刻出來的文字，而想要換成別的樣式或顏色，那麼就得靠 PROC PRINT 程序手冊裡面都很少提到（至少 SAS online documentation 沒有寫）的 style option！&lt;br /&gt;&lt;br /&gt;style option 基本的撰寫格式如下：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-22_1738。" src="http://farm4.static.flickr.com/3063/2787269681_ab2b0bcbd8.jpg?v=0" onload="show_notes_initially();" height="96" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;以這個圖例說明：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-22_1755。" src="http://farm4.static.flickr.com/3053/2787302459_0df35df543.jpg?v=0" onload="show_notes_initially();" height="146" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;利用四個 style 指令將 Obs 標題顏色、表格內資料背景顏色、Obs 列顏色以及底部 total 底色一次進行修改。&lt;br /&gt;&lt;br /&gt;接下來又一步一步來介紹不同 style 指令的用法。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1. 更改標題列顏色&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;如果想要將標題列著成黃色，如下圖所示：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-23_1621。" src="http://farm4.static.flickr.com/3211/2789786661_cf8c116068.jpg?v=0" onload="show_notes_initially();" height="189" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;則可以用下面這道程式來實現：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-23_1623。" src="http://farm4.static.flickr.com/3154/2789793985_49c7b31c5a.jpg?v=0" onload="show_notes_initially();" height="160" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;其中，黃色標記處 style(header)={background=yellow}; 即是讓標題列變成黃色的關鍵。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2. 更改總和列顏色和字型和大小&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;PROC PRINT 裡面有個 SUM statement 可以計算每個欄位的總和，如想要更改此處的背景顏色、字型樣式和字型大小，如下圖所示：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-23_1626。" src="http://farm4.static.flickr.com/3193/2789797795_2753b9eee7.jpg?v=0" onload="show_notes_initially();" height="208" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;則可以使用這道程式：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-23_1630。" src="http://farm4.static.flickr.com/3078/2790660858_13d990cc6a.jpg?v=0" onload="show_notes_initially();" height="194" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;黃色標明處 style (grandtotal)={background=grayee font=(Arial) font_size=6}; 即是更改由橘色標明處 SUM statement 所算出來的兩個總和欄位的背景顏色(grayee)、字型(Arial)和字型大小(font_size)。如果沒有 SUM statement，則黃色標明處的語法將不會有任何作用。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;3. 更改表格資料欄背景顏色&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;如想要改變表格資料的背景顏色，如下圖所示：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-23_1637。" src="http://farm4.static.flickr.com/3131/2790677408_8ae8e24d68.jpg?v=0" onload="show_notes_initially();" height="224" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;則語法如下：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-23_1652。" src="http://farm4.static.flickr.com/3080/2789869613_687e285f71.jpg?v=0" onload="show_notes_initially();" height="249" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;黃色標明處 style(data)={background=grayee} 即是用來設定資料欄位背景顏色。附帶一提，標題列會自動斷成兩行是利用紅色標明處的 split='*' 進行設定，然後在橘色標明處 label statement 裡面將標題要斷行的地方打上 * 即可。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;4. 更改分類總和欄位背景顏色&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;如果有使用 by statement 來計算不同分類欄位的總和，則其背景顏色也可以修改，如下圖所示：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-23_1657。" src="http://farm4.static.flickr.com/3094/2790727094_10a8e6accf.jpg?v=0" onload="show_notes_initially();" height="421" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;語法如下：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-23_1659。" src="http://farm4.static.flickr.com/3056/2789883635_27cece1453.jpg?v=0" onload="show_notes_initially();" height="140" width="500" /&gt;&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-23_1701。" src="http://farm4.static.flickr.com/3224/2790737456_164cfb6649.jpg?v=0" onload="show_notes_initially();" height="131" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;此程式由於有使用 by origcity; 和 sum statement 來計算每個程式 sales2005 和 sales2006 的總和，所以要修改分類總和欄位的背景顏色，就得用黃色標明處的 style(total)={background=light green}; 來設定。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;5. 更改特定欄位字體顏色&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;若想指定某個欄位的字型顏色，如下圖所示：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-23_1704。" src="http://farm4.static.flickr.com/3043/2790747022_95b8133b8c.jpg?v=0" onload="show_notes_initially();" height="252" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;可使用下列程式：&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-23_1707。" src="http://farm4.static.flickr.com/3035/2789903929_76138143cc.jpg?v=0" onload="show_notes_initially();" height="79" width="500" /&gt;&lt;br /&gt;&lt;img class="reflect" title="" alt="你拍攝的 2008-08-23_1706。" src="http://farm4.static.flickr.com/3007/2790751618_d69a4fb121.jpg?v=0" onload="show_notes_initially();" height="146" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;黃色標明處的 var month 後面加上 /style={foreground=red}; 就可以更改 month 這個欄位字型顏色。此外，一開頭的 SAS logo 是用 title3 後面的 "^S=preimage='c:\ben\qp\SAS_logo.bmp'}" 所貼上。&lt;br /&gt;&lt;br /&gt;總結：作者有坦承這篇文件沒有把 22 個 trick 都用上，不過會在 conference 裡面說明。不過由於沒有她在會議裡面的任何影音檔，所以無法得知其他沒有在文件裡面的小技巧是什麼。但上述這些語法已經足夠讓表格變的更漂亮，因此有興趣的人可以玩玩不同組合最出現什麼情況。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;CONTACT INFORMATION&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. Contact the author at:&lt;br /&gt;Ben Cochran&lt;br /&gt;The Bedford Group&lt;br /&gt;Raleigh, NC 27607&lt;br /&gt;Office: 919.831.1191&lt;br /&gt;Fax: 919.831.1191&lt;br /&gt;Email: bedfordgroup@nc.rr.com&lt;br /&gt;Web: www.bedford-group.com&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-8621059153573912699?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/8621059153573912699/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=8621059153573912699&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/8621059153573912699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/8621059153573912699'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2008/08/using-22-easy-tricks-with-ods-to.html' title='Using 22 Easy Tricks with ODS to Generate Colorful Reports'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-8296450468469181712</id><published>2008-08-14T16:33:00.005-04:00</published><updated>2008-10-04T20:16:54.794-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='資料整理'/><title type='text'>Adding One Value to All Observations</title><content type='html'>原文載點：&lt;a href="http://www.nesug.info/Proceedings/nesug07/cc/cc45.pdf"&gt;http://www.nesug.info/Proceedings/nesug07/cc/cc45.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;由於最近在工作上太多人問到這個問題，所以我特別找出這一篇文章來說明。在 SAS 裡面，要在每筆資料後面加上一個特定值，依據資料排列格式的不同，有許多種作法。有得很簡單，只需要在 data step 加上一行即可，有得很複雜，得動用到 merge statement 或 proc sql 才能解決。這一篇在 NESUG 2007 年發表的技術文件列出了一些解法可供參考。&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;本例使用這個樣本資料：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data temp;&lt;br /&gt;input Obs ID EARNHR @@;&lt;br /&gt;cards;&lt;br /&gt;1 1 .&lt;br /&gt;2 2 5.75&lt;br /&gt;3 3 5.75&lt;br /&gt;4 4 6.30&lt;br /&gt;5 5 6.75&lt;br /&gt;6 6 8.00&lt;br /&gt;7 7 8.25&lt;br /&gt;8 8 9.60&lt;br /&gt;9 9 10.05&lt;br /&gt;10 10 12.80&lt;br /&gt;;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;如果打算算出 EARNHR 的中間值，然後讓他變成一個獨立的變數放在原資料 temp 的最後面。最常使用的方法是先使用 PROC MEANS 把中間值的結果另存到新的資料檔裡面：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc means data = temp noprint ;&lt;br /&gt;  var EARNHR ;&lt;br /&gt;  output out = add (drop = _TYPE_ _FREQ_) median(EARNHR) = MEDIANEARNHR;&lt;br /&gt;run ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;然後再用 merge 的方法放回原資料檔：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data temp3 ;&lt;br /&gt;  set temp ;&lt;br /&gt;  if _N_ = 1 then set add ;&lt;br /&gt;run ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;接下來要教兩個進階用法。由於第一個方法會生出一個無用的資料檔 MEDIANEARNHR，雖然他只是放在暫存檔，關掉 SAS 後就會消失。但使用 PROC SQL 就根本連這個檔都不會產生。方法如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc sql ;&lt;br /&gt;  select mean(EARNHR) as AVGEARNHR format = 8.2 into :MEANEARNHR&lt;br /&gt;  from temp ;&lt;br /&gt;quit;&lt;br /&gt;&lt;br /&gt;data temp ;&lt;br /&gt;  set temp ;&lt;br /&gt;  mean= &amp;amp;MEANEARNHR ;&lt;br /&gt;run ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;本例改成放 EARNHR 的平均值 MEANEARNHR。先用 PROC SQL 把 AVEARNHR 算出來，放進一個叫做 MEANEARNHR 的巨集變數裡面，然後在把他命名成mean放進原來的資料內。這還有很多其他的用途。比方說如果想要挑出 EARNHR 小於平均值的樣本，則可以用這個 data step 來挑出：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data temp2 ;&lt;br /&gt;  set temp ;&lt;br /&gt;  where EARNHR lt &amp;amp;MEANEARNHR ;&lt;br /&gt;run ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;挑出來的結果是：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;Obs ID EARNHR&lt;br /&gt;1 2 5.75&lt;br /&gt;2 3 5.75&lt;br /&gt;3 4 6.30&lt;br /&gt;4 5 6.75&lt;br /&gt;5 6 8.00&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;第三種方法則是用 SYMPUT 函式來定義巨集變數。此例，先用 PROC MEANS 去計算 EARNHR 的中間值，並存在 add2 裡面。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;proc means data = temp noprint ;&lt;br /&gt;  var EARNHR ;&lt;br /&gt;  output out = add2 (drop=_TYPE_ _FREQ_) median(EARNHR) = MEDIANEARNHR;&lt;br /&gt;run ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;然後開一個虛無的資料集「_null_」（這個資料連在work library都不會出現），然後把 add2 裡面的中間值變數名稱用 SYMPUT 定義成巨集變數。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data _null_ ;&lt;br /&gt;  set add2 ;&lt;br /&gt;  call symputx ('MDNEARNHR', MEDIANEARNHR) ;&lt;br /&gt;run ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;最後就可以利用這個巨集變數在新的 data step 裡面做很多動作。無論是新增變數還是去挑資料都相當容易。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data temp;&lt;br /&gt;  set temp ;&lt;br /&gt;  median=&amp;MDNEARNHR;&lt;br /&gt;  where EARNHR ge 0 and EARNHR lt &amp;amp;MDNEARNHR ;&lt;br /&gt;run ;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;個人傾向使用 PROC SQL 是因為他能夠減少無謂的資料檔輸出，只是需要相當熟悉他的語法才能夠用上手。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;CONTACT INFORMATION&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. Contact the author at:&lt;br /&gt;Anne W. Warren&lt;br /&gt;MDRC&lt;br /&gt;16 East 34th Street, 19th floor&lt;br /&gt;New York, NY 10016&lt;br /&gt;Work Phone: 212.340.8661&lt;br /&gt;Fax: 212.684.0832&lt;br /&gt;Email: anne.warren@mdrc.org&lt;br /&gt;Web: www.mdrc.org&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-8296450468469181712?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/8296450468469181712/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=8296450468469181712&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/8296450468469181712'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/8296450468469181712'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2008/08/adding-one-value-to-all-observations.html' title='Adding One Value to All Observations'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-4605553953405367494</id><published>2008-06-23T17:16:00.001-04:00</published><updated>2008-10-04T20:17:07.069-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>Reliability analysis: Calculate and Compare Intra-class Correlation Coefficients (ICC) in SAS</title><content type='html'>原文載點：&lt;a href="http://www.nesug.info/Proceedings/nesug07/sa/sa13.pdf"&gt;http://www.nesug.info/Proceedings/nesug07/sa/sa13.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;在 reliability analysis 裡面，intra-class correlation coefficients (ICC) 是一個相當重要的統計指標。不過長久以來，SAS 內部並沒有可以直接計算 ICC 的程序。雖然有許多&lt;a href="http://department.obg.cuhk.edu.hk/researchsupport/IntraClass_correlation.asp"&gt;線上的 ICC 計算器&lt;/a&gt;，不過仍有許多人研發出在 SAS 上運作的 ICC macro 供 SAS 使用者使用。Li Lu 和 Nawar Shara 在 2007 年的 NESUG 發表了一篇自行撰寫的 ICC macro 技術文件，不但可用來計算 ICC 本身，還可以求出其信賴區間。&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;原始碼如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro Icc_sas(ds, response, subject);&lt;br /&gt; ods output OverallANOVA =all;&lt;br /&gt; proc glm data=&amp;ds;&lt;br /&gt;     class &amp;subject;&lt;br /&gt;     model &amp;amp;response=&amp;subject;&lt;br /&gt; run;&lt;br /&gt; data Icc(keep=sb sw n R R_low R_up);&lt;br /&gt;     retain sb sw n;&lt;br /&gt;     set all end=last;&lt;br /&gt;     if source='Model' then sb=ms;&lt;br /&gt;     if source='Error' then do;sw=ms; n=df; end;&lt;br /&gt;     if last then do;&lt;br /&gt;     R=round((sb-sw)/(sb+sw), 0.01);&lt;br /&gt;     vR1=((1-R)**2)/2;&lt;br /&gt;     vR2=(((1+R)**2)/n +((1-R)*(1+3*R)+4*(R**2))/(n-1));&lt;br /&gt;     VR=VR1*VR2;&lt;br /&gt;     L=(0.5*log((1+R)/(1-R)))-(1.96*sqrt(VR))/((1+R)*(1-R));&lt;br /&gt;     U=(0.5*log((1+R)/(1-R)))+(1.96*sqrt(VR))/((1+R)*(1-R));&lt;br /&gt;     R_Low=(exp(2*L)-1)/(exp(2*L)+1);&lt;br /&gt;     R_Up=(exp(2*U)-1)/(exp(2*U)+1);&lt;br /&gt;     output;&lt;br /&gt;     end;&lt;br /&gt; run;&lt;br /&gt; proc print data=icc noobs split='*';&lt;br /&gt;     var r r_low r_up;&lt;br /&gt;     label r='ICC*' r_low='Lower bound*' r_up='Upper bound*';&lt;br /&gt;     title 'Reliability test: ICC and its confidence limits';&lt;br /&gt; run;&lt;br /&gt;%mend;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;包含三個參數：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ds：資料名稱（含 library）&lt;/li&gt;&lt;li&gt;response：反應變數名稱&lt;/li&gt;&lt;li&gt;subject：ID 名稱&lt;/li&gt;&lt;/ul&gt;使用方式相當簡單。如：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%Icc_sas(ds=one, response=cimt, subject=subject_id);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;由於原文沒有提供 one 這個資料集的原始資料，所以不知道跑出來的結果如何。有興趣的人可以拿自己的資料測試，並與其他線上 ICC 計算器的結果進行比對。如有發現異常現象請回報給原作者。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;CONTACT INFORMATION&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Your code requests, comments and questions are valued and encouraged. Contact the author at&lt;br /&gt;Li Lu&lt;br /&gt;Dept of Epidemiology and Statistics&lt;br /&gt;MedStar Research Institute&lt;br /&gt;6495 New Hampshire Avenue&lt;br /&gt;Hyattsville, MD 20783&lt;br /&gt;(301) 560-7313&lt;br /&gt;li.lu@medstar.net&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-4605553953405367494?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/4605553953405367494/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=4605553953405367494&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/4605553953405367494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/4605553953405367494'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2008/06/reliability-analysis-calculate-and.html' title='Reliability analysis: Calculate and Compare Intra-class Correlation Coefficients (ICC) in SAS'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-6688888116627503380</id><published>2008-06-05T22:09:00.001-04:00</published><updated>2008-10-04T20:17:20.222-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='巨集程式'/><title type='text'>ALPHA_CI: A SAS® Macro for Computing Confidence Intervals for Coefficient Alpha</title><content type='html'>原文載點：&lt;a href="http://www2.sas.com/proceedings/forum2008/230-2008.pdf"&gt;http://www2.sas.com/proceedings/forum2008/230-2008.pdf&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;在進行效度分析的時候，我們通常都會需要去求一個叫做 Cronbach's alpha的值，而這個值越大代表整個問卷設計的可信度越高。在 SAS 中可利用 PROC CORR 程序輕鬆地計算出這個數值出來，但卻沒有辦法去估計他的信賴區間。事實上，已有不少的學者發表相關文獻來估計 Cronbach's alpha 的信賴區間，而 Jeffrey D. Kromrey, Jeanine Romano 和 Susan T. Hibbard 收集了八個不同的估計方法，並將其整合在一個 macro 程式裡面。&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;相關的理論請參考原文以及其附錄的參考文獻。&lt;br /&gt;&lt;br /&gt;整個 macro 的原始程式碼如下：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%macro ALPHA_CI (dsn = _last_,n_items = 100,confidence = .95);&lt;br /&gt;proc iml symsize = 500;&lt;br /&gt;start Bonett(N1,items,rxx,confidence,lowerCI,upperCI);&lt;br /&gt;* +--------------------------------------------------------------------------------------+&lt;br /&gt;Bonett 2002 method of CI computation&lt;br /&gt;Inputs to subroutine are number of examinees (N1), number of items (items),&lt;br /&gt;sample value of coefficient alpha (rxx), and desired level of confidence&lt;br /&gt;(Confidence).&lt;br /&gt;Outputs are the upper and lower limits of the confidence interval (upperCI, lowerCI)&lt;br /&gt;+--------------------------------------------------------------------------------------+;&lt;br /&gt;critZ = -1#probit((1-Confidence)/2);&lt;br /&gt;transBon_z = log(1-abs(rxx));&lt;br /&gt;if rxx &lt;0 transbon_z =" transBon_z" var_z =" (2#items)/((items" se_bon_z =" sqrt(var_z);" lowerci =" 1" upperci =" 1" lowerf =" (1-Confidence)/2;" upperf =" Confidence" fb =" FINV(upperF,N1-1,(N1-1)#(items-1),0);" fa =" FINV(lowerF,N1-1,(N1-1)#(items-1),0);" lowerci =" 1" upperci =" 1" critz =" -1#probit((1-Confidence)/2);" transfish_z =" 0.5#log((1+abs(rxx))/(1-abs(rxx)));" transfish_z =" transfish_z" se_fish_z =" sqrt((n1-3)##-1);" upperci =" (exp(2#(transfish_z" lowerci =" (exp(2#(transfish_z" critz =" -1#probit((1-Confidence)/2);" transhawh_z =" (1-rxx)**(1/3);" var_z =" ((18#items)#(n1" se_hawh_z =" sqrt(var_z);" c_star =" ((9#n1" lowerci =" 1" upperci =" 1" critz =" -1#probit((1-Confidence)/2);" bigone =" j(N1," means =" ((bigone`)*out3pl)/N1;" score3pld =" out3pl-(bigone*means);" itemcov =" (1/(N1-1))*((SCORE3PLd`)*SCORE3PLd);" one =" j(items,1);" jtphij =" (one`)*itemcov*one;" trphisq =" trace(itemcov*itemcov);" trsqphi =" (trace(itemcov))**2;" jtphisqj =" (one`)*(itemcov*itemcov)*one;" omega =" jtphij*(trphisq+trsqphi);" omega =" omega-(2*(trace(itemcov))*jtphisqj);" omega =" (2/(jtphij**3))*omega;" s2 =" (items**2)/((items-1)**2);" s2 =" s2*omega;" se =" sqrt(s2/N1);" lowerci =" rxx-(CritZ*se);" upperci =" rxx+(CritZ*se);" lowerf =" (1-Confidence)/2;" upperf =" Confidence" fb =" FINV(upperF,n1#(items-1),n1,0);" fa =" FINV(lowerF,n1#(items-1),n1,0);" upperci =" 1" lowerci =" 1" critz =" -1#probit((1-Confidence)/2);" upperci =" 1" lowerci =" 1" parm =" J(1,7,.);" nsub =" NROW(data);" nvar =" NCOL(data);" nv2 =" nvar*(nvar+1)/2;" rsub =" 1." rs1 =" 1." vrat =" nvar" mean =" data[+,]" quant =" -1#probit((1-prob)/2);" cov =" rs1" vvar =" vecdiag(cov);" summat =" cov[+,+];" sumvars =" vvar[+];" sumcovs =" .5*(summat" wcv =" cov" wvv =" vecdiag(wcv);" sumvar2 =" wvv[+];" summat2 =" wcv[+,+];" alpha =" vrat" tmp =" 2." t1 =" summat" t2 =" summat" t3 =" 2.*sumvars" nase =" tmp*(t1" nase =" sqrt(rsub*nase);" dwrtvar =" -2." dwrtcov =" vrat" jac =" J(nvar,nvar,dwrtcov);" j=" 1" trac =" 0.;" isub="1" v =" data[isub,]" wcv =" jac" tmp =" wcv[+,+];" trac =" trac" nnase =" sqrt(rsub*rs1*trac);" i =" 1" i =" 1" item_scores =" temp_x;"&gt; 1 then do;&lt;br /&gt;Item_Scores = Item_Scores || temp_x;&lt;br /&gt;End;&lt;br /&gt;%end;&lt;br /&gt;confidence = &amp;confidence;&lt;br /&gt;* +---------------------------------+&lt;br /&gt;Computation of Cronbach Alpha&lt;br /&gt;+---------------------------------+;&lt;br /&gt;N_items = ncol(Item_Scores);&lt;br /&gt;N_obs = nrow(Item_Scores);&lt;br /&gt;mu1 = J(N_items,1,0);* ;&lt;br /&gt;var = J(1,N_items,0);* ;&lt;br /&gt;do k = 1 to N_items;&lt;br /&gt;do i=1 to N_obs;&lt;br /&gt;mu1[k,1] = mu1[k,1] + Item_Scores[i,k];* ;&lt;br /&gt;end;&lt;br /&gt;var[1,k]=(mu1[k,1]/N_obs)*(1 - mu1[k,1]/N_obs);&lt;br /&gt;end;&lt;br /&gt;sumvar=0;&lt;br /&gt;do k = 1 to N_items;&lt;br /&gt;sumvar = sumvar + var[1,k];* ;&lt;br /&gt;end;&lt;br /&gt;rowsum = J(N_obs,1,0);&lt;br /&gt;do p = 1 to N_obs;&lt;br /&gt;do k = 1 to N_items;&lt;br /&gt;rowsum[p,1]=rowsum[p,1] + Item_Scores[p,k];&lt;br /&gt;end;&lt;br /&gt;end;&lt;br /&gt;sumscore = 0;&lt;br /&gt;sumscore2 = 0;&lt;br /&gt;do p = 1 to N_obs;&lt;br /&gt;sumscore = sumscore + rowsum[p,1];&lt;br /&gt;sumscore2= sumscore2 + rowsum[p,1]##2;&lt;br /&gt;end;&lt;br /&gt;vartotal= (sumscore2-(sumscore##2/N_obs))/(N_obs);&lt;br /&gt;* +------------------------------------------------------------+&lt;br /&gt;Be sure we have some score variance before going any further&lt;br /&gt;* +------------------------------------------------------------+;&lt;br /&gt;if vartotal &lt;=0 then do; print 'Total Score Variance =' vartotal; print 'Check the Data!'; end; if vartotal &gt; 0 then do;&lt;br /&gt;rxx = (N_items/(N_items -1))*((vartotal- sumvar)/vartotal);&lt;br /&gt;if rxx &lt; rxx =" .00001;"&gt; .99 then rxx = .99;&lt;br /&gt;* +-------------------------------------------+&lt;br /&gt;Call subroutines for confidence intervals&lt;br /&gt;+------------------------------------------+;&lt;br /&gt;run Bonett(N_obs,N_items,rxx,Confidence,lowerBonett,upperBonett);&lt;br /&gt;run Feldt(N_obs,N_items,rxx,Confidence,lowerFeldt,upperFeldt);&lt;br /&gt;run Fisher(N_obs,N_items,rxx,Confidence,lowerFisher,upperFisher);&lt;br /&gt;run HW(N_obs,N_items,rxx,Confidence,lowerHw,upperHW);&lt;br /&gt;run ID(N_obs,N_items,rxx,Item_Scores,confidence,lowerID,upperID);&lt;br /&gt;run KF1(N_obs,N_items,rxx,Confidence,lowerKF1,upperKF1);&lt;br /&gt;run KF2(N_obs,N_items,rxx,Confidence,lowerKF2,upperKF2);&lt;br /&gt;parm = scalpha(Item_Scores,confidence);&lt;br /&gt;lowerADF = parm[1,6];&lt;br /&gt;upperADF = parm[1,7];&lt;br /&gt;end; * end the 'if vartotal &gt; 0' conditional;&lt;br /&gt;rxx = round(rxx,.001);&lt;br /&gt;* +---------------------------------+&lt;br /&gt;Printed macro output&lt;br /&gt;+---------------------------------+;&lt;br /&gt;file print;&lt;br /&gt;put @1 'Confidence Intervals for Coefficient Alpha' /&lt;br /&gt;@1 '-------------------------------------------------------' /&lt;br /&gt;@1 'Level of Confidence:' @30 Confidence /&lt;br /&gt;@1 'Number of Observations:' @30 N_obs /&lt;br /&gt;@1 'Number of Items:' @30 N_items /&lt;br /&gt;@1 'Sample Value of Alpha:' @30 rxx //&lt;br /&gt;@1 'Method' @40 'Lower' @50 'Upper' /&lt;br /&gt;@1 '------------------------------' @40 '-----' @50 '-----' /&lt;br /&gt;@1 'Bonett' @40 lowerBonett 5.3 @50 upperBonett 5.3 /&lt;br /&gt;@1 'Feldt' @40 lowerFeldt 5.3 @50 upperFeldt 5.3 /&lt;br /&gt;@1 'Fisher' @40 lowerFisher 5.3 @50 upperFisher 5.3 /&lt;br /&gt;@1 'Hakstain &amp;amp; Whalen' @40 lowerHW 5.3 @50 upperHW 5.3 /&lt;br /&gt;@1 'Iacobucci &amp;amp; Duchachek' @40 lowerID 5.3 @50 upperID 5.3 /&lt;br /&gt;@1 'Koning &amp;amp; Frances Exact' @40 lowerKF1 5.3 @50 upperKF1 5.3 /&lt;br /&gt;@1 'Koning &amp;amp; Frances Asymptotic' @40 lowerKF2 5.3 @50 upperKF2 5.3 /&lt;br /&gt;@1 'Asymptotic Distribution Free' @40 lowerADF 5.3 @50 upperADF 5.3 /&lt;br /&gt;@1 '-------------------------------------------------------';&lt;br /&gt;quit;&lt;br /&gt;%mend;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;以上長達數百行的原始碼，我們不需要特別瞭解內部構造，只要知道該怎樣用即可。整個 macro 包含三個參數：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;dsn：使用的 data set 名稱。如果沒有特別指定，則這個 macro 會直接使用最後一次使用過的 data set。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;n_items：變數數量。預設值是 1000。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;confidence：信賴區間大小。預設值是 0.95。&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;以下為一個小小使用範例。假設有個問卷裡面有五道題目，而每題的選項只有兩種：1 和 0。可利用下面這個 data step 完成資料輸入：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;data one;&lt;br /&gt;input @1 (X1 - X5)(1.);&lt;br /&gt;cards;&lt;br /&gt;10000&lt;br /&gt;11000&lt;br /&gt;11100&lt;br /&gt;11110&lt;br /&gt;11111&lt;br /&gt;00000&lt;br /&gt;10000&lt;br /&gt;11000&lt;br /&gt;11100&lt;br /&gt;11110&lt;br /&gt;11111&lt;br /&gt;00000&lt;br /&gt;;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;欲算出 95%、99% 和 90% 的信賴區間，則只要輸入下面這三行即可：&lt;br /&gt;&lt;pre&gt;&lt;code&gt;%ALPHA_CI (dsn = one,n_items = 5);&lt;br /&gt;%ALPHA_CI (dsn = one,n_items = 5,confidence=.99);&lt;br /&gt;%ALPHA_CI (dsn = one,n_items = 5,confidence=.90);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;以第一個 95% 信賴區間為例，報表如下：&lt;br /&gt;&lt;img class="reflect" alt="" src="http://farm4.static.flickr.com/3056/2555233900_a8996cc28e.jpg?v=0" onload="show_notes_initially();" height="375" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;由於沒有方法去檢定哪個信賴區間是最適合的，所以作者列出下面這個表格，讓使用者根據自己的樣本大小去評斷哪種方法所算出來的信賴區間有較高的覆蓋機率（coverage probability）。&lt;br /&gt;&lt;img class="reflect" alt="" src="http://farm4.static.flickr.com/3086/2554411681_de56947cd7.jpg?v=0" onload="show_notes_initially();" height="256" width="500" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;CONTACT INFORMATION&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Your comments and questions are valued and encouraged. Please contact Jeff Kromrey at:&lt;br /&gt;University of South Florida&lt;br /&gt;4202 East Fowler Ave. EDU 162&lt;br /&gt;Tampa, FL 33620&lt;br /&gt;Work Phone: 813-974-5739&lt;br /&gt;Fax: 813-974-4495&lt;br /&gt;Email: kromrey@tempest.coedu.usf.edu&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6268919072942670865-6688888116627503380?l=sugiclub.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sugiclub.blogspot.com/feeds/6688888116627503380/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6268919072942670865&amp;postID=6688888116627503380&amp;isPopup=true' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6688888116627503380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6268919072942670865/posts/default/6688888116627503380'/><link rel='alternate' type='text/html' href='http://sugiclub.blogspot.com/2008/06/alphaci-sas-macro-for-computing.html' title='ALPHA_CI: A SAS® Macro for Computing Confidence Intervals for Coefficient Alpha'/><author><name>天堂之門</name><uri>https://profiles.google.com/115512793178406908631</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-bZZ6ZfitOVc/AAAAAAAAAAI/AAAAAAAAF-g/Bgz3EH3hnYE/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6268919072942670865.post-7049217207448815617</id><published>2008-05-17T13:32:00.005-04:00</published><updated>2011-06-08T13:19:56.963-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程序語法'/><title type='text'>PROC FACTOR: How to Interpret the Output of a Real-World Example</title><content type='html'>原文載點：&lt;a href="http://www2.sas.com/proceedings/sugi22/STATS/PAPER268.PDF"&gt;&lt;span class="url"&gt;http://www2.sas.com/proceedings/sugi22/STATS/PAPER268.PDF&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;在網路上面看到有許多論文是做實證研究的人使用 factor analysis，但一方便不懂其理論，另一方面蠻幹式地去跑程式，當然跑出來的報表是有看沒有懂。每次一直重複解答同樣的問題也讓回應者感到很煩，所以在這邊就對 PROC FACTOR 做個簡單描述。我引用 Rachel  J. Goldberg 所發表的技術文件，但不知道是哪一年發表的，也不曉得是在哪一期的 SUGI 發表的。不過該篇文章確實放在 SUGI 的資料庫裡面，所以就拿出來做一個簡易的範例教學。&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;/span&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;span id="fullpost"&gt;&amp;nbsp;使用 Factor Analysis 的三大目標是：&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span id="fullpost"&gt;使用最少的因素數來解釋資料最大的變異。&lt;/span&gt;&lt;/li&gt;&lt;span id="fullpost"&gt;&lt;li&gt;藉著轉置因素來找尋更簡單也更容易去解釋的因素。&lt;/li&gt;&lt;li&gt;決定因素之有意義的解釋以瞭解資料本身潛在的特性，以利於更進一步的分析。&lt;/li&gt;&lt;/span&gt;&lt;/ul&gt;&lt;span id="fullpost"&gt;我們以下面一個簡單的範例程式來瞭解 PROC FACTOR 中每個語法的意義和用途。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;PROC FACTOR DATA=SAVE.EXAMP&lt;br /&gt;METHOD=PRINCIPAL&lt;br /&gt;SCREE&lt;br /&gt;MINEIGEN=O&lt;br /&gt;NFACTOR=16&lt;br /&gt;ROTATE=VARIMAX&lt;br /&gt;REORDER&lt;br /&gt;OUT=SAVE.EXAMPFAC;&lt;br /&gt;VAR X2--GAPLL;&lt;br /&gt;RUN;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;簡言之，PROC FACTOR 程序裡面只有一個 VAR statement 需要拿來指定要納入整個分析的原始變數名稱（即此例的 X2 -- GAPLL）。許多內部功能，全部都只需要在 PROC FACTOR 後面的 option 來操作。以下就分別介紹每個 option 的用途：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;DATA：用來指定所使用的資料集名稱。&lt;/li&gt;&lt;li&gt;METHOD：用來指定從原始變數歸納出數個主要因素所需的方法。最常使用的是主成分分析法（Principle Component Analysis），語法是 PRINCIPLE 或 PRIN 或 P。其他還有 Alpha method（語法是 ALPHA）、Harris method（語法是 HARRIS）、Unweighted least squares factor analysis（語法是 ULS）等等。不過 PRINCIPLE 仍就是最常使用的方法。&lt;/li&gt;&lt;li&gt;SCREE：可以畫出特徵值（eigenvalue）的 scree plot，稍後的範例會再介紹。&lt;/li&gt;&lt;li&gt;MINEIGEN：可以指定特徵值的最小值，小於這個最小值的特徵值將不會被列在報表裡面。預設值是「0」。&lt;/li&gt;&lt;li&gt;NFACTOR：可以指定被歸納出來的因素的數量，預設值是等同於原始變數數量。亦即，若有四個原始變數，則會產生四個因素。如果利用這個 option 設定成只要三個因素，則最後一個因素（通常是特徵值最小的那個因素）將不會被列在報表裡面。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;ROTATE：這應該是整個程序中最重要的一個選項。轉置的功用主要是讓歸納出來的因素彼此間更有區分性和代表性。以幾何學的角度來看，轉置後的因素在空間向量裡面會更加呈現直角狀態，亦即互相獨立。但是在實務經驗裡面來看，並不是轉置過後的因素就一定會完美到這種地步，我們僅能就所能夠容忍的範圍內來採納。轉置的方法有很多種，常用的有 Varimax rotation（語法是 VARIMAX 或 V）、Orthomax rotation（語法是 ORTHOMAX）、Orthogonal equamax rotation（語法是 EQUAMAX）等等。此外，並沒有工具可以輔助來求得最佳化的轉置法，通常都是一個個去測試，看哪個結果比較容易解釋就用哪種轉置法。如果沒有指定這個選項，則因素不會被轉置。&lt;/li&gt;&lt;li&gt;REORDER：這個語法只是控制報表裡面各種因素的排列方式是依照能夠解釋資料最大變異的因素排在最上面，然後依序排下來。&lt;/li&gt;&lt;li&gt;OUT：可以將分析結果輸出成另一個資料集。&lt;/li&gt;&lt;/ul&gt;以上是最常使用的 option，但其實還有其他 option 可以使用。而 VAR 也絕對不是唯一的 statement，詳細的全部語法介紹可以參考下面這個連結：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://support.sas.com/onlinedoc/913/getDoc/en/statug.hlp/factor_sect5.htm"&gt;http://support.sas.com/onlinedoc/913/getDoc/en/statug.hlp/factor_sect5.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;在解釋輸出報表之前，先稍微提一下特徵值（eigenvalue）的觀念，讓沒有線性代數背景的人能夠對這個怪異名詞有一點粗淺的瞭解。他最原始的數理演算過程可以參考下面個中文網頁：&lt;br /&gt;&lt;br /&gt;&lt;a href="http://webclass.ncu.edu.tw/~junwu/ch5_3_2.htm"&gt;http://webclass.ncu.edu.tw/~junwu/ch5_3_2.htm&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;在因素分析中，特徵值便是拿來製造原始變數的線性組合所需要的元素。&lt;br /&gt;&lt;br /&gt;以下就來介紹幾個重要的輸出報表：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;EIGENVALUES OF THE CORRELATION MATRIX&lt;/span&gt;&lt;br /&gt;&lt;img alt="" class="reflect" height="186" onload="show_notes_initially();" src="http://farm3.static.flickr.com/2337/2497203389_e48976e74f.jpg?v=0" width="456" /&gt;&lt;br /&gt;&lt;br /&gt;這個報表提供了所有特徵值（從大到小排列）所提供的訊息，包含：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Eigenvalue：特徵值數據。&lt;/li&gt;&lt;li&gt;Difference：和後一個特徵值的差距。&lt;/li&gt;&lt;li&gt;Proportion：每個特徵值可以解釋資料變異的比例。越大的特徵值可以解釋資料的變異也越大。&lt;/li&gt;&lt;li&gt;Cumulative：累積的解釋變異比例。&lt;/li&gt;&lt;/ul&gt;一般說來，大於一的特徵值已經足以解釋資料的變異。而以此範例為例，最小的特徵值是 1.0139，也就表示十六個特徵值所歸納出來的因素都可以使用。但這只是「學理上」的講法，實際還是要看最後的結果能不能解釋。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;SCREE PLOT OF EIGENVALUE&lt;br /&gt;&lt;/span&gt;&lt;img alt="" class="reflect" height="500" onload="show_notes_initially();" src="http://farm4.static.flickr.com/3139/2498034910_851c7afa0a.jpg?v=0" width="449" /&gt;&lt;br /&gt;&lt;span style="color: red; font-weight: bold;"&gt;(註）原文無圖，僅以另一個 SAS 範例內的 Scree plot 來代替。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Scree plot 是把所有特徵值按大小標記在座標軸上。若將每個點連接起來，可以發現斜率越大的區段能夠解釋資料變異的能力越大。由於一開始的特徵值都比較大，所以起初的斜率都很大，到最後特徵值越來越小，整個斜率變化的幅度也會慢慢趨緩。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;FACTOR PATTERN&lt;/span&gt;&lt;br /&gt;&lt;img alt="" class="reflect" height="210" onload="show_notes_initially();" src="http://farm3.static.flickr.com/2148/2498036430_810c4900e3.jpg?v=0" width="454" /&gt;&lt;br /&gt;&lt;br /&gt;這個表格顯示出每個因素的變異數能夠解釋原始變數變異的程度。我們稱這些數字為負荷（loading）。負荷越大代表該變數在那個因素的重要性也越大。理想上我們只希望一個變數只要在其中一個因素裡面佔有相對重要性就好，因此當一個變數在某因素出現較大的負荷，則我們就能把該變數歸納到擁有較大負荷的因素裡去。但是，在因素分析中，並沒有明確的規定多大的負荷才叫做大，通常都是以「相對比較」來看。最佳的情況是，某變數的在某因素的負荷比其他因素的負荷要來的大，並且其他因素的負荷最好是&lt;span style="color: red; font-weight: bold;"&gt;非常接近零&lt;/span&gt;。不過以此例的變數 X33 來看，其因素一和因素二的負荷分別是 0.42684 和 0.73425，都比因素三和因素四的負荷要來的大，可是沒有統計檢定能夠檢測出因素二的負荷使顯著大於因素一的負荷。這種情況通常都是由使用者自由心證，不過我們都會建議在遇到這種情況時，接著去做轉置（rotation）的動作。如果轉置後，X33在因素一的負荷變的更小，而在因素二的負荷卻跟著變大（當然因素三和因素四的負荷不能跟著變大），則這個轉置就有用處。轉置的方法有很多，本例是用Varimax進行轉置。轉置後的 factor pattern 會在稍後敘述。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VARIANCE EXPLAINED BY EACH FACTOR&lt;/span&gt;&lt;br /&gt;&lt;img alt="" class="reflect" height="163" onload="show_notes_initially();" src="http://farm3.static.flickr.com/2239/2497213781_5490252587.jpg?v=0" width="469" /&gt;&lt;br /&gt;&lt;br /&gt;這張表格是表示每個因素所能解釋整體資料變異的程度。數據是從大到小排列，數據越小代表所能解釋整體資料變異的程度越小，因此因素也越不重要。所有數字相加將會等於資料本身的變異數。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;FINAL COMMUNALITY ESTIMATES&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;table border="1" cellpadding="7" cellspacing="1" frame="box" rules="groups"&gt;&lt;thead&gt;&lt;tr&gt;&lt;td align="center" bg="" colspan="5" style="color: #aaaaaa;" valign="bottom"&gt;&lt;span style="color: #0033aa; font-family: Verdana, Helvetica, Helv; font-size: 85%;"&gt;&lt;b&gt;Final Communality Estimates: Total = 4.669974&lt;/b&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt;  &lt;td align="right" bg="" style="color: #aaaaaa;" valign="bottom"&gt;&lt;span style="color: #0033aa; font-family: Verdana, Helvetica, Helv; font-size: 85%;"&gt;&lt;b&gt;Population&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;  &lt;td align="right" bg="" style="color: #aaaaaa;" valign="bottom"&gt;&lt;span style="color: #0033aa; font-family: Verdana, Helvetica, Helv; font-size: 85%;"&gt;&lt;b&gt;School&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;  &lt;td align="right" bg="" style="color: #aaaaaa;" valign="bottom"&gt;&lt;span style="color: #0033aa; font-family: Verdana, Helvetica, Helv; font-size: 85%;"&gt;&lt;b&gt;Employment&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;  &lt;td align="right" bg="" style="color: #aaaaaa;" valign="bottom"&gt;&lt;span style="color: #0033aa; font-family: Verdana, Helvetica, Helv; font-size: 85%;"&gt;&lt;b&gt;Services&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;  &lt;td align="right" bg="" style="color: #aaaaaa;" valign="bottom"&gt;&lt;span style="color: #0033aa; font-family: Verdana, Helvetica, Helv; font-size: 85%;"&gt;&lt;b&gt;HouseValue&lt;/b&gt;&lt;/span&gt;&lt;/td&gt; &lt;/tr&gt;&lt;/thead&gt; &lt;tbody&gt;&lt;tr&gt;  &lt;td align="right" bg="" style="color: #cccccc;"&gt;&lt;span style="color: black; font-family: Verdana, Helvetica, Helv; font-size: 85%;"&gt;0.98782629&lt;/span&gt;&lt;/td&gt;  &lt;td align="right" bg="" style="color: #cccccc;"&gt;&lt;span style="color: black; font-family: Verdana, Helvetica, Helv; font-size: 85%;"&gt;0.88510555&lt;/span&gt;&lt;/td&gt;  &lt;td align="right" bg="" style="color: #cccccc;"&gt;&lt;span style="color: black; font-family: Verdana, Helvetica, Helv; font-size: 85%;"&gt;0.97930583&lt;/span&gt;&lt;/td&gt;  &lt;td align="right" bg="" style="color: #cccccc;"&gt;&lt;span style="color: black; font-family: Verdana, Helvetica, Helv; font-size: 85%;"&gt;0.88023562&lt;/span&gt;&lt;/td&gt;  &lt;td align="right" bg="" style="color: #cccccc;"&gt;&lt;span style="color: black; font-family: Verdana, Helvetica, Helv; font-size: 85%;"&gt;0.93750041&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;span style="color: red; font-weight: bold;"&gt;(註）原文無圖，僅以另一個 SAS 範例內的表格來代替。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;這張表格是上面那個 factor pattern 每一行的平方和，用來表示所有因素可以解釋各個變數變異的程度。所有數據加總便是上面那個 Final Communality Estimates。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;ROTATED FACTOR PATTERN&lt;/span&gt;&lt;br /&gt;&lt;img alt="" class="reflect" height="213" onload="show_notes_initially();" src="http://farm3.static.flickr.com/2302/2498084162_8398acc1ca.jpg?v=0" width="454" /&gt;&lt;br /&gt;&lt;br /&gt;這張表格便是經過轉置過後的 factor pattern。這個 factor pattern 明顯可以看出每個變數只有在其中某一個因素擁有較高的負荷，而且其他因素的負荷都低到接近零。&lt;br /&gt;&lt;br /&gt;不過，在這邊必須特別強調，根據個人經驗，轉置後的 factor pattern 有可能不會像本例那樣容易區分。這有可能是原始資料本來就沒有辦法進行有效的因素分析。通常解決的方法是換別的轉置法來看結果有沒有比較好。如果試過所有的轉置方法後仍沒有達到預期效果，則必須朝增加樣本數或剔除離群值等各方面來下手。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;VARIANCE EXPLAINED BY EACH FACTOR&lt;/span&gt;&lt;br /&gt;&lt;img alt="" class="reflect" height="166" onload="show_notes_initially();" src="http://farm3.static.flickr.com/2055/2497255447_240471c282.jpg?v=0" width="464" /&gt;&lt;br /&gt;&lt;br /&gt;這張表是經過轉置過後每個因素可以解釋整體資料變異程度的新數據。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;FINAL COMMUNALITY ESTIMATES&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;接下來會再看到一張 final communality estimates 的表格。這張表會和前面那張轉置前的 final communality estimates 表格一模一樣，因為轉置並不會對此處的數據產生任何影響。&lt;br /&gt;&lt;br /&gt;以上就是幾個比較重要的因素分析表格解說。基本上大部分的分析到此，把變數歸類命名後就可以
