顯示具有 SAS 標籤的文章。 顯示所有文章
顯示具有 SAS 標籤的文章。 顯示所有文章

2018年7月19日 星期四

Non printable 字元

問題:有特殊 ASCII 字碼存在資料裡面,而且用 print 也看不見,會造成資料 compare 不一致,或者 ods 輸出會出現莫名的換行或符號
解決:
可以先了解有哪些 non-printable 的字碼,可參考
ascii-table

ASCII extended sets characters 有兩種編碼

  • 十進位編碼 0 to 255 (decimal values)
  • 六進位編碼 00 to FF (hexadecimal values)

但一般的 ASCII table (不含extended sets) 是 0 to 127
因此前 33 個 (0 to 32) and character 127 are the non-printable characters

例如: HT ( Horizontal Tabulation )
就是鍵盤上的 tab
用十進位編碼來看是 9 號,可按鍵盤 tab 或者 ALT 數字鍵盤9
用六進位編碼是 09 ,在 SAS 裡用 '09'x

反過來說,要看變項值的 Hexadecimal

data a; a='!'; put a= a hex. ; run; 

第一、要檢查出來

  • 用 sas function 的 NOTPRINT(string <,start>) 如果是 NOTPRINT 回傳 1

依SAS原廠的範例,來看 132, 127254 被 NOTPRINT 定義為 non-printable

data test; 
  do dec=0 to 255;  
    byte=byte(dec);  
    hex=put(dec,hex2.);  
    notprint=notprint(byte);  
    output;  
  end;  

proc print data=test; run;

ref: SAS(R) 9.2 Language Reference: Dictionary, Fourth Edition

  • 用 prxmatch 等搜尋去找。 regular expression 輸入 hexadecimal values 是用 \x00

    data test2; set test;
    byte_re=put(byte, $hex2.);
    kk=prxmatch("/00|01|02|03|04|05|06|07|08|09|0A/", byte_re);
    kk2=find(byte,'00'x);
    kk3=prxmatch("/[^\x00\t\x20-\x7E]/", byte); /自定義查找/
    run;

第二、進行轉換

  • translate 取代1個字,就會留下1個位置,即原本9個不能換成8個。
    更可以1次把多個字作取代 f2_translate=translate(f1,' ','000102030405060708090A'x);

  • tranwrd 類似 translate 但只能1次換1個。

  • transtrn 1次換1個,但可以原本9個換成8個。

    data example;
    length f1 f2_translate f3_tranwrd f4_transtrn $20;
    f1 = cat('Part1','0A'x,'Part2');
    f2_translate = translate(f1,' ','0A'x);
    f3_tranwrd = tranwrd(f1,'0A'x,' ');
    f4_transtrn = transtrn(f1,'0A'x,trimn(''));
    run;

ref: https://programmer-pro.com/special-character-sas-hex/

2018年6月12日 星期二

AUTOEXEC相關

說明:要調整 sas work library 的位置。

改變 work library 的實體位置

  • 直接在電腦左下「程式集」按右鍵修改 SAS 的捷徑,在最尾端加上 -WORK "d:\SAS Temporary Files"
  • 或是去改個人設定檔,先查設定檔在哪
    proc options option=config;run;
    查看 log 應可見 CONFIG=C:\Program Files\SASHome2\SASFoundation\9.4\nls\zt\sasv9.cfg 之類的
    用文字編輯器打開加入以下
    -WORK "d:\SAS Temporary Files"

上面 proc option 的地方,若想做成 macro variable 可用
%put %SYSFUNC( GETOPTION( CONFIG )) ;
想完整列出所有option 用
proc options host;run;

ref: SAS System Options by Category
http://support.sas.com/documentation/cdl/en/hostwin/69955/HTML/default/viewer.htm#n0qn87565ybxoun12srorc6xhpz5.htm


說明:建立一個program,把開啟SAS想要 pre-loading 的相關程式,都納入,方便管理

預載 program

  • 依前項 work 的改法加入

-AUTOEXEC "D:\99_Tool\OneDrive\SAS_self\mysas\AUTOEXEC.SAS"
可以查詢 proc options option=Autoexec; run;

  • 或是所有想載入的所有程式放進 AUTOEXEC.SAS 裡帶入
    %inc "program path" / source2 ;
    上面 source2 會把原本的程式 put 出來

ref: Store and Recall Macros with SAS Macro Libraries


說明:單純預載需要的 macro

預載需要的 macro 有以下方法

  1. 直接用 %inc
  2. 讀取 compiled sas macro
  3. Autocall library

1. 直接用 %inc
若是同 folder 多個以 sas as the file extension 的 program ,可以用

filename files "program folder";  
%include files(name_of_program 1);
%include files(name_of_program 2);

2. 讀取 compiled sas macro

第1.設定 System options to store 以及 Macro options to store ,做出 compiled sas macro , dlcreatedir 可用來建立 folder

options dlcreatedir mstored sasmstore=one;  
libname one "d:\test";  
%Macro DAY1() / store source des="a test for store macro";  
  %put 今日是 &sysdate;  
%Mend DAY1;  
%Macro DAY2() / store source des="a test for store macro";  
  %put 明日是 %sysfunc(intnx(DAY, "&sysdate"d ,1),DATE7.);  
%Mend DAY2;  

第2.下次要用時,也要設定 mstored sasmstore

libname one "d:\test";  
options mstored sasmstore=one;  
%DAY1();  
%DAY2();  

若有多個 lib 可以用

options mstored sasmstore=ALL_LIB;  
libname one "d:\test";  
libname two "d:\test\two";  
libname ALL_LIB (one two);  

第3.可用以下做個確認

proc catalog catalog=one.sasmacr; 
  contents; 
quit;

第4.這類 compiled sas macro ,可以用 %copy 在 log 取得原始碼

options mstored sasmstore=one;  
%copy DAY1 /source;  

3. Autocall library

第1.建立好自己的 macro ,並確認沒有 store source

%Macro DAY1() /  des="a test for store macro";
%put 今日是 &sysdate;
%Mend DAY1;

第2.設定 System option to recall

Options mautosource sasautos=one;  
filename one 'd:\test';   
*;   
%DAY1();    

這兒 macro 的 compile 是發生在第4行時(叫出來用),並存在WORK裡。前項 folder 之下所有 sas file 的 macro 都可直接呼叫。
注意,如果第一次呼叫失敗,修改好程式後,要把 sas 關了再開重跑。
所以若原本有 store source ,那就有額外 option 要處理,我猜測是 mstored sasmstore 以及 sasmstore 的 library 之類的。

第3. 多個位置的應用。用逗號或 space 分開

Options mautosource sasautos= (one,two) ;  
filename one 'd:\test';   
filename two 'd:\test\two';   
*;   
%DAY1();  
*;   
%DAY2();  

整體來說,前3個方法可以用在同1個 program 裡,它們的 search sequence 為

  1. current session 做出來的 (WORK.SASMACR) ,如 %inc 或當下寫的
  2. compiled sas macro
  3. Autocall library
  4. SASHELP

ref: Store and Recall Macros with SAS Macro Libraries


說明:單純預載需要的 format

