*===== 6章:SASマクロ ;

*--- 6.1 ;
*--- Example 1 ;
options mprint ;
data DT ;
   input X Y ;
cards;
10 20
12 40
15 32
;
run ;

*--- SASマクロの定義 ;
%macro PRINT_DS ;
   proc print data=DT ;
   run ;
%mend PRINT_DS ;

*--- SASマクロの定実行 ;
%PRINT_DS ;

*--- 6.2 ;
*--- マクロ変数 ;
options mprint symbolgen ;
%macro PRINT_DS2(DSN) ;
   proc print data=&DSN. ;
   run ;
%mend PRINT_DS2 ;

%PRINT_DS2(DT) ;

*--- 複数のマクロ変数 ;
options mprint symbolgen ;
data DT1 ;
   input TREAT $ N ;
cards;
薬剤A 15
薬剤B 15
;
run ;

data DT2 ;
   input GENDER $ N ;
cards;
男性 10
女性 20
;
run ;

%macro PRINT_DS3(DSN1,DSN2) ;
   proc print data=&DSN1. ; run ;
   proc print data=&DSN2. ; run ;
%mend PRINT_DS3 ;

%PRINT_DS3(DT1,DT2) ;

%PRINT_DS3(DSN1=DT1,DSN2=DT2) ;

*--- 初期値の指定 ;
%macro PRINT_DS3(DSN1=DT1,DSN2=DT2) ;
   proc print data=&DSN1. ; run ;
   proc print data=&DSN2. ; run ;
%mend PRINT_DS3 ;

%PRINT_DS3 ;

*--- %let,%put ;
*--- 1 ;
%let VARIABLE = WEIGHT ;
%put マクロ変数VARIABLEに格納されている値は &VARIABLE です。 ;

*--- 2 ;
%let VARIABLE = WEIGHT ;
data &VARIABLE ;
   ID  = 1 ;
   WGT = 70 ;
run ;

*--- 3 ;
%let X1 = 2 ;
%let X2 = 3 ;
%let X3 = %eval(&X1 + &X2) ;
%put *** &X1 + &X2 = &X3 *** ;

*-- call symput ;
data _null_ ;
   call symput('MV1','SYMPUT') ; *--- 文字列をそのまま格納 ;
   X1 = 'SYMPUT2' ;
   call symput('MV2',X1) ; *--- X1の値を格納 ;
   X2 = 10 ;
   call symput('MV3',compress(put(X2,best.))) ; *--- X2を文字列に変換して格納 ;
   X3 = '4' ;
   call symput('MV'||X3,'TEST') ; *--- マクロ変数MV4に文字列を格納 ;
run ;

*--- マクロ変数の値を確認 ;
%put MV1: &MV1 MV2: &MV2 MV3: &MV3 MV4: &MV4 ;

*--- symget関数 ;
*--- 使用例1 ;
%let A = TEST ;
data _SYMGET ;
   VALUE = symget('A') ;
run ;
proc print data=_SYMGET ; run ;

*--- 使用例2 ;
%let A1 = VAL1 ;
%let A2 = VAL2 ;

data VAL ;
   input X $ ;
cards;
A1
A2
;
run ;

data _SYMGET2 ;
   set VAL ;
   VALUE = symget(X) ;
run ;

proc print data=_SYMGET2 ; run ;

*--- 自動マクロ変数 ;
data _SYS ;
   x=1 ;
run ;

%put SYSDATE:  &SYSDATE ;
%put SYSDATE9: &SYSDATE9 ;
%put SYSDSN:   &SYSDSN ;
%put SYSERR:   &SYSERR ;
%put SYSLAST:  &SYSLAST ;
%put SYSSCPL:  &SYSSCPL ;
%put SYSVER:   &SYSVER ;

*--- globalとlocal ;
%global X ;

%macro LG ;
   %let X = GLOBAL ;

   %local Y ;
   %let Y = LOCAL ;
   %put Y: &Y ;
%mend LG ;
%LG ;
%put X: &X ;

*--- sqlプロシジャintoステートメント ;
*--- 1 ;
data INTO1 ;
   X = "INTO" ;
run ;

proc sql noprint ;
   select X into: _X1 from INTO1 ;
quit ;

%put _X: &_X1 ;

*--- 2 ;
data INTO2 ;
   input X $ @@ ;
cards;
a b c
;
run ;

proc sql noprint ;
   select X into: _X2 separated by ',' from INTO2 ;
quit ;

%put _X2: &_X2 ;

*--- 3 ;
data INTO3 ;
   input Y Z $ ;
cards;
1 a
2 b
3 c
;
run ;

proc sql noprint ;
   select Y,Z into: _Y separated by "," , : _Z separated by "|"
      from INTO3 ;
quit ;

%put &_Y ;
%put &_Z ;

*--- 4 ;
proc sql noprint ;
   select catx('=',compress(put(Y,best.)),quote(compress(Z))) into: FMT separated by " "
      from INTO3 ;
quit ;

%put FMT: &FMT ;

proc format ;
   value ABCFMT &FMT ;
run ;

*--- 6.3 %ifステートメント ;
*--- 1 ;
options mprint symbolgen mlogic ;
%macro PRINT_IF(FLAG=) ;
   proc print data=%if       &FLAG=1 %then DT1 ;
                   %else %if &FLAG=2 %then DT2 ;;
   run ;
%mend PRINT_IF ;

%PRINT_IF(FLAG=1) ;
%PRINT_IF(FLAG=2) ;

*--- 2 ;
options mprint symbolgen mlogic ;
data BP ;
   input ID DBP SBP ;
cards;
1  80 123
2  90 142
3  83 115
4  77 106
5  95 150
6  85 132
7  65 105
8  72 127
9  88 140
10 98 155
;
run ;

%macro MEANS_PRINT(FLAG=) ;
   %if &FLAG = 1 %then %do ;
      proc means data=BP ; var DBP SBP ; run ;
   %end ;
   %if &FLAG = 2 %then %do ;
      proc print data=BP ; run ;
   %end ;
%mend MEANS_PRINT ;

%MEANS_PRINT(FLAG=1) ;
%MEANS_PRINT(FLAG=2) ;

*--- 6.4 %doステートメント ;
*--- %do - %end ;
data DO1 ;
   input AREA $ AIRTEMP @@ ;
cards;
東京都 21 大阪府 23 沖縄県 28
;
run ;
data DO2 ;
   input AREA $ HUMIDITY @@ ;
cards;
東京都 41 大阪府 58 沖縄県 84
;
run ;
data DO3 ;
   input AREA $ POP @@ ;
cards;
東京都 20 大阪府 50 沖縄県 90
;
run ;

%macro DO_PRINT ;
   %do I =1 %to 3 %by 1 ;
      proc print data=DO&I ; run ;
   %end ;
%mend DO_PRINT ;

%DO_PRINT ;

*--- %do %while - %end ;
%macro DO_WHILE ;
   %let I = 1 ;
   %do %while(&I <= 3) ;
      proc print data=DO&I ; run ;
      %let I = %eval(&I + 1) ;
   %end ;
%mend DO_WHILE ;

%DO_WHILE ;

*--- %do %until - %end ;
%macro DO_UNTIL ;
   %let I = 1 ;
   %do %until(&I > 3) ;
      proc print data=DO&I ; run ;
      %let I = %eval(&I + 1) ;
   %end ;
%mend DO_UNTIL ;

%DO_UNTIL ;

*--- 6.5 引用符 ;
%let A = Variable ;
data QUOTE ;
   X1='単引用符: &A' ;
   X2="二重引用符: &A" ;
run ;

title1 '単引用符: &A' ;
title2 "二重引用符: &A" ;
proc print data=QUOTE ; run ;
title ;

*--- 6.6 マクロ関数 ;
*--- 計算 ;
%let A = 4.3 ;
%let B = 3 ;
%let C = %sysevalf(&A*&B) ;
%put *** &A * &B = &C *** ;

*--- マスキング ;
*--- %str,%nrstr ;
%let PRINT = %str(proc print data=STR ; run ;) ;
%let LABEL = %nrstr(A&B) ;
%put *** &PRINT *** ;
%put *** &LABEL *** ;

%let PRINT = proc print data=STR ; run ; ;
%let LABEL = A&B ;
%put *** &PRINT *** ;
%put *** &LABEL *** ;

*--- %quote,%bquote ;
%let A = apple ;
%let B = car ;