預載 format

  • 用 %inc 來 reload
  • 不reload的方式

不reload的方式

第1.前次 format 再建立時要指定輸出的 LIBRARY

options dlcreatedir;  
libname one "d:\test";  
PROC FORMAT LIBRARY=one PAGE;
value $sex ‘M’=’Male’
           ‘F’=’Female’;
run;

那個 PAGE 是同時把 format print 出來看

第2.後續要用時

libname one "d:\test";  
proc format library=one; run;  

第3.如果想 check

proc catalog catalog=one.formats;  
  contents;  
quit;
proc format library = one.formats;
  select $sex;
run;

ref: Base SAS® 9.4 Procedures Guide,

2018年6月11日 星期一

建資料或讀資料

說明:資料本身有 contain semicolons

Use the DATALINES4 statement 範例如下

libname two "d:\test\two";  
filename file1 "d:\test\two\DAY1.sas";  
data a ;  
  length code $100.;  
  input code &  $ ;  
  file file1 ;  
  put code $ ;  
datalines4;  
%Macro DAY1() / store source des="a test for store macro";  
  %put 今日是 &sysdate;  
%Mend DAY1;   
;;;;   
run;  

input code & 這裡面的 & 很重要,沒放的話,遇到 space 就不讀了,變成
%Macro
%put
%Mend

ref: Store and Recall Macros with SAS Macro Libraries

2018年2月23日 星期五

SQL應用

問題:要一次把整個 dataset variables 都 rename
說明:
ref: Renaming All Variables in a SAS Data Set Using the Information from PROC SQL's Dictionary Tables

options macrogen mprint mlogic ;
%macro rename(lib,dsn);
  options pageno=1 nodate ;
  proc contents data=&lib..&dsn;
    title "Before Renaming All Variables";
  run;
  proc sql noprint;
    select nvar into :num_vars
    from dictionary.tables
    where libname="&LIB" and memname="&DSN";
    select distinct(name) into :var1-:var%TRIM(%LEFT(&num_vars))
    from dictionary.columns where libname="&LIB" and memname="&DSN";
  quit;

  proc datasets library=&LIB;
    modify  &DSN;
    rename
      %do i=1 %to &num_vars;
      &&var&i=NEWNAME_&&var&i.  %end;
     ;
  quit;
  options pageno=1 nodate;
  proc contents data=&lib..&dsn;
    title "After Renaming All Variables";
  run;
%mend rename;
%rename(WORK,ONE);

以上的用法有2個重點

  • 應用 sas 系統 library SASHELP 的 dictionary tables
  • sql 的 into: 可產生 macro variable
    適用只有1列資料
    例如 select NAME into: source_err from dataset
    若有n列 NAME 希望得到 &source_err 為 n1,n2,n3 就要下 separated by
    例如 select NAME into: source_err separated by ',' from dataset
    若有n列 NAME 希望得到 n 個 macro variable 就如下
    select distinct(name) into :var1-:varN

另外,能用 dictionary tables 的話也可以直接套 call execute() 去改 data set


2018年1月10日 星期三

macro應用

問題:把一個數字套用format容易,但若要用macro facility來處理呢?
說明:
在data step要套用format,直覺想到以下

data a;
  a=1.5;
  b=put(1.5,z5.2);
  put b; 
  put a z5.2 ;
run;

若要把上面put出來的01.50弄成macro variable,需要再套一個call symput指令。
後來摸過%SYSFUNC(),它可以套用dataset的function,就摸索出以下方式

  • %put %SYSFUNC( abs(1.5), z5.2) ;放一個能得到1.5的function,用簡單的abs就好
  • %put %SYSFUNC( putn(1.5,z5.2)) ;

但請注意下列這種無法用

  • %put %SYSFUNC(1.5, z5.2) ; 這個錯在sysfunc沒有指定function,只有給1.5。
  • %put %SYSFUNC( put(1.5,z5.2)) ; 目前不知為何,只知道sysfunc要配putn,putc,inputn,inputc才能用

也可以把要指定的format格式弄成macro variable,方便後續開發運用,如以下的例子

%MACRO now( fmt= DATETIME23.3 ) /DES= 'timestamp';  
  %SYSFUNC( DATETIME(), &fmt )  
%MEND  now ;  
%put %now;

ref: The Big Introduction from the Smallest Macro

這篇有一些東西還沒仔細看,A user-defined format that creates a date-time string that import wizards treat as a value.

PROC FORMAT ; 
   PICTURE  
       u_dt .= ' ' 
       OTHER ='%0Y/%0m/%0d %0H:%0M:%0S'( DATATYPE= DATETIME ); 
RUN ; 

問題:Quotes within Quotes ,有時候會錯亂? 說明:
下面例子呈現data step幾個原則

%let saying = Nevermore; 
data _null_; 
 Nevermore='test';
 
 a1='&saying';
 a1A_1='"&saying"';
 a1A_2='""&saying""';
 a1A_3='"""&saying"""';
 a1B_1='''&saying''';
 a1B_2='''''&saying''''';
 a1B_3='''''''&saying''''''';

 a2="&saying";
 a2A_1="'&saying'";
 a2A_2="''&saying''";
 a2A_3="'''&saying'''";
 a2B_1="""&saying""";
 a2B_2="""""&saying""""";
 a2B_3="""""""&saying""""""";

 put (a:) (=/);
run;

/*Log output 如下*/

a1=&saying
a1A_1="&saying"
a1A_2=""&saying""
a1A_3="""&saying"""
a1B_1='&saying'
a1B_2=''&saying''
a1B_3='''&saying'''
a2=Nevermore
a2A_1='Nevermore'
a2A_2=''Nevermore''
a2A_3='''Nevermore'''
a2B_1="Nevermore"
a2B_2=""Nevermore""
a2B_3="""Nevermore"""
  • 當最外層quotes是single quote,裡面的macro variable 就無法被 resolve,如a1系列。最外層是 double quote ,macro variable 就有可能被resovle,如 a2A_1。
    作者對此的註解是 during the assignment of the variable’s value, the inner single quotes are masked, not seen as parsing characters, so the macro variable resolves.
  • 當最外層quotes與內層quotes是同一種quote,在內層的quote就必須用連續2個quote為單位,此時,會把連續2個quote轉成1個quote,如對照一下 a1A_1 和 a1B_1 ,可發現雖然最後都是1個 single or double quote,但是 a1B_1 的內層是2個 quote ; 比較 a1A_3 a1B_3 就更明顯,a1B_3用了6個。
    要注意,連續2個quote轉成1個quote,此件事發生的時機為: when the parser sees two single (or double) quotes immediately following each other, the parser resolves them into one quote mark after the closing quote has been determined.

下面的例子,就只有 note1 的結果會和 note0 相同。

data _null_; 
 note0 = "The raven sayth: 'Nevermore'"; 
 note1 = "The raven sayth: '&saying'"; 
 note2 = 'The raven sayth: ''&saying'''; 
 note2_1 = 'The raven sayth: ''''&saying'''''; 
 note3 = "The raven sayth: ""&saying"""; 
 put (note:) (=/); 
run;