%let X1 = %quote(This is an &A..) ;
%let X2 = %bquote(It's a &B..) ;

%put &X1 ;
%put &X2 ;

*--- %sysfunc ;
*--- 文字関数 ;
%let CHAR1 = %sysfunc(catx(=,A,B)) ;
%let CHAR2 = %sysfunc(compress(&))AAA ;
%let CHAR3 = %qsysfunc(compress(&))AAA ;

%put *** &CHAR1 *** ;
%put *** &CHAR2 *** ;
%put *** &CHAR3 *** ;

*--- 数値関数 ;
%let NUM1 = %sysfunc(int(1.2)) ;
%let NUM2 = %sysevalf(%sysfunc(mean(1,5,7))+%sysfunc(std(1,5,7))) ;
%let NUM3 = %sysfunc(round(&NUM2,.01)) ;

%put *** &NUM1 *** ;
%put *** &NUM2 *** ;
%put *** &NUM3 *** ;

*--- 6.7 複数のアンパサンド ;
data DT1 ;
   input WGT @@ ;
cards;
80 85 74 67 72 58 66 63 51 45
;
run ;

data DT2 ;
   input ABD @@ ;
cards;
88 95 87 78 81 77 90 102 99 70
;
run ;

data DT3 ;
   input LDL @@ ;
cards;
150 127 110 141 102 99 135 120 85 89
;
run ;

%macro NMEANS(DATA1=,DATA2=,DATA3=,VAR1=,VAR2=,VAR3=) ;
   %do I = 1 %to 3 ;
      proc means data=&&DATA&I n mean stddev min median max maxdec=2 ;
         var &&VAR&I ;
      run ;
   %end ;
%mend NMEANS ;

%NMEANS(DATA1=DT1,DATA2=DT2,DATA3=DT3,VAR1=WGT,VAR2=ABD,VAR3=LDL) ;

*--- 6.8 統計解析マクロ ;
*--- ttest ;
proc format ;
   value TRTF 1 = "薬剤A" 2 = "薬剤B" ;
run ;

data WGTDT ;
   do TREAT = 1 to 2 ;
      do I = 1 to 10 ;
         input WGT @@ ;
         output ;
      end ;
   end ;
   format TREAT TRTF. ;
cards;
80 85 74 67 72 58 66 63 51 45
75 90 70 63 88 89 56 90 83 63
;
run ;

%macro TWOSAMP_T(DATA=,VAR=,GRP=) ;
   proc ttest data=&DATA ;
      class &GRP ;
      var &VAR ;
   run ;
%mend TWOSAMP_T ;

%TWOSAMP_T(DATA=WGTDT,VAR=WGT,GRP=TREAT) ;

*--- 2x2分割表 ;
proc format ;
   value HEALF 1 = "治癒" 2 = "未治癒" ;
run ;

data TESTDT ;
   input TREAT HEAL NN ;
   format TREAT TRTF. HEAL HEALF. ;
cards;
1 1 35
1 2 20
2 1 28
2 2 26
;
run ;

%macro FREQ_BIN(DATA=,GRP=,VAL=,W=,RD=,RR_OR=,CHI=) ;
   proc freq data=&DATA ;
      %if &W ne %str() %then weight &W ;;
      table &GRP*&VAL / %if &RD    = yes %then riskdiff ;
                        %if &RR_OR = yes %then relrisk  ;
                        %if &CHI   = yes %then chisq    ;;
   run ;
%mend FREQ_BIN ;

%FREQ_BIN(DATA=TESTDT,GRP=TREAT,VAL=HEAL,W=NN,RD=yes,RR_OR=yes,CHI=yes) ;

*--- リスク差のみ ;
%FREQ_BIN(DATA=TESTDT,GRP=TREAT,VAL=HEAL,W=NN,RD=yes,RR_OR=no,CHI=no) ;

*--- 回帰分析 ;
data WGTHGT ;
   do I = 1 to 10 ;
      input WGT HGT @@ ;
      output ;
   end ;
cards;
80 175 85 178 74 169 67 168 72 173 58 160 66 170 63 161 51 157 45 155
;
run ;

%macro REG_M(DATA=,Y=,X=,INT=yes) ;
   proc reg data=&DATA ;
      model &Y = &X %if &INT ne yes %then / noint ;;
   run ; quit ;
%mend REG_M ;

%REG_M(DATA=WGTHGT,Y=WGT,X=HGT) ;

*--- notint ;
%REG_M(DATA=WGTHGT,Y=WGT,X=HGT,INT=no) ;

*--- 分散分析 ;
proc format ;
   value TRT2F 1 = "薬剤A" 2 = "薬剤B" 3 = "薬剤C" ;
run ;

data BP ;
   do TREAT = 1 to 3 ;
      do I = 1 to 10 ;
          input SBP_CHG @@ ;
          output ;
      end ;
   end ;
   format TREAT TRT2F. ;
cards;
 -5  -6  -8  -6   0   4  -2   6  -2   3
-15 -20 -15 -12 -21 -13 -14   3 -11  -9
 -7   9  11 -18   3 -12  -3  -9  -8   1
;
run ;

%macro GLM_M(DATA=,GRP=,Y=,X=,MEANS=,CONT=) ;
   %if &MEANS = yes %then %do ;
      proc means data=&DATA ;
         class &GRP ;
         var &Y ;
      run ;
   %end ;

   proc glm data=&DATA ;
      class &GRP &X ;
      model &Y = &GRP &X / ss3 ;
      %if &CONT ne %str() %then contrast "Contrast" &GRP &CONT / e ;;
   run ; quit ;
%mend GLM_M ;

%GLM_M(DATA=BP,GRP=TREAT,Y=SBP_CHG,X=,MEANS=yes,CONT=%str(-1 1 0)) ;

*--- 生存時間解析 ;
proc format ;
   value TRTF 1 = "薬剤1" 2 = "薬剤2" ;
run ;

data LIFE_EV ;
   do TREAT = 1 to 2 ;
      input DAYS CEN @@ ;
      output ;
   end ;
   format TREAT TRTF. ;
cards;
85 1 112 1  38 1 55 0 148 1 188 1 140 0 123 1
88 1 96  0 112 1 87 1  76 1 156 1  78 0 198 1
;
run ;

%macro LIFETEST_M(DATA=,TIME=,CENSOR=,CENVAL=,STRATA=) ;
   proc lifetest data=&DATA ;
      time &TIME*&CENSOR(&CENVAL) ;
      strata &STRATA ;
   run ;
%mend LIFETEST_M ;

%LIFETEST_M(DATA=LIFE_EV,TIME=DAYS,CENSOR=CEN,CENVAL=0,STRATA=TREAT) ;

*--- Cox ;
%macro CON_M(DATA=,CLASS=,TIME=,CENSOR=,CENVAL=,X=,TIES=) ;
   proc phreg data=&DATA ;
      class &CLASS ;
      model &TIME*&CENSOR(&CENVAL) = &X / ties=&TIES ;
   run ;
%mend CON_M ;

%CON_M(DATA=LIFE_EV,CLASS=TREAT,TIME=DAYS,CENSOR=CEN,CENVAL=0,X=TREAT,TIES=exact) ;

*--- 例数設計: 2t ;
%macro POWER_DIFF(ALPHA=,SIDES=,DIFF=,NULLDIFF=0,SD=, POWER=,NTOTAL=) ;
   proc power ;
      twosamplemeans
      test     = diff
      alpha    = &AlPHA
      sides    = &SIDES
      meandiff = &DIFF
      nulldiff = &NULLDIFF
      stddev   = &SD
      power    = &POWER
      ntotal   = &NTOTAL ;
   run ;
%mend POWER_DIFF ;

%POWER_DIFF(ALPHA=0.025,SIDES=1,DIFF=2,SD=4,POWER=0.8,NTOTAL=.) ;

%POWER_DIFF(ALPHA=0.025,SIDES=1,DIFF=1 to 5 by 1,SD=3 to 5 by 1,POWER=0.8,NTOTAL=.) ;

*--- 例数設計: proportion diff ;
%macro POWER_BIN(ALPHA=,SIDES=,GROUPPS=,NULLPDIFF=0,POWER=,NTOTAL=) ;
   proc power ;
      twosamplefreq
      test      = pchi
      alpha     = &ALPHA
      sides     = &SIDES
      groupps   = &GROUPPS
      nullpdiff = &NULLPDIFF
      power     = &POWER
      ntotal    = &NTOTAL  ;
run ;
%mend POWER_BIN ;

%POWER_BIN(ALPHA=0.05,SIDES=2,GROUPPS=(0.8 0.7), POWER=0.8,NTOTAL=.) ;

%POWER_BIN(ALPHA=0.05,SIDES=2,GROUPPS=0.8 0.85 0.9 | 0.7, POWER=0.8,NTOTAL=.) ;

*--- 例数設計: Survival Analysis ;
%macro POWER_SURV(ALPHA=,SIDES=,LABEL1=,LABEL2=,TIME1=,TIME2=,RATE1=,RATE2=,
                  ATIME=0.001,FTIME=,POWER=,NTOTAL=) ;
   proc power ;
      twosamplesurvival
      test           = logrank
      alpha          = &ALPHA
      sides          = &SIDES
      %do I = 1 %to 2 ;
         curve("&&LABEL&I") = (&&TIME&I):(&&RATE&I)
      %end ;
      groupsurvival  = "&LABEL1" | "&LABEL2"
      accrualtime    = &ATIME
      followuptime   = &FTIME 
      power          = &POWER
      ntotal         = &NTOTAL ; 
   run ;
%mend POWER_SURV ;

%POWER_SURV(ALPHA=0.05,SIDES=2,LABEL1=%str(薬剤A),LABEL2=%str(薬剤B),
            TIME1=2,TIME2=2,RATE1=0.9,RATE2=0.8,FTIME=5,POWER=0.8,NTOTAL=.) ;

*--- 6.9 レポート作成マクロ ;

*--- データの作成 ;
data HAIKEI ;
   input ID TREAT AGE GENDER SMOKE WEIGHT FPG ;
cards;
1  1 79 2 1 78.6  142
2  2 53 1 2 63.1  140
3  2 58 1 2 56.5  106
4  1 51 2 2 101.0 119
5  1 68 2 2 98.2  134
6  2 53 1 1 53.1  106
7  1 53 2 2 80.3  118
8  1 50 2 1 62.2  114
9  1 64 1 2 68.3  84
10 2 67 2 2 58.1  123
11 1 57 1 1 76.8  127
12 2 41 2 2 76.6  116
13 1 52 2 1 77.4  130
14 2 50 2 2 77.9  118
15 1 41 2 2 88.4  109
16 1 51 1 2 61.2  103
17 2 38 2 1 79.5  134
18 2 55 1 1 49.2  106
19 1 57 2 2 50.2  110
20 1 43 2 2 76.9  107
21 2 62 1 2 60.3  113
22 1 43 1 2 62.0  120
23 1 57 1 1 84.9  116
24 2 50 2 1 81.9  121
25 1 47 1 1 79.3  103
26 1 45 1 1 74.7  105
27 1 60 2 2 58.9  114
28 1 58 1 1 44.7  114
29 2 61 1 1 60.5  136
30 1 68 2 1 100.6 126
31 2 50 2 2 97.2  116
32 2 50 2 2 80.7  144
33 1 68 1 2 38.7  124
34 2 53 1 2 67.3  123
35 2 48 1 2 62.0  139
36 1 52 1 1 56.1  126
37 2 57 1 2 60.6  117
38 2 56 1 2 73.0  114
39 2 55 1 1 77.5  121
40 2 47 1 1 70.2  122
41 2 51 1 1 64.0  119
42 2 53 1 1 57.9  125
43 2 62 1 1 67.8  136
44 1 49 2 2 65.7  108
45 2 41 1 2 77.0  123
46 2 60 1 2 55.9  111
47 2 52 2 1 94.5  124
48 1 63 2 1 74.1  117
49 2 61 2 1 80.1  105
50 1 57 1 1 69.8  130
51 1 60 1 2 64.6  104
52 1 60 1 2 62.8  110
53 2 65 2 2 72.0  110
54 2 46 1 2 82.9  111
55 2 50 2 2 88.2  129
56 1 59 1 2 58.9  144
57 1 51 1 2 59.5  120
58 2 57 1 2 52.8  124
59 2 58 2 1 84.7  109
60 2 71 2 2 60.6  103
;
run ;


*--- 要約統計量のレポート ;
%macro SUM_STAT(DATA=,GRP=,VAR=,VARLABEL=,STAT=,STATF=) ;
   *--- 1. 統計量のカウント,キーワードとフォーマットの抽出 ;
   %let I = 1 ;
   %do %while(%scan(&STAT,&I) ne %str()) ;
      %let STAT_N = &I ;
      %let STAT&I  = %scan(&STAT ,&I) ;
      %let STATF&I = %scan(&STATF,&I,%str( )) ;
      %let I = %eval(&I + 1) ;
   %end ;
   *--- 2. 要約統計量の算出 ;
   proc summary data=&DATA nway ;
       class &GRP ;
       var &VAR ;
       output out=_OUT(drop=_FREQ_ _TYPE_)
       %do J = 1 %to &STAT_N ;
          &&STAT&J = &&STAT&J
       %end ;;
   run ;
   *--- 3. データセットの転置: 要約統計量を縦,各群を横に展開 ;
   proc transpose data=_OUT out=_OUT_T prefix=GRP ;
      var %do J = 1 %to &STAT_N ; &&STAT&J %end ;;
      id &GRP ;
   run ;      
   *--- 4. フォーマットの割り当てと文字変数への変換 ;
   data RES_CONT ;
      length LABEL _NAME_ _RES1 _RES2 $20. ;
      set _OUT_T ;
      LABEL = "&VARLABEL" ;
      %do K = 1 %to &STAT_N ;
         if _NAME_ = "&&STAT&K" then do ;
            _RES1 = put(GRP1,&&STATF&K) ;
            _RES2 = put(GRP2,&&STATF&K) ;
         end ;
      %end ;
      keep LABEL _NAME_ _RES1 _RES2 ;
   run ;
   *--- 5. レポート作成 ;
   proc report data=RES_CONT nowd ;
      column LABEL _NAME_ _RES1 _RES2 ;
      define LABEL  / order "項目" ;
      define _NAME_ / display "要約統計量" ;
      define _RES1  / display "薬剤1" style={just=r} ;
      define _RES2  / display "薬剤2" style={just=r} ;
   run ;
%mend SUM_STAT ;

%SUM_STAT(DATA=HAIKEI,GRP=TREAT,VAR=WEIGHT,VARLABEL=%str(Weight(kg)),
           STAT=n mean stddev min median max,
           STATF=8. 8.2 8.3 8.1 8.2 8.1) ;

*--- カテゴリ変数のレポート ;
%macro SUM_CAT(DATA=,GRP=,VAR=,VARLABEL=,VARF=) ;
   *--- 1. 例数とパーセントを算出 ;
   ods listing close ;
   proc tabulate data=&DATA out=_OUT ;
      class &GRP &VAR ;
      table &GRP,&VAR*(n rowpctn)  ;
   run ;
   ods listing ;
   *--- 2. N(%)とするために文字変数に変換 ;
   data _OUT2 ;
      set _OUT ;
      _RES=put(N,best.)||"("||put(pctn_10,6.1)||")" ;
   run ;
   proc sort data=_OUT2 ; by &VAR ; run ;
   *--- 3. データセットの転置: N(%)を縦,各群を横に展開 ;
   proc transpose data=_OUT2 out=_OUT_T prefix=_RES ;
      by &VAR ;
      var _RES ;
      id &GRP ;
   run ;
   *--- 4. 各カテゴリへのフォーマットの割り当て ;
   data RES_CAT ;
      length LABEL _NAME_ $20. ;
      LABEL="&VARLABEL" ;
      set _OUT_T ;
      _NAME_ = left(put(&VAR,&VARF..)) ;
      keep LABEL _NAME_ _RES1 _RES2 ; 
   run ;
   *--- 5. レポート作成 ;
   proc report data=RES_CAT nowd ;
      column LABEL _NAME_ _RES1 _RES2 ;
      define LABEL  / order "項目" ;
      define _NAME_ / display "カテゴリ" ;
      define _RES1  / display "薬剤1" style={just=r} ;
      define _RES2  / display "薬剤2" style={just=r} ;
   run ;
%mend SUM_CAT ;

proc format ;
   value GENDERF 1="Male" 2="Female" ;
run ;

%SUM_CAT(DATA=HAIKEI,GRP=TREAT,VAR=GENDER,VARLABEL=Gender,VARF=GENDERF) ;