其他文章裡摘錄的重點

  • 要產生一個title 為 Tom's Truck 可用 title1 "Tom's Truck"; 或者是 title1 'Tom''s Truck';
  • 以前 X command 在 windows 系統下有點麻煩,X command 要用quote, 而 windows 的 path 一定要用 double quote,造成冏境 x 'dir "c:\&temp\*.sas"' ;
    &temp無法被 resolve。
    但現在X command 本身不必用 quote 了,可省下最外層的single quote。
  • DM STATEMENT 一定要有 quote,但 sas 9 開始它 can contain macro variables,並且第1個 quote 是用於把指令轉傳給 Display manager 去處理,因此 dm 'log; file "c:\&temp\logdump1.log"'; Display manager 只收到 log; file "c:\&temp\logdump1.log" , 當然可以 resovle &temp。 另個例子,dm "log; file 'c:\&temp\logdump1.log'"; 稍有不同,因為 file 收到的是 'c:\&temp\logdump1.log' ,第1次沒有轉,但因 file 會把 quote 當成 parsing characters within the command 所以 &temp 又可以轉了。
  • CALL DEFINE STATEMENT在用時,call define(_col_,'style', 'style={flyover="&temp Mean WT"}'); 是可以被 resovle 的。
  • FILENAME STATEMENT
    想要下的指令 filename tmpdat pipe 'dir "c:\&temp\*.sas" /o:n /b'; 但它無法被 resolve。本例的必要條件有2個,1. pipe 之後的 dir... 一定要放在 quotation mark 裡面,2. dir 之後的 path 一定要放在 double quotes 裡面。解法如下...

Using the DATA Step Quote Function
用 sysfunc + Quote Function 來替代條件1,最簡單
filename tmpdat pipe %sysfunc(quote(dir "c:\&temp\*.sas" /o:n /b));

Using Repeated Quote Marks
把外層換成 double quotes ,內層換成 doubled double quotes ,如此 the interior string is marked in a second pass of the parser, after the macro variable has been resolved.
filename tmpdat pipe "dir ""c:\&temp\*.sas"" /o:n /b";

Using Macro Quoting Functions
針對外層的 single quote ,用 macro quoting function 來處理,這有很多種,並且每種用途不太相同,常用的有

  • %STR(%')
  • %BQUOTE()

例如可把原式改為
filename tmpdat pipe %bquote(')dir "c:\&temp\*.sas" %bquote(/o:n /b'); 但這會有錯,因為 single quote 被蓋著,沒有 remove macro quoting ,後面的 dir 就被當成 unquoted option ,不符合條件1
可用 %UNQUOTE() 把整個 dir command 包起來處理
filename tmpdat pipe %Unquote(%bquote(')dir "c:\&temp\*.sas" %bquote(/o:n /b'));
整包送進去 macro facility 處理,最後要離開時會得到'dir "c:\My Loc\*.sas" /o:n /b',這串才能正確接著 filename statement 。具有 %LEFT %TRIM 也可以 remove macro quoting 但應用的時機不同。

ref: Quotes within Quotes When Single (‘) and Double (“) Quotes are not Enough


說明:put出日期有關的資訊

%put &sysdate.;
%put %sysfunc(today(),date9. );

%put &systime. ;
%put %sysfunc(time(),time5. );

%put %sysfunc(datetime(),datetime20. );


說明: CALL EXECUTE made easy for SAS data-driven programming

文中指出,基本的概念是:
As the DATA step iterates, the code is appended to the queue as many times as there are iterations of the DATA step. After the DATA step completes, the code in the queue gets executed in the order of its creation (First In First Out).

有 macro reference 的情況

  • macro reference in double quotes
    they will be resolved by the SAS macro pre-processor during the DATA step compilation. Nothing unusual.

  • macro reference in single quotes
    will be resolved by CALL EXECUTE itself. 同上也是在 pushed out of the DATA step 之前就會完成。
    因為 CALL EXECUTE 具有 macro resolution privilege

  • CALL SYMPUT or SYMPUTX statement (in a DATA step) or an INTO clause (in PROC SQL)
    WARNING: Apparent symbolic reference VARLIST not resolved.
    它們的 macro variable 還沒真的建立之前,就被要求要 resovle
    解決的方式可以直接把整個 statement 用 %nrstr 包起來 ,如:
    call execute('%nrstr(%onetable('!!strip(tname)!!'));');
    強迫推到 queue 裡,之後再 resolve macro
    NOTE: CALL EXECUTE generated line.
    1 + %onetable(ADDRESS);

  • 把 MACRO 的名稱也用 dataset variable 代入
    arg=cats('%nrstr(%', MNAME_variable, '(parameter=', Para, '))' );
    call execute(arg);

ref: https://blogs.sas.com/content/sgf/2017/08/02/call-execute-for-sas-data-driven-programming/

2017年12月1日 星期五

SAS DMKEY

問題:快速清除log與output
解決:使用 DMKEY
ref: Shortcuts to Save Time While Working with SAS
Back Up with Each Submit and Save Your Sanity
SAS Display Manager Commands

先按F9來編輯快速鍵,可以指定 F3 為
log; clear; output; clear; wpgm; submit;

它的意思依序是,跳到log視窗-->清除log-->跳output-->清除output-->跳editor-->執行你的code

當然也可以在program裡面,直接引用,方法如下:
dm "log;clear;out;clear; wpgm; submit;" ;

也有相同做用,只是做用的機制不同。

其他用法,持續補充:

  • include "某program",但要加submit
    include "某program";submit;
  • 在program editor以語法來設定F9裡面的keys
    dm "keydef F6 'log;clear;'";
    dm "keydef 'SHF F12' 'log;cle;output;cle;wpgm;end;wpgm;cle;'";
  • 重覆執行,可以關閉 view table
    dm 'next VIEWTABLE:; end;';
  • save the log to a permanent file, overwriting if necessary
    dm 'log; file "C:\My files\log 1 &sysdate9..log" replace';

SAS HELP有一點點相關的說明:
List of SAS Windows and Window Commands

2014年8月13日 星期三

在字串中找出 substring的位置

 /*
INDEX     (source,  excerpt  )  與條件完全相符的字串去找
FIND        (string,substring<,modifiers> <,startpos> )   與條件完全相符的字串去找,可設'I'忽略大小寫、'T'皆trim,搜尋的起點

INDEXC  (source,  excerpt-1 <,… excerpt-n> ) 以條件內的任一個字母、數字或符號去找
INDEXW (source, excerpt      <,delimiters>   )  以完全相符的單字組去找,預設分隔是space
*/


data test_index;
   a = 'ABC.DEF (X=Y)';
   b = 'X=Y';
  x_ab = index(a,b);     put x_ab= ;
  f_ab_1=find(a,b);      put f_ab_1=;
  f_ab_2=find(a,b,11);      put f_ab_2=; *超過了;
  f_ab_3=find(a,'a',  'I');      put f_ab_3=; *Ignore 大小寫;

length bt $10. ;
bt='X=Y';
  x_abt_1 = index(a, bt);     put x_abt_1= ;*bt尾要補至12位元的空白;
  x_abt_2 = index(a, trim(bt) );     put x_abt_2= ;
  F_abt_1 = find(a, bt, 'T' );     put f_abt_1= ; *兩者皆Trim;
 
c='X=Y=F' ;
  xc_ab_1 = indexc(a, c                       );     put xc_ab_1= ; *找到F;
  xc_ab_2 = indexc(a, c,  'abc.( )'       );     put xc_ab_2= ;

  wc_ab_1 = indexw(a, 'DEF'               );     put wc_ab_1= ;
  wc_ab_2 = indexw(a, 'DEF' ,    '.'      );     put wc_ab_2= ; *尾端有空白;
  wc_ab_3 = indexw(a, 'DEF' ,    '. '      );     put wc_ab_3= ;*逗點接空白;
run;

2014年8月6日 星期三

Delete等於的records,就是保留不等於的records??

希望留下 Sex 和 disnn2 都不為 Missing的部分,但因為在「趕時間」,再轉換IF-then-else 與 SET 裡的 where 時,很直覺地把,IF-then-else 裡的 Delete「等於的」records,改為SET 裡的 Where 保留「不等於」的records
真能如此嗎?

有一組資料如下

Sex disnn2 i
. . 1
. 0 2
. 1 3
1 . 1
1 0 2
1 1 3
2 . 1
2 0 2
2 1 3
目標:留下 Sex 和 disnn2 都不為 Missing的部分
轉譯:
1. Sex 或 disnn2 有Missing 就該刪
【直接轉換 Missing—>不是Missing,刪—>留】
2. Sex不是Missing 或 Disnn2不是Missing就要留
方法
結果
data t1 ; set n_copy;
if sex=. or disnn2 =. 
                  then delete ;
put sex disnn2;
run;
1 0
1 1
2 0
2 1
data test1 ; set n_copy;
if sex^=. or disnn2 ^=.  ;
put sex disnn2;
run;
. 0
. 1
1 .
1 0
1 1
2 .
2 0
2 1
正確的應該再多一道手續,OR 轉為 AND
方法
結果
data t2 ; set n_copy;
if sex^=. and disnn2 ^=.  ;
put sex disnn2;
run;
1 0
1 1
2 0
2 1

2014年7月17日 星期四

以Batch 模式執行SAS的簡便語法


=====================================================
:SAS Batch 檔輸出,這裡可寫說明
:以下設定參數代表的意義
set src=C:\
set code=test_pgm.sas
set log=C:\
set prt=C:\
:以下為呼叫SAS的指令
"C:\Program Files\SASHome\x86\SASFoundation\9.3\sas.exe" -nologo -nosplash -sysin "%src%%code%" -print "%prt%" -log "%log%"
exit
=====================================================

注意事項:

  1. 要使用,請將上面線內的語法貼到notepad裡,並將副檔名存成 batch。
  2. set的部分,src,log,prt分別是在設定sas語法、log、output存放的路徑,而 code則在指定sas語法檔名
  3. 最後一段SAS指令的部分為完整的一列,就是在同一列裡,中間並沒有用Enter換行。而 -sysin 之後立馬要接sas語法檔的詳細路徑。-print 與 -log 若不指定路徑,預設會出現在含有 sas.exe 的資料匣裡。




參考來源:
http://forum.slime.com.tw/thread136868.html
https://communities.sas.com/message/107052

2014年7月10日 星期四

常用的資料整理程式

/*依 ID,Merge 兩個資料檔 ,再依某變項 (cmdecod),保留唯一的值*/

/*方法一*/
DATA t ; merge cm(in=a )  treat ; by subjid  ;  if a ;
run;
proc sort data=T    nodupkey out=t3;
by subjid cmdecod;
run;

/*方法二*/
DATA t ; merge cm(in=a )  treat ; by subjid  ;  if a ;
run;
data t2  ; set t ; by subjid cmdecod;
if first.cmdecod;
run;

/*方法三*/
proc sql
   noprint;
   create table cmtosum as
      select unique (c.cmdecod) as cmdecod, c.subjid, t.trtcd
         from cm as c, treat as t
         where c.subjid = t.subjid
         order by subjid, cmdecod;
quit;


/*依組別(藥名),把資料檔由直向拉成橫向*/

/*方法一*/
Proc sort    data = counts;       by cmdecod trtcd; run;
Data cc2 ; set counts; by cmdecod trtcd;
/*記住3個變項值,不然數據長成一斜線*/
Retain n1-n3;
/*新組別時,先清空數據*/
Array nn {3} n1-n3;
   if first.cmdecod then do i =1 to 3;
nn{i}=.;
   end;
/*指定數值,亦可用Array的方式 nn{trtcd} ,但本例 trtcd有missing,固改用 if then 的方式*/
  if trtcd=. then n1=frequency;
  if trtcd=0 then n2=frequency;
  if trtcd=1 then n3=frequency;
/*輸出每組的最後一筆*/
if last.cmdecod;
run;

/*方法二*/
Proc sort    data = counts;  by cmdecod trtcd; run;
/*利用 Merge ,分組別進行*/
Data cm;
   merge counts(where = (trtcd = 1) rename = (frequency = count1))
         counts(where = (trtcd = 0) rename = (frequency = count2))
         counts(where = (trtcd = .) rename = (frequency = count3))
         end = eof;
      by cmdecod;
run;

/*方法三*/
/*較不建議,若是 ID 的變項值為 missing ,資料會被刪除*/
Proc transpose data=counts prefix=nn out=cc ;
by cmdecod ; id trtcd;
var Frequency;
run;




部分程式引用,Ref:  Jack Shostak, SAS Programming in the Pharmaceutical Industry.

2014年7月9日 星期三

常用的Macro

/*資料筆數存成 Macro Variable*/
/*方法一*/
Proc Sql noprint;
/*Macro Variable N1 */
select Count ( Distinct subjid ) format=3.
into :N1
      from treat
      where trtcd = 1;

 /*Macro Variable N2 */
select count(distinct subjid) format = 3.
      into :n2
      from treat
      where trtcd = 0;
Quit;
%put &N1 &N2;

/*方法二*/
data _null_;
   set treat end = eof;
   **** 分組的 COUNTER 並 retain 住;
   if trtcd = 1 then
      n1 + 1;
   else if trtcd = 0 then
      n2 + 1;
   **** 總 COUNTER.;
   n3 + 1;
   **** 資料最後一列即為所要的數值;
   if eof then
      do;  
         call symput("n1", put(n1,3.)); *用 PUT 數值轉為文字;
         call symput("n2", put(n2,3.));
         call symput("n3", put(n3,3.));
      end;
run;


/*一組變項定義為 Macro Variables*/
/*方法一 用 Arrary*/
DATA A;
Array Vars {8} $18.     (
'Dis_hypertension'
'Dis_DM'
'Dis_hyperlipidemia'
'Dis_stroke'
'dis_asthma'
'Dis_Kidney'
'Dis_HD'
'Dis_osteoporosis'
)  ;
Do i =1 to 8;
Call symput (  'I_num'  , compress(i)  );
Call symput (  'Vv'||compress(i) , Vars{i}  );
End;
run;
%Put   &I_num;
%Put &Vv1 &Vv2  &Vv8 ;

/*方法二 用資料檔處理的方式*/
%LET Text=  那一整群變項;
/*以變項群建立新資料檔(橫向)*/
DATA M_LIST ; input &text;   run;
/*讀 sashelp.Vcolumn取得資料檔訊息(直向)*/
Proc Sql;
Create Table M_LIST2  AS Select Name as MVAR_LIST   From sashelp.Vcolumn
Where libname='WORK' and memname='M_LIST' ;
Quit;
/*以及變項群數目*/
Proc Sql noprint;
Select nvar into :Num  From Sashelp.Vtable
Having libname='WORK' and memname='M_LIST' ;
Quit;
/*巨集變項名稱 Var1,  Var2, ~ VarN */
DATA M_Vars  (Keep= MVAR_PRE);
Pre='Var' ;
do i=1 to &Num;   MVAR_PRE=Pre||compress(i);  output;  End;
run;
/*Macro name 與 變項群 MERGE,Symput為 Macro Variable*/
DATA _NULL_  ; Merge M_vars M_list2 ;   Call Symput ( MVAR_PRE, MVAR_LIST);  run;

2014年4月28日 星期一

運用 Do loop 整理資料

  • /*
    DO index-variable=start TO stop BY increment;
    SAS statements
    END;
    */
    • data test;
      Amount=1000;
      Rate=.075/12;
      do month=1 to 12; /*開始 Iteration */
          Earned+(amount+earned)*rate;
      end;  /*month 跑到 13 才停,因此最後是 13 */
      run;  /*輸出 所有變項值*/
    • do i=1 to Years;
      變項也可以當成 Stop 的依據
    • /*Decrementing DO Loops ,最後到 1 結束*/
    • a Series of Items
      • DO index-variable=
        2,5,9,13,27;
      • DO index-variable=
        'MON','TUE','WED','THR','FRI';
      • DO index-variable=
        Spring, Summer, Fall , Winter;  變項值

/*Nesting DO Loops*/
  • data work.earn;
    do year=1 to 20; /*每年增資*/
        Capital+2000;
        do month=1 to 12; /*每月複利*/
            Interest=capital*(.012/12);
            capital+interest;
        end;
    end;
    run;

/*Conditionally Executing DO Loops*/
  • /* DO UNTIL(expression); */
    在程式底才判斷,因此statement一定至少執行一次
    • data invest;
          do until (Capital>=9000);
              capital+1000;
              capital+capital*.10;
              Year+1;
              output;
          end;
      run;
      proc print noobs;run;
    • data invest;
          do Year=1 to 10  until (Capital>=20000);
              capital+1000;
              capital+capital*.10;
              output;
          end;
      if year=11 then year=10;
      /*index-variable 跑足就會多 1  */
      run;
      proc print noobs;run;
    • data invest;         /*依 condition 提早結束*/
          do Year=1 to 10  until (Capital>=20000);
              capital+5000;
              capital+capital*.10;
              output;
          end;
          if year=11 then year=10;
      run;
      proc print noobs;run;
  • /* DO WHILE(expression); */
    在程式初就判斷,因此statement可能完全不執行
    • data invest;
          do while (Capital>=9000);
      *不會執行,因為初始是 0 ,要 >= 9000 才會動;
              capital+1000;
              capital+capital*.10;
              Year+1;
              output;
          end;
      run;

系統抽樣 搭配 Point-Output-Stop
  • DATA TT;
        Do sample=1 to 206 by 5 ;
            SET SASUSER.frequentflyers  point=sample;
            Output;
        End;
                    Stop;
    RUN;

2014年4月27日 星期日

建構變項—SAS Funtion

function-name(argument-1<,argument-n>);

  • mean(x1,x2,x3)
  • mean(of x1-x3)
    • mean(x1-x3)變成 x1-x3 的平均
  • mean(of narray{*})

 

文字與數值之間轉換

  • 多數的function使用時,系統可自行轉換,建立一個暫時變項,但遇到 $ , 等情況會失效
  • Input 可 Character-to-Numeric Conversion
    • INPUT(source, informat)
      New=Input ( ID ,  4. )
  • Put 可 Numeric-to-Character Conversion
    • PUT (source,format)
      • Fee_lv2=put( fee, 3.);
      • Fee_lv2=put( fee, fee.);
      • Fee_lv=input(  put( fee, fee.),  $10. );

========================
與 Date Value 有關的 function
========================

  • now1=mdy(4,27,2014); format now1 date9.;
    now2='27Apr2014'd;    format now2 date9.;
  • now3=today(); format now3 mmddyy10.;
    now4=date(); format now4 mmddyy8.;
  • nowtime=time(); format nowtime TIME8.;
    nowtime2='27Apr2014:15:35:00'dt; 
    format nowtime2 datetime.;

now1=
mdy(4,27,2014);

不正確的用法
mdy(Apr,27,2014);
mdy(‘Apr’,27,2014);

format now1 date9.;

27APR2014

now2=
'27Apr2014'd;

format now2 date7.;

27APR14

now3=today();




now4=date();

format now3 mmddyy10.;

format now4 mmddyy8.;

04/27/2014

04/27/14

nowtime=time();

format nowtime TIME8.;

15:35:17

nowtime2=
'27Apr2014:15:35:00'dt;

format nowtime2 datetime.;

27APR14:15:35:00

 

  • day=day(now1); /*27APR2014*/
    27
    month=month(now1);
    4
    year=year(now1);
    2014
  • qtr=qtr(now1);
    2
  • weekday=weekday(now1);
    1 /*日一二三四五六*/

 

  • 時間間隔
    INTCK('interval',from,to) 
    INTCK ( 'day' , '31dec2013'd , '01jan2014'd );
    常用於算周年
    • Day  經過幾個日數----------  1日
    • Week 經過幾個Sunday ----- 0個 Sunday
      • from為周日,to為周一,則0個Sunday
      • from為周六,to為周日,則1個Sunday
    • Month 經過幾個某月1日------1個某月1日
    • Year 經過幾個1月1日---------1個1月1日
      • Years = intck ( ‘year’, First_meet, Today() );

 

    • 時間推移
      INTNX('interval',startfrom,
                             increment<,'alignment'>)
      'alignment' 可為 b m e s,用於 month較易懂,其他interval 的不是很懂
      • Month
        • MonthX=intnx ('month','27apr2014'd, 5 , 'alignment' );
          推 5個月,b m e s的結果依序為
          01SEP2014月初
          15SEP2014月中
          30SEP2014月尾
          27SEP2014同日

 

日期之差

  • DATDIF(start_date,end_date,basis)
    • basis 有
      '30/360'   'ACT/ACT' 
  • YRDIF(start_date,end_date,basis)
    • basis 有
      '30/360'   'ACT/ACT'   'ACT/360'   'ACT/365'

 

=========================
與 文字 有關的 function
========================

傳出變項裡的字串,或者取代字串

  • SCAN(argument,n<,delimiters>)
    • 依 delimiter 區分,來選字第n個字,leading delimiters have no effect,預設的delimiter 有
      blank . < ( + | & ! $ * ) ; ^ - / , %
    • SCAN產生的新變項預設為 $200. 
      最好先設定 LENGTH
    • 新變項=scan (Name , 2,  ' -'  );
      delimiter 是 空白 與 -
    • 新變項=scan (Name , 2,  '-'  );
      delimiter 只有 -  
  • SUBSTR (argument, position <,n>)
    n表示連著取n個字元,不指定 n 就是position之後全要了。數值變項,請先Put成文字變項。
    • 依 position 來選字
      • First=Substr ( name , 1, 5) ;
    • 依 position 來取代文字,類似 TRANWRD
      • Substr ( name , 1, 5  ) ='First';
      • 有意義一點的作法是
        IF Substr ( name , 1, 1  ) = 'M'
             then Substr ( name , 1, 2  ) ='W%';
        注意新增的文字的 n 要對,本例為2個字元。
  • TRANWRD(source,target,replacement)
    搜查特定文字,並取代該文字。記得設定 length
    • Nname=TRANWRD ( name , 'M' ,  'W%' );

 

刪除多餘空白

  • TRIM(argument)
    刪除trailing blanks,用於組合文字
    新變項的length有可能多於實際文字量,因此還是會有trailing blanks
    • new=trim(Lastname) || ', ' || trim(location) || ', ' || trim(phone) ;
  • CATX(separator,string-1 <,...string-n>)
    • 用於連結字串,移除 leading and trailing blanks, 插入分隔符號( separator)。
      相當於TRIM and LEFT 的組合
    • new2=catx ( ', ' , Lastname, location, phone);

 

找字串的Position

  • INDEX(source,excerpt)
    搜尋特定字串(case sensitive),並回傳找到第一個的位置,若找無就是0
    • n1=INDEX (Lastname,'LA') ;
  • FIND(string,substring<,modifiers><,startpos> )
    用途與INDEX相近
    • n2=Find (Lastname,'LA') ;

 

大小寫文字的轉換

    • UPCASE(argument) 全大寫
    • LOWCASE(argument) 全小寫
    • PROPCASE(argument<,delimiter(s)>) 依分隔點區分,首字元大寫

 

========================
與 數字 有關的 function
========================

INT(argument) 取整數部分

ROUND(argument,round-off-unit) 類似四捨五入

  • d1 = round(1234.56789,100)     - 1200;
    d2 = round(1234.56789,10)      - 1230;
    d3 = round(1234.56789,1)       - 1235;
    d4 = round(1234.56789,.1)      - 1234.6;
    d5 = round(1234.56789,.01)     - 1234.57;
    d6 = round(1234.56789,.001)    - 1234.568; 
    d7 = round(1234.56789,.0001)   - 1234.5679;
    d8 = round(1234.56789,.00001)  - 1234.56789;

2014年4月25日 星期五

SAS 資料處理技巧1

變項Keep 與 Drop
  • data work (drop=age group);
  • set clinic    (keep=age group BMI );
    • 讀檔時 (SET) 只進 age group BMI ,新資檔(DATA) 刪除 age group,最後輸出只有BMI


FIRST.變項 與 LAST.變項
  • 一定要先Proc Sort
  • Proc Sort 之後,遇到 Data ; by X Y;,在program data vector裡會自動建立FIRST.變項 與 LAST.變項,First.X Last.X First.Y Last.Y,可參考下表
Department FIRST.Department LAST.Department
A 1 0
A 0 0
A 0 1
B 1 0
B 0 1
C 1 1

範例如下:
data salaries2 ; set salaries ;
by Department;
/*第一筆設定為0*/ 
if first.Department then Payroll=0;
/*累加*/
      payroll+yearly;
/*是最後一筆再輸出*/
if last.Department;
run;

Using Direct Access:指定讀特定一筆數據,並輸出。(Point-Output-Stop)
  • Point 與 OUTPUT 聯用。通常用於取得Random sample。
    • data test;
          obsnum=3; /*自定變項與值*/
          set salaries  point=obsnum;  /* 被 point 變項就消失 */
          N=1;
          OUTPUT;  /*強制輸出到實體資料檔*/
          Stop;     /*找到某筆數據後,停止 iteration,不
                          必等到 Mark of the end */
      K=1;   /*因為在OUTPUT之後,數值不會被輸出*/
      run;

資料列末端的技巧 ( End=var )
  • 用途:輸出資料檔的最未一筆總計。(似乎用Last.即可)
  • End=var,建立暫時變項 var ,若 SET statemnet 讀到了 end of file,var就為1
  • END= 不與 POINT= 一起用
    • set sasuser.stress2(keep=timemin timesec) end=last;
    • .........
    • if last; /* 當 last = 1 才輸出 */

SAS DATA SET 的處理流程,與讀 Raw data file 差不多,主要差異如下:
  • Execution Phase:第一筆資料輸出到新資料檔後,會在 Program Data Vector裡 Retain 保留 SET statement 已讀入的 (如:第一筆資料) 與 sum statement 所產生的變項,一直到再執行 SET statement,讀入第二筆數據
    • 但讀 RAW DATA FILE 則是重設為 MISSING,除非是RETAIN, SUM STATEMENT變項, 暫時的ARRARY,FILE或INFILE的OPTION建立的變項,自動變項

2014年4月24日 星期四

建構變項

累積加總
  • data stress; set sasuser.stress2;
    TotalTime=(timemin*60)+timesec;
    SumSec+totaltime;
    run;
    • SumSec 在 + 的左邊,它的起啟值就是 0 ,而非 missing
    • 其結果類似以下右欄
      1  1
      1  2
      1  3
      1  4

RETAIN variable <initial;-value>;
  • 主要特色
    • data complie 的指令,無法作用於 set, merge的變項
    • 指定變項初始值為任何文字或數字,避免變項在每次iteration被重置
  • SumSec 由10000 起算而非 0
    retain SumSec 10000;
    sumsec+totaltime;

IF-THEN/ELSE 的指令,會比 很多的 IF-THEN 更省資源,或者改用 SELECT-WHEN 的語法
  • SELECT (select-expression);
    WHEN ( condition,…, condition ) Execute-statement;
    WHEN ( condition,…, condition ) Execute-statement;
    OTHERWISE <Execute-statement>;
    END;
    • select (TimeMin) ;
          when ( '13' ) TimeGroup='Lower';
      雖然TimeMine是數值,也一定要 “”
    • OTHERWISE  一要有,否則有
      ERROR: Unsatisfied WHEN clause


變項特性的設定
  • The length of a new variable is determined by the first reference in the DATA step。若要用LENGTH 來指定變項長度,應放在最前端的程式。
    • length Test $ 10;
  • LABEL var= ‘Description’;
  • FORMAT var formats;

DROP and KEEP 變項
  • 用在 Data 、set 、Proc data= 的 Option
    • (DROP=variable(s))
      (KEEP=variable(s))
      • data work (drop=age group);
      • set clinic    (keep=age group BMI );
      • 讀檔時 (SET) 只進 age group BMI ,新資檔(DATA) 刪除 age group,最後輸出只有BMI
  • 在 DATA step 的statement
    • DROP variable(s) ;
      KEEP variable(s);

2014年4月23日 星期三

準備Base programming 筆記_HTML Output

ODS 有很多 Destinations,其中常用的是 LISTING, HTML, OUTPUT, PDF 等。

輸出 ODS HTML
  1. ODS HTML BODY="file-specification"   STYLE=style-name;               
                    /* BODY 可用 FILE*/
  2. ODS HTML BODY=fileref;  * 特定檔案才可;
  3. ODS HTML PATH=mine.mycat BODY=name.HTML;
    • procedure 1 ~ procedure N
  • ODS HTML CLOSE;


多張表,製作 Table of Contents
  • 以 frame.html 為主,裡頭紀錄 content 與 body的路徑,因此有相對、絕對路徑兩種設定方式,讀檔時按 frame.html即可。
  • 相對路徑的寫法 1  (檔案一起搬到別的資料匣也能正確開啟)
    • ods html   
    • body="z:\DATA\data.html"       (url='data.html') 
    • contents="z:\DATA\toc.html"   (url='toc.html')
    • frame="z:\DATA\frame.html";
  • 相對路徑的寫法 2
    • ods html   path="z:\DATA\"  (url=none)
    • body="data.html"    
    • contents="toc.html" 
    • frame="frame.html";
  • 絕對路徑的寫法
    •  (URL='某個真的 url') 
    • 需再將三個檔案部署到正確的網址

2014年4月22日 星期二

準備Base programming 筆記_簡單的分析統計

PROC MEANS <DATA=SAS-data-set>
<statistic-keyword(s)> <option(s)>;
  • 預設會出報表,但可用NOPRINT 不出報表。
  • 報表的小數位
    • proc means data=sasuser.diabetes min max maxdec=1;
      run;
  • Group Processing,Class 與 BY
    • Class 不必先 sort,報表集合為一張
    • By 必先sort,報表分成N張,但總分層較多時,速度較快
  • OUTPUT OUT=SAS-data-set STATISTIC=new_variable(s);
    • var arterial heart cardiac urinary;
      output out=test mean=Ave_1 Ave_2 ;
      • Ave_1 Ave_2 是依VAR的順序,先到先贏,即arterial heart ,而 cardiac urinary 就沒有輸出。
      • STATISTIC=new_variable(s) 可指定不只一組,不指定就是全部變項的全部統計值都輸出。

PROC SUMMARY
  • 大致用法同上,但預設無報表,要用 PRINT (option)才會出表

PROC FREQ
  • / nofreq nopercent norow nocol missing
  • tables sex*weight*height;
    N way table 會先以 sex進行分層,輸出weight*height的表(frequency, percent, row pct, column pct)
  • tables sex*weight*height / list;
    只輸出 frequency,與其相關的percent, cumulative frequency, cumulative percent
  • tables sex*weight*height / crosslist;
    以List的方式,輸出與N way table相同的表,支援用 Proc template進行修改。

2014年4月21日 星期一

數字轉文字並保留小數位數

/*數字轉文字並保留小數位數 Converting a Numeric Variable to a Character Variable*/
data tt;
b=131.19;
b1=compress(b);
b2=put(b,6.2);
a=130.00;
a1=compress(a);
a2=put(a,6.2);
run;
image
之前都用 compress的方式,但最大問題是剛好整數(130.00)會變成130!有想過以 length 取得長度,但數值的長度與是否為整數無關,一開始指定best12. ,該欄下的所有 length 就都是12。
因此改用 put 最方便,PUT always return a character
其中參數6.2是指先保留6個位元,其中含兩位小數,輸出後的文字總長即為6位元。

2014年4月20日 星期日

Reading Raw Data File

指定外部資料檔的位置,與讀檔
  • SAS系統檔,Libname
    libname NHIS 'c:\report';
  • 其他檔案,Filename
    • 單檔 filename nhis "z:\DATA\admit.txt";
      nhis 代表實體檔案
      • DATA work.admit;
            infile nhis delimiter='09'x MISSOVER DSD  firstobs=2;
            input ....;
      • filename nhis clear;
    • 多檔 Filename NHIS2 'c:\report\';
      • DATA work.admit;
            infile nhis2(admit.txt) delimiter='09'x MISSOVER DSD  firstobs=2;
            input...;
    • 直接呼叫檔案
      • DATA work.admit;
            infile "z:\DATA\admit.txt" delimiter='09'x MISSOVER DSD  firstobs=2;

Column Input
  • INPUT variable <$> startcol-endcol . . .;
    適用於 Fixed-field Records
    • 條件:固定的n個變項,變項為標準的數字與文字,原始資料要按位子對齊好
    • 指定變項的起點與終點,因此,變項間的順序就不重要了。資料欄位也可被重覆讀取。
  • 用 Infile 
    • libname libref 'SAS-data-library';
      filename nhis "z:\DATA\admit.txt";
    • DATA work.admit;
    • infile "z:\DATA\admit.txt" obs=10 ;
    • input ID 1-10 Name $ 20-30 Sex 15;
    • run;
  • 用 Datalines (Reading Instream Data )
    • DATA work.admit;
    • input ID 1-10 Name $ 20-35 Sex $ 15;
    • DATALINES;
    • 2458          F    Murray, W
    • 2462          M    Almers, C
    • ;
    • 不必再 run
  • Datalines 換行讀取  (僅讀入部分變項)
    • data coat;
    • input category high1-high3 / low1-low3;
    • datalines;
    • 5555 9 8 7 6
    • 4 3 2 1
    • 8888 21 12 34 64
    • 13 14 15 16
    • ;
  • DATA ERROR訊息,不會中斷DATA STEP。

Formatted Input
  • 適用於 Fixed-field Records standard and nonstandard data
    @ n 與 + n  可以交互使用
  • INPUT @n Var-name Informat. ;
    n表示第幾個欄位(position)起
    • input @15 ID $5. @1 LastName $10. @30 Payment 8.
  • INPUT +n Var-name Informat.;
    用+n 要加到變項的起點,要注要讀完一個變項後,column pointer 會自動往後一位,LastName 在第10位End,到第15位的ID時,要 +4 就可以了。
    往回讀資料,要用  + (-n)
    • input LastName $10. +4 ID $5.  +10 Payment 8.
  • Informat 告知 SAS 原始資料的儲存方式,才能順利讀取檔案,但是在 PDV裡,變項不自動以 informat指定格式儲存。
    • PERCENTw.d      w為總長,d為小數位數
    • COMMAw.d
      • 適用在數值卻有  , $ %   等符號 
    • date7.         date9.
      mmddyy8.   mmddyy10.
      datetime.
      TIME8. 

Record Formats
Raw data 儲存observation的方式
  • Fixed-Length Records
    每筆的 end of record marker 都在同一位置 
  • Variable-Length Records
    不固定的 end of record marker
    • 有fixed-field data的,某區段都固定給某變項,例如欄位長固定( 4.)
      PAD option
      • 有些筆數的值較短(ex: 10,還有兩個位元),會提早遇到end of record,避免電腦傻傻執意要換到下列補足長度(另2位元)
      • 本欄為 missing

Free-Format Data
欄位的 begin 與 end 沒有完全固定position
  • List Input與Delimiter(DLM)
    raw data file的限制:數字與文字都只能 8位元,超過會 truncated;標準變項;以空白或符號分隔變項;文字或數字裡不能有該符號;missing要用 . 或其他文字表示。
    • Infile "z:\DATA\admit.txt" DLM=’符號’
      Input
      var1 var2
      var3-var6 
      (var7-var10) ($)   ….. varN ;
  • 解決方案
    • MISSOVER option:某列尾端有Missing value
    • DSD option:某列開頭、列中有missing value
      • 預設Delimiter 為 , 
      • ,, 表示 missing
      • 值的引號”會被移除
    • Length statement:文字大於8位元
      • Infile ….; Length Var $20. ; input Id Var …..;
        注意此時Input裡的 Var 不必再加 $ 了。但因為先以 Length設定,Var是第一個變項,而非 Id
    • & 文字值含有空白(不連續),如 Taipei city
      • 其後的Delimiter 要改為兩個空白「  」
      • Length City $ 12; Input …  city & ;
        或 Input … city & $12. ;
    • : 數值或文字長度超過8,且不內含空白
      • 文字時,需設 Length
      • 數值時,不需設 Length,用 Comma. 即可
        • input name: $13.  pop: Comma.  ;
          datalines;
          TaipeiCity 100,000,000
          KeelungCity 100000000
          ;

讀 Excel 檔
  • libname libref 'location-of-Excel-workbook' <options>;
    • libname readxls "Z:\DATA\finance.xls";
    • proc contents data=readxls._all_ ; run; *可直接知道sheet細詳資訊;
    • data finance ;  set   READXLS."'1$'"n  ;run;
    • libname readxls clear; *停止連結 xls 檔;
  • 可用的 option 
    • DBMAX_TEXT=n
      單欄文字長度
    • GETNAMES=YES|NO
      第一列為變項名
    • MIXED=YES|NO
      所有資料轉成文字,預設是no
    • SCANTEXT=YES|NO
      以最長的列寬為預設列寬。
    • SCANTIME=YES|NO
      no 只有time 的變項 也用 date9.
      yes 改用 time8.
    • USEDATE=YES|NO
      yes date/time 的變項 用 date9.no  改用 datetime.

標準的與非標準的變項
  • 數值型
    • 標準的: 羅馬數字、小數數字、正負號數字、科學記號(ex: E-notation)
    • 非標準的:內含(%$,)、日期時間、分數、二進位、十六進位

建構變項的OPERATOR
  • arithmetic operator,依優先順序
    • -(負號)、**(指數)
    • 乘除
    • 加減
  • Comparison Operators
    • > < = ^= >= <=
    • in ( 1 ,2 ,3) 或  in ( 1 2 3) 
    • in ( "LINK" , "Value" )
  • Logical Operators
    • AND & ,  OR  | ,  NOT ^ 
      • 用 OR的注意事項
        • if TimeMin<12 or 14; 
          • OR 前後要分開看, 2 一定是 true,本條件形同虛設
        • if TimeMin<12 or TimeMin=14;
          • 會輸出 <12 還有 =14 的。

新增日期、時間變項 (待續補充)
  • 日期(兩位年從1920起至2019)
    •                   Date='01jan2014'd;              Date='01jan14'd;
    • 以上可選  attrib date format=date9.; 或 attrib date format=date7.;
    • 或            attrib date format=mmddyy10.;   attrib date format=mmddyy8.;
                      01/01/2014                                 01/01/14
  • 時間 
    • Time='21:00't;
    • attrib TIME format=TIME8.;  21時0分0秒
  • Datetime
    • DateTime='01jan2014:21:00:00'dt;
    • attrib DateTime format=datetime.;

輸出Raw Data File
  • 把sas dataset 轉成 依 column 對齊的 txt檔
    • data _null_;
    • set sasuser.admit;
    • file "z:\admit_column.txt"; *沒有 file 就 put 到 log裡;
    • Put
    •   ID  4.
    •   @6 Name  15.    /* 用 @ 位置  VAR  長度  比較不會出錯  */
    •   @22 Sex  1.
    • run;
  • Sas dataset 轉成 Free-Format raw data;
    • PUT variable <: format>;
      • file …;  Put ID  Fee: 7.2 ;
    • DLM=’’
      • file … DLM=’,’;
    • DSD
      • file … DSD;
      • 預設Delimiter 為 ,
      • 有 , 的數值,會包在一組雙引號中
    • PROC EXPORT DATA=SAS-data-set;
      OUTFILE=filename <DELIMITER='delimiter'>;
      RUN;
  • 存到 xls 檔的 sheet
    • libname readxls "Z:\DATA\finance.xls";
    • data readxls.admit;
    • set sasuser.admit; *不必用 'admit$'n ;
    • run;

運用filename, PIPE, infile 與 windows語法互動, 參考Back Up with Each Submit and Save Your Sanity
    • filename backup pipe 'dir C:\backup /t:w /a:-d /OD';
    • data backup;
    •  infile backup missover pad length=len;
    •  input @01 line $varying200. len; 
    • run; 
    •  

    2014年3月24日 星期一

    SAS 9.3 64位元與 Win 7 64位元,無法讀取匯入 Excel(xls, xlsx)或 Access (mdb, accdb)


    問題描述:
    作業系統環境是 Win7 64 與 SAS 9.3 64位元,Office 為 2003 版的,使用以下方式讀取或匯出 Excel 或Access的檔案
    • Import Wizard
    • Proc import 或Proc export
      • PROC IMPORT DBMS=EXCEL 
                    DATAFILE= "\directory\filename.xls" 
                   OUT= WORK.cdc REPLACE;
             SHEET="Sheet1";
             GETNAMES=YES;
             MIXED=NO;
             SCANTEXT=YES;
             USEDATE=YES;
             SCANTIME=YES;
        RUN;
    • Libname
      • libname myref  "\directory\filename.xls";
    會失敗,而Log檔訊息為
    ERROR: Connect: 類別未登錄
    ERROR: Error in the LIBNAME statement.
    ERROR: Error trying to establish connection: Unable to create Data Source.: Class not registered
    ERROR: Error in the LIBNAME statement.
    此狀況常見於剛換系統,以前寫的sas碼都變得無法執行。

    解決方式:
    • 換回 SAS 9.3 的 32位版,但工程較大 ,但也一樣要安裝SAS PC Files Server
    • 使用SAS PC 檔案伺服器(SAS PC Files Server)來讀取檔案,建議SAS 64位元用戶一定要裝。
    1. 安裝方式請參考 SAS® 9.3 FOUNDATION for Windows 安裝導引
    2. 安裝過程中,一定要選擇讓 SAS PC Files Server隨windosw 自行啟動,否則後續每次叫檔案要自行到「所有程式」手動啟動
    3. 讀檔或匯出檔案的程式碼要稍微改如下
    4. libname myref pcfiles server="localhost" 
      port=9621
      path="\directory\filename.xls";
      proc import dbms=excelcs
            datafile='\directory\filename.xls' 
            out=sas-data-output-filename replace;
         sheet='sheet-name';
         server="localhost";
         port=9621 ;
      run;
      如此,只要更動少部分的程式即可!
        如果有進一步問題,可參考:http://support.sas.com/kb/33/228.html
      或是 http://support.sas.com/kb/43/802.